blob: 30f98eb6638296c598c304e9eae9acf9f69d284d [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);
Bram Moolenaarfd133322019-03-29 12:20:27 +0100116static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117#endif
118static void f_confirm(typval_T *argvars, typval_T *rettv);
119static void f_copy(typval_T *argvars, typval_T *rettv);
120#ifdef FEAT_FLOAT
121static void f_cos(typval_T *argvars, typval_T *rettv);
122static void f_cosh(typval_T *argvars, typval_T *rettv);
123#endif
124static void f_count(typval_T *argvars, typval_T *rettv);
125static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
126static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100127#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200128static void f_debugbreak(typval_T *argvars, typval_T *rettv);
129#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200130static void f_deepcopy(typval_T *argvars, typval_T *rettv);
131static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200132static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200133static void f_did_filetype(typval_T *argvars, typval_T *rettv);
134static void f_diff_filler(typval_T *argvars, typval_T *rettv);
135static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
136static void f_empty(typval_T *argvars, typval_T *rettv);
137static void f_escape(typval_T *argvars, typval_T *rettv);
138static void f_eval(typval_T *argvars, typval_T *rettv);
139static void f_eventhandler(typval_T *argvars, typval_T *rettv);
140static void f_executable(typval_T *argvars, typval_T *rettv);
141static void f_execute(typval_T *argvars, typval_T *rettv);
142static void f_exepath(typval_T *argvars, typval_T *rettv);
143static void f_exists(typval_T *argvars, typval_T *rettv);
144#ifdef FEAT_FLOAT
145static void f_exp(typval_T *argvars, typval_T *rettv);
146#endif
147static void f_expand(typval_T *argvars, typval_T *rettv);
148static void f_extend(typval_T *argvars, typval_T *rettv);
149static void f_feedkeys(typval_T *argvars, typval_T *rettv);
150static void f_filereadable(typval_T *argvars, typval_T *rettv);
151static void f_filewritable(typval_T *argvars, typval_T *rettv);
152static void f_filter(typval_T *argvars, typval_T *rettv);
153static void f_finddir(typval_T *argvars, typval_T *rettv);
154static void f_findfile(typval_T *argvars, typval_T *rettv);
155#ifdef FEAT_FLOAT
156static void f_float2nr(typval_T *argvars, typval_T *rettv);
157static void f_floor(typval_T *argvars, typval_T *rettv);
158static void f_fmod(typval_T *argvars, typval_T *rettv);
159#endif
160static void f_fnameescape(typval_T *argvars, typval_T *rettv);
161static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
162static void f_foldclosed(typval_T *argvars, typval_T *rettv);
163static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
164static void f_foldlevel(typval_T *argvars, typval_T *rettv);
165static void f_foldtext(typval_T *argvars, typval_T *rettv);
166static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
167static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200168static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200169static void f_function(typval_T *argvars, typval_T *rettv);
170static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
171static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200172static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_getbufline(typval_T *argvars, typval_T *rettv);
174static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100175static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200176static void f_getchar(typval_T *argvars, typval_T *rettv);
177static void f_getcharmod(typval_T *argvars, typval_T *rettv);
178static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
179static void f_getcmdline(typval_T *argvars, typval_T *rettv);
180#if defined(FEAT_CMDL_COMPL)
181static void f_getcompletion(typval_T *argvars, typval_T *rettv);
182#endif
183static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
184static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
185static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
186static void f_getcwd(typval_T *argvars, typval_T *rettv);
187static void f_getfontname(typval_T *argvars, typval_T *rettv);
188static void f_getfperm(typval_T *argvars, typval_T *rettv);
189static void f_getfsize(typval_T *argvars, typval_T *rettv);
190static void f_getftime(typval_T *argvars, typval_T *rettv);
191static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100192static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200194static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_getmatches(typval_T *argvars, typval_T *rettv);
196static void f_getpid(typval_T *argvars, typval_T *rettv);
197static void f_getcurpos(typval_T *argvars, typval_T *rettv);
198static void f_getpos(typval_T *argvars, typval_T *rettv);
199static void f_getqflist(typval_T *argvars, typval_T *rettv);
200static void f_getreg(typval_T *argvars, typval_T *rettv);
201static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200202static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203static void f_gettabvar(typval_T *argvars, typval_T *rettv);
204static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100205static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200206static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100207static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200208static void f_getwinposx(typval_T *argvars, typval_T *rettv);
209static void f_getwinposy(typval_T *argvars, typval_T *rettv);
210static void f_getwinvar(typval_T *argvars, typval_T *rettv);
211static void f_glob(typval_T *argvars, typval_T *rettv);
212static void f_globpath(typval_T *argvars, typval_T *rettv);
213static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
214static void f_has(typval_T *argvars, typval_T *rettv);
215static void f_has_key(typval_T *argvars, typval_T *rettv);
216static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
217static void f_hasmapto(typval_T *argvars, typval_T *rettv);
218static void f_histadd(typval_T *argvars, typval_T *rettv);
219static void f_histdel(typval_T *argvars, typval_T *rettv);
220static void f_histget(typval_T *argvars, typval_T *rettv);
221static void f_histnr(typval_T *argvars, typval_T *rettv);
222static void f_hlID(typval_T *argvars, typval_T *rettv);
223static void f_hlexists(typval_T *argvars, typval_T *rettv);
224static void f_hostname(typval_T *argvars, typval_T *rettv);
225static void f_iconv(typval_T *argvars, typval_T *rettv);
226static void f_indent(typval_T *argvars, typval_T *rettv);
227static void f_index(typval_T *argvars, typval_T *rettv);
228static void f_input(typval_T *argvars, typval_T *rettv);
229static void f_inputdialog(typval_T *argvars, typval_T *rettv);
230static void f_inputlist(typval_T *argvars, typval_T *rettv);
231static void f_inputrestore(typval_T *argvars, typval_T *rettv);
232static void f_inputsave(typval_T *argvars, typval_T *rettv);
233static void f_inputsecret(typval_T *argvars, typval_T *rettv);
234static void f_insert(typval_T *argvars, typval_T *rettv);
235static void f_invert(typval_T *argvars, typval_T *rettv);
236static void f_isdirectory(typval_T *argvars, typval_T *rettv);
237static void f_islocked(typval_T *argvars, typval_T *rettv);
238#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
239static void f_isnan(typval_T *argvars, typval_T *rettv);
240#endif
241static void f_items(typval_T *argvars, typval_T *rettv);
242#ifdef FEAT_JOB_CHANNEL
243static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
244static void f_job_info(typval_T *argvars, typval_T *rettv);
245static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
246static void f_job_start(typval_T *argvars, typval_T *rettv);
247static void f_job_stop(typval_T *argvars, typval_T *rettv);
248static void f_job_status(typval_T *argvars, typval_T *rettv);
249#endif
250static void f_join(typval_T *argvars, typval_T *rettv);
251static void f_js_decode(typval_T *argvars, typval_T *rettv);
252static void f_js_encode(typval_T *argvars, typval_T *rettv);
253static void f_json_decode(typval_T *argvars, typval_T *rettv);
254static void f_json_encode(typval_T *argvars, typval_T *rettv);
255static void f_keys(typval_T *argvars, typval_T *rettv);
256static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
257static void f_len(typval_T *argvars, typval_T *rettv);
258static void f_libcall(typval_T *argvars, typval_T *rettv);
259static void f_libcallnr(typval_T *argvars, typval_T *rettv);
260static void f_line(typval_T *argvars, typval_T *rettv);
261static void f_line2byte(typval_T *argvars, typval_T *rettv);
262static void f_lispindent(typval_T *argvars, typval_T *rettv);
263static void f_localtime(typval_T *argvars, typval_T *rettv);
264#ifdef FEAT_FLOAT
265static void f_log(typval_T *argvars, typval_T *rettv);
266static void f_log10(typval_T *argvars, typval_T *rettv);
267#endif
268#ifdef FEAT_LUA
269static void f_luaeval(typval_T *argvars, typval_T *rettv);
270#endif
271static void f_map(typval_T *argvars, typval_T *rettv);
272static void f_maparg(typval_T *argvars, typval_T *rettv);
273static void f_mapcheck(typval_T *argvars, typval_T *rettv);
274static void f_match(typval_T *argvars, typval_T *rettv);
275static void f_matchadd(typval_T *argvars, typval_T *rettv);
276static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
277static void f_matcharg(typval_T *argvars, typval_T *rettv);
278static void f_matchdelete(typval_T *argvars, typval_T *rettv);
279static void f_matchend(typval_T *argvars, typval_T *rettv);
280static void f_matchlist(typval_T *argvars, typval_T *rettv);
281static void f_matchstr(typval_T *argvars, typval_T *rettv);
282static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
283static void f_max(typval_T *argvars, typval_T *rettv);
284static void f_min(typval_T *argvars, typval_T *rettv);
285#ifdef vim_mkdir
286static void f_mkdir(typval_T *argvars, typval_T *rettv);
287#endif
288static void f_mode(typval_T *argvars, typval_T *rettv);
289#ifdef FEAT_MZSCHEME
290static void f_mzeval(typval_T *argvars, typval_T *rettv);
291#endif
292static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
293static void f_nr2char(typval_T *argvars, typval_T *rettv);
294static void f_or(typval_T *argvars, typval_T *rettv);
295static void f_pathshorten(typval_T *argvars, typval_T *rettv);
296#ifdef FEAT_PERL
297static void f_perleval(typval_T *argvars, typval_T *rettv);
298#endif
299#ifdef FEAT_FLOAT
300static void f_pow(typval_T *argvars, typval_T *rettv);
301#endif
302static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
303static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200304#ifdef FEAT_JOB_CHANNEL
305static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200306static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200307static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
308#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309static void f_pumvisible(typval_T *argvars, typval_T *rettv);
310#ifdef FEAT_PYTHON3
311static void f_py3eval(typval_T *argvars, typval_T *rettv);
312#endif
313#ifdef FEAT_PYTHON
314static void f_pyeval(typval_T *argvars, typval_T *rettv);
315#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100316#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
317static void f_pyxeval(typval_T *argvars, typval_T *rettv);
318#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200319static void f_range(typval_T *argvars, typval_T *rettv);
320static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200321static void f_reg_executing(typval_T *argvars, typval_T *rettv);
322static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200323static void f_reltime(typval_T *argvars, typval_T *rettv);
324#ifdef FEAT_FLOAT
325static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
326#endif
327static void f_reltimestr(typval_T *argvars, typval_T *rettv);
328static void f_remote_expr(typval_T *argvars, typval_T *rettv);
329static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
330static void f_remote_peek(typval_T *argvars, typval_T *rettv);
331static void f_remote_read(typval_T *argvars, typval_T *rettv);
332static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100333static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200334static void f_remove(typval_T *argvars, typval_T *rettv);
335static void f_rename(typval_T *argvars, typval_T *rettv);
336static void f_repeat(typval_T *argvars, typval_T *rettv);
337static void f_resolve(typval_T *argvars, typval_T *rettv);
338static void f_reverse(typval_T *argvars, typval_T *rettv);
339#ifdef FEAT_FLOAT
340static void f_round(typval_T *argvars, typval_T *rettv);
341#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100342#ifdef FEAT_RUBY
343static void f_rubyeval(typval_T *argvars, typval_T *rettv);
344#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200345static void f_screenattr(typval_T *argvars, typval_T *rettv);
346static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100347static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200348static void f_screencol(typval_T *argvars, typval_T *rettv);
349static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100350static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200351static void f_search(typval_T *argvars, typval_T *rettv);
352static void f_searchdecl(typval_T *argvars, typval_T *rettv);
353static void f_searchpair(typval_T *argvars, typval_T *rettv);
354static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
355static void f_searchpos(typval_T *argvars, typval_T *rettv);
356static void f_server2client(typval_T *argvars, typval_T *rettv);
357static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200358static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359static void f_setbufvar(typval_T *argvars, typval_T *rettv);
360static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
361static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
362static void f_setfperm(typval_T *argvars, typval_T *rettv);
363static void f_setline(typval_T *argvars, typval_T *rettv);
364static void f_setloclist(typval_T *argvars, typval_T *rettv);
365static void f_setmatches(typval_T *argvars, typval_T *rettv);
366static void f_setpos(typval_T *argvars, typval_T *rettv);
367static void f_setqflist(typval_T *argvars, typval_T *rettv);
368static void f_setreg(typval_T *argvars, typval_T *rettv);
369static void f_settabvar(typval_T *argvars, typval_T *rettv);
370static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100371static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200372static void f_setwinvar(typval_T *argvars, typval_T *rettv);
373#ifdef FEAT_CRYPT
374static void f_sha256(typval_T *argvars, typval_T *rettv);
375#endif /* FEAT_CRYPT */
376static void f_shellescape(typval_T *argvars, typval_T *rettv);
377static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100378#ifdef FEAT_SIGNS
379static void f_sign_define(typval_T *argvars, typval_T *rettv);
380static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
381static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100382static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100383static void f_sign_place(typval_T *argvars, typval_T *rettv);
384static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
385static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
386#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200387static void f_simplify(typval_T *argvars, typval_T *rettv);
388#ifdef FEAT_FLOAT
389static void f_sin(typval_T *argvars, typval_T *rettv);
390static void f_sinh(typval_T *argvars, typval_T *rettv);
391#endif
392static void f_sort(typval_T *argvars, typval_T *rettv);
393static void f_soundfold(typval_T *argvars, typval_T *rettv);
394static void f_spellbadword(typval_T *argvars, typval_T *rettv);
395static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
396static void f_split(typval_T *argvars, typval_T *rettv);
397#ifdef FEAT_FLOAT
398static void f_sqrt(typval_T *argvars, typval_T *rettv);
399static void f_str2float(typval_T *argvars, typval_T *rettv);
400#endif
401static void f_str2nr(typval_T *argvars, typval_T *rettv);
402static void f_strchars(typval_T *argvars, typval_T *rettv);
403#ifdef HAVE_STRFTIME
404static void f_strftime(typval_T *argvars, typval_T *rettv);
405#endif
406static void f_strgetchar(typval_T *argvars, typval_T *rettv);
407static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408static void f_strlen(typval_T *argvars, typval_T *rettv);
409static void f_strcharpart(typval_T *argvars, typval_T *rettv);
410static void f_strpart(typval_T *argvars, typval_T *rettv);
411static void f_strridx(typval_T *argvars, typval_T *rettv);
412static void f_strtrans(typval_T *argvars, typval_T *rettv);
413static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
414static void f_strwidth(typval_T *argvars, typval_T *rettv);
415static void f_submatch(typval_T *argvars, typval_T *rettv);
416static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200417static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200418static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419static void f_synID(typval_T *argvars, typval_T *rettv);
420static void f_synIDattr(typval_T *argvars, typval_T *rettv);
421static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
422static void f_synstack(typval_T *argvars, typval_T *rettv);
423static void f_synconcealed(typval_T *argvars, typval_T *rettv);
424static void f_system(typval_T *argvars, typval_T *rettv);
425static void f_systemlist(typval_T *argvars, typval_T *rettv);
426static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
427static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
428static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
429static void f_taglist(typval_T *argvars, typval_T *rettv);
430static void f_tagfiles(typval_T *argvars, typval_T *rettv);
431static void f_tempname(typval_T *argvars, typval_T *rettv);
432static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
433static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200434static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200435static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100436static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100437static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200438static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100439static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100440static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200441#ifdef FEAT_JOB_CHANNEL
442static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
443#endif
444static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
445#ifdef FEAT_JOB_CHANNEL
446static void f_test_null_job(typval_T *argvars, typval_T *rettv);
447#endif
448static void f_test_null_list(typval_T *argvars, typval_T *rettv);
449static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
450static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200451#ifdef FEAT_GUI
452static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
453#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200454static void f_test_settime(typval_T *argvars, typval_T *rettv);
455#ifdef FEAT_FLOAT
456static void f_tan(typval_T *argvars, typval_T *rettv);
457static void f_tanh(typval_T *argvars, typval_T *rettv);
458#endif
459#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200460static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200461static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200462static void f_timer_start(typval_T *argvars, typval_T *rettv);
463static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200464static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200465#endif
466static void f_tolower(typval_T *argvars, typval_T *rettv);
467static void f_toupper(typval_T *argvars, typval_T *rettv);
468static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100469static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
471static void f_trunc(typval_T *argvars, typval_T *rettv);
472#endif
473static void f_type(typval_T *argvars, typval_T *rettv);
474static void f_undofile(typval_T *argvars, typval_T *rettv);
475static void f_undotree(typval_T *argvars, typval_T *rettv);
476static void f_uniq(typval_T *argvars, typval_T *rettv);
477static void f_values(typval_T *argvars, typval_T *rettv);
478static void f_virtcol(typval_T *argvars, typval_T *rettv);
479static void f_visualmode(typval_T *argvars, typval_T *rettv);
480static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
481static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
482static void f_win_getid(typval_T *argvars, typval_T *rettv);
483static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
484static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
485static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100486static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487static void f_winbufnr(typval_T *argvars, typval_T *rettv);
488static void f_wincol(typval_T *argvars, typval_T *rettv);
489static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200490static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200491static void f_winline(typval_T *argvars, typval_T *rettv);
492static void f_winnr(typval_T *argvars, typval_T *rettv);
493static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
494static void f_winrestview(typval_T *argvars, typval_T *rettv);
495static void f_winsaveview(typval_T *argvars, typval_T *rettv);
496static void f_winwidth(typval_T *argvars, typval_T *rettv);
497static void f_writefile(typval_T *argvars, typval_T *rettv);
498static void f_wordcount(typval_T *argvars, typval_T *rettv);
499static void f_xor(typval_T *argvars, typval_T *rettv);
500
501/*
502 * Array with names and number of arguments of all internal functions
503 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
504 */
505static struct fst
506{
507 char *f_name; /* function name */
508 char f_min_argc; /* minimal number of arguments */
509 char f_max_argc; /* maximal number of arguments */
510 void (*f_func)(typval_T *args, typval_T *rvar);
511 /* implementation of function */
512} functions[] =
513{
514#ifdef FEAT_FLOAT
515 {"abs", 1, 1, f_abs},
516 {"acos", 1, 1, f_acos}, /* WJMc */
517#endif
518 {"add", 2, 2, f_add},
519 {"and", 2, 2, f_and},
520 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200521 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200522 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523 {"argidx", 0, 0, f_argidx},
524 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200525 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#ifdef FEAT_FLOAT
527 {"asin", 1, 1, f_asin}, /* WJMc */
528#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100529 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100531 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200532 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200533 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200534 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100535 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536 {"assert_match", 2, 3, f_assert_match},
537 {"assert_notequal", 2, 3, f_assert_notequal},
538 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100539 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200540 {"assert_true", 1, 2, f_assert_true},
541#ifdef FEAT_FLOAT
542 {"atan", 1, 1, f_atan},
543 {"atan2", 2, 2, f_atan2},
544#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100545#ifdef FEAT_BEVAL
546 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100547# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100548 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100549# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100550#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200551 {"browse", 4, 4, f_browse},
552 {"browsedir", 2, 2, f_browsedir},
553 {"bufexists", 1, 1, f_bufexists},
554 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
555 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
556 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
557 {"buflisted", 1, 1, f_buflisted},
558 {"bufloaded", 1, 1, f_bufloaded},
559 {"bufname", 1, 1, f_bufname},
560 {"bufnr", 1, 2, f_bufnr},
561 {"bufwinid", 1, 1, f_bufwinid},
562 {"bufwinnr", 1, 1, f_bufwinnr},
563 {"byte2line", 1, 1, f_byte2line},
564 {"byteidx", 2, 2, f_byteidx},
565 {"byteidxcomp", 2, 2, f_byteidxcomp},
566 {"call", 2, 3, f_call},
567#ifdef FEAT_FLOAT
568 {"ceil", 1, 1, f_ceil},
569#endif
570#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100571 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200572 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200573 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200574 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
575 {"ch_evalraw", 2, 3, f_ch_evalraw},
576 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
577 {"ch_getjob", 1, 1, f_ch_getjob},
578 {"ch_info", 1, 1, f_ch_info},
579 {"ch_log", 1, 2, f_ch_log},
580 {"ch_logfile", 1, 2, f_ch_logfile},
581 {"ch_open", 1, 2, f_ch_open},
582 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100583 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200584 {"ch_readraw", 1, 2, f_ch_readraw},
585 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
586 {"ch_sendraw", 2, 3, f_ch_sendraw},
587 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200588 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200589#endif
590 {"changenr", 0, 0, f_changenr},
591 {"char2nr", 1, 2, f_char2nr},
592 {"cindent", 1, 1, f_cindent},
593 {"clearmatches", 0, 0, f_clearmatches},
594 {"col", 1, 1, f_col},
595#if defined(FEAT_INS_EXPAND)
596 {"complete", 2, 2, f_complete},
597 {"complete_add", 1, 1, f_complete_add},
598 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100599 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600#endif
601 {"confirm", 1, 4, f_confirm},
602 {"copy", 1, 1, f_copy},
603#ifdef FEAT_FLOAT
604 {"cos", 1, 1, f_cos},
605 {"cosh", 1, 1, f_cosh},
606#endif
607 {"count", 2, 4, f_count},
608 {"cscope_connection",0,3, f_cscope_connection},
609 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100610#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200611 {"debugbreak", 1, 1, f_debugbreak},
612#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613 {"deepcopy", 1, 2, f_deepcopy},
614 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200615 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200616 {"did_filetype", 0, 0, f_did_filetype},
617 {"diff_filler", 1, 1, f_diff_filler},
618 {"diff_hlID", 2, 2, f_diff_hlID},
619 {"empty", 1, 1, f_empty},
620 {"escape", 2, 2, f_escape},
621 {"eval", 1, 1, f_eval},
622 {"eventhandler", 0, 0, f_eventhandler},
623 {"executable", 1, 1, f_executable},
624 {"execute", 1, 2, f_execute},
625 {"exepath", 1, 1, f_exepath},
626 {"exists", 1, 1, f_exists},
627#ifdef FEAT_FLOAT
628 {"exp", 1, 1, f_exp},
629#endif
630 {"expand", 1, 3, f_expand},
631 {"extend", 2, 3, f_extend},
632 {"feedkeys", 1, 2, f_feedkeys},
633 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
634 {"filereadable", 1, 1, f_filereadable},
635 {"filewritable", 1, 1, f_filewritable},
636 {"filter", 2, 2, f_filter},
637 {"finddir", 1, 3, f_finddir},
638 {"findfile", 1, 3, f_findfile},
639#ifdef FEAT_FLOAT
640 {"float2nr", 1, 1, f_float2nr},
641 {"floor", 1, 1, f_floor},
642 {"fmod", 2, 2, f_fmod},
643#endif
644 {"fnameescape", 1, 1, f_fnameescape},
645 {"fnamemodify", 2, 2, f_fnamemodify},
646 {"foldclosed", 1, 1, f_foldclosed},
647 {"foldclosedend", 1, 1, f_foldclosedend},
648 {"foldlevel", 1, 1, f_foldlevel},
649 {"foldtext", 0, 0, f_foldtext},
650 {"foldtextresult", 1, 1, f_foldtextresult},
651 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200652 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"function", 1, 3, f_function},
654 {"garbagecollect", 0, 1, f_garbagecollect},
655 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200656 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657 {"getbufline", 2, 3, f_getbufline},
658 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100659 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200660 {"getchar", 0, 1, f_getchar},
661 {"getcharmod", 0, 0, f_getcharmod},
662 {"getcharsearch", 0, 0, f_getcharsearch},
663 {"getcmdline", 0, 0, f_getcmdline},
664 {"getcmdpos", 0, 0, f_getcmdpos},
665 {"getcmdtype", 0, 0, f_getcmdtype},
666 {"getcmdwintype", 0, 0, f_getcmdwintype},
667#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200668 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200669#endif
670 {"getcurpos", 0, 0, f_getcurpos},
671 {"getcwd", 0, 2, f_getcwd},
672 {"getfontname", 0, 1, f_getfontname},
673 {"getfperm", 1, 1, f_getfperm},
674 {"getfsize", 1, 1, f_getfsize},
675 {"getftime", 1, 1, f_getftime},
676 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100677 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200678 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200679 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680 {"getmatches", 0, 0, f_getmatches},
681 {"getpid", 0, 0, f_getpid},
682 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200683 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200684 {"getreg", 0, 3, f_getreg},
685 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200686 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200687 {"gettabvar", 2, 3, f_gettabvar},
688 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100689 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200690 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100691 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200692 {"getwinposx", 0, 0, f_getwinposx},
693 {"getwinposy", 0, 0, f_getwinposy},
694 {"getwinvar", 2, 3, f_getwinvar},
695 {"glob", 1, 4, f_glob},
696 {"glob2regpat", 1, 1, f_glob2regpat},
697 {"globpath", 2, 5, f_globpath},
698 {"has", 1, 1, f_has},
699 {"has_key", 2, 2, f_has_key},
700 {"haslocaldir", 0, 2, f_haslocaldir},
701 {"hasmapto", 1, 3, f_hasmapto},
702 {"highlightID", 1, 1, f_hlID}, /* obsolete */
703 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
704 {"histadd", 2, 2, f_histadd},
705 {"histdel", 1, 2, f_histdel},
706 {"histget", 1, 2, f_histget},
707 {"histnr", 1, 1, f_histnr},
708 {"hlID", 1, 1, f_hlID},
709 {"hlexists", 1, 1, f_hlexists},
710 {"hostname", 0, 0, f_hostname},
711 {"iconv", 3, 3, f_iconv},
712 {"indent", 1, 1, f_indent},
713 {"index", 2, 4, f_index},
714 {"input", 1, 3, f_input},
715 {"inputdialog", 1, 3, f_inputdialog},
716 {"inputlist", 1, 1, f_inputlist},
717 {"inputrestore", 0, 0, f_inputrestore},
718 {"inputsave", 0, 0, f_inputsave},
719 {"inputsecret", 1, 2, f_inputsecret},
720 {"insert", 2, 3, f_insert},
721 {"invert", 1, 1, f_invert},
722 {"isdirectory", 1, 1, f_isdirectory},
723 {"islocked", 1, 1, f_islocked},
724#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
725 {"isnan", 1, 1, f_isnan},
726#endif
727 {"items", 1, 1, f_items},
728#ifdef FEAT_JOB_CHANNEL
729 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200730 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200731 {"job_setoptions", 2, 2, f_job_setoptions},
732 {"job_start", 1, 2, f_job_start},
733 {"job_status", 1, 1, f_job_status},
734 {"job_stop", 1, 2, f_job_stop},
735#endif
736 {"join", 1, 2, f_join},
737 {"js_decode", 1, 1, f_js_decode},
738 {"js_encode", 1, 1, f_js_encode},
739 {"json_decode", 1, 1, f_json_decode},
740 {"json_encode", 1, 1, f_json_encode},
741 {"keys", 1, 1, f_keys},
742 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
743 {"len", 1, 1, f_len},
744 {"libcall", 3, 3, f_libcall},
745 {"libcallnr", 3, 3, f_libcallnr},
746 {"line", 1, 1, f_line},
747 {"line2byte", 1, 1, f_line2byte},
748 {"lispindent", 1, 1, f_lispindent},
749 {"localtime", 0, 0, f_localtime},
750#ifdef FEAT_FLOAT
751 {"log", 1, 1, f_log},
752 {"log10", 1, 1, f_log10},
753#endif
754#ifdef FEAT_LUA
755 {"luaeval", 1, 2, f_luaeval},
756#endif
757 {"map", 2, 2, f_map},
758 {"maparg", 1, 4, f_maparg},
759 {"mapcheck", 1, 3, f_mapcheck},
760 {"match", 2, 4, f_match},
761 {"matchadd", 2, 5, f_matchadd},
762 {"matchaddpos", 2, 5, f_matchaddpos},
763 {"matcharg", 1, 1, f_matcharg},
764 {"matchdelete", 1, 1, f_matchdelete},
765 {"matchend", 2, 4, f_matchend},
766 {"matchlist", 2, 4, f_matchlist},
767 {"matchstr", 2, 4, f_matchstr},
768 {"matchstrpos", 2, 4, f_matchstrpos},
769 {"max", 1, 1, f_max},
770 {"min", 1, 1, f_min},
771#ifdef vim_mkdir
772 {"mkdir", 1, 3, f_mkdir},
773#endif
774 {"mode", 0, 1, f_mode},
775#ifdef FEAT_MZSCHEME
776 {"mzeval", 1, 1, f_mzeval},
777#endif
778 {"nextnonblank", 1, 1, f_nextnonblank},
779 {"nr2char", 1, 2, f_nr2char},
780 {"or", 2, 2, f_or},
781 {"pathshorten", 1, 1, f_pathshorten},
782#ifdef FEAT_PERL
783 {"perleval", 1, 1, f_perleval},
784#endif
785#ifdef FEAT_FLOAT
786 {"pow", 2, 2, f_pow},
787#endif
788 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100789 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200790#ifdef FEAT_JOB_CHANNEL
791 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200792 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200793 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
794#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100795#ifdef FEAT_TEXT_PROP
796 {"prop_add", 3, 3, f_prop_add},
797 {"prop_clear", 1, 3, f_prop_clear},
798 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100799 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100800 {"prop_type_add", 2, 2, f_prop_type_add},
801 {"prop_type_change", 2, 2, f_prop_type_change},
802 {"prop_type_delete", 1, 2, f_prop_type_delete},
803 {"prop_type_get", 1, 2, f_prop_type_get},
804 {"prop_type_list", 0, 1, f_prop_type_list},
805#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806 {"pumvisible", 0, 0, f_pumvisible},
807#ifdef FEAT_PYTHON3
808 {"py3eval", 1, 1, f_py3eval},
809#endif
810#ifdef FEAT_PYTHON
811 {"pyeval", 1, 1, f_pyeval},
812#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100813#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
814 {"pyxeval", 1, 1, f_pyxeval},
815#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200816 {"range", 1, 3, f_range},
817 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200818 {"reg_executing", 0, 0, f_reg_executing},
819 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820 {"reltime", 0, 2, f_reltime},
821#ifdef FEAT_FLOAT
822 {"reltimefloat", 1, 1, f_reltimefloat},
823#endif
824 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100825 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200826 {"remote_foreground", 1, 1, f_remote_foreground},
827 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100828 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200829 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100830 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831 {"remove", 2, 3, f_remove},
832 {"rename", 2, 2, f_rename},
833 {"repeat", 2, 2, f_repeat},
834 {"resolve", 1, 1, f_resolve},
835 {"reverse", 1, 1, f_reverse},
836#ifdef FEAT_FLOAT
837 {"round", 1, 1, f_round},
838#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100839#ifdef FEAT_RUBY
840 {"rubyeval", 1, 1, f_rubyeval},
841#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842 {"screenattr", 2, 2, f_screenattr},
843 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100844 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200845 {"screencol", 0, 0, f_screencol},
846 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100847 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848 {"search", 1, 4, f_search},
849 {"searchdecl", 1, 3, f_searchdecl},
850 {"searchpair", 3, 7, f_searchpair},
851 {"searchpairpos", 3, 7, f_searchpairpos},
852 {"searchpos", 1, 4, f_searchpos},
853 {"server2client", 2, 2, f_server2client},
854 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200855 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856 {"setbufvar", 3, 3, f_setbufvar},
857 {"setcharsearch", 1, 1, f_setcharsearch},
858 {"setcmdpos", 1, 1, f_setcmdpos},
859 {"setfperm", 2, 2, f_setfperm},
860 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200861 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200862 {"setmatches", 1, 1, f_setmatches},
863 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200864 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865 {"setreg", 2, 3, f_setreg},
866 {"settabvar", 3, 3, f_settabvar},
867 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100868 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869 {"setwinvar", 3, 3, f_setwinvar},
870#ifdef FEAT_CRYPT
871 {"sha256", 1, 1, f_sha256},
872#endif
873 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100874 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100875#ifdef FEAT_SIGNS
876 {"sign_define", 1, 2, f_sign_define},
877 {"sign_getdefined", 0, 1, f_sign_getdefined},
878 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100879 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100880 {"sign_place", 4, 5, f_sign_place},
881 {"sign_undefine", 0, 1, f_sign_undefine},
882 {"sign_unplace", 1, 2, f_sign_unplace},
883#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200884 {"simplify", 1, 1, f_simplify},
885#ifdef FEAT_FLOAT
886 {"sin", 1, 1, f_sin},
887 {"sinh", 1, 1, f_sinh},
888#endif
889 {"sort", 1, 3, f_sort},
890 {"soundfold", 1, 1, f_soundfold},
891 {"spellbadword", 0, 1, f_spellbadword},
892 {"spellsuggest", 1, 3, f_spellsuggest},
893 {"split", 1, 3, f_split},
894#ifdef FEAT_FLOAT
895 {"sqrt", 1, 1, f_sqrt},
896 {"str2float", 1, 1, f_str2float},
897#endif
898 {"str2nr", 1, 2, f_str2nr},
899 {"strcharpart", 2, 3, f_strcharpart},
900 {"strchars", 1, 2, f_strchars},
901 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
902#ifdef HAVE_STRFTIME
903 {"strftime", 1, 2, f_strftime},
904#endif
905 {"strgetchar", 2, 2, f_strgetchar},
906 {"stridx", 2, 3, f_stridx},
907 {"string", 1, 1, f_string},
908 {"strlen", 1, 1, f_strlen},
909 {"strpart", 2, 3, f_strpart},
910 {"strridx", 2, 3, f_strridx},
911 {"strtrans", 1, 1, f_strtrans},
912 {"strwidth", 1, 1, f_strwidth},
913 {"submatch", 1, 2, f_submatch},
914 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200915 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200916 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917 {"synID", 3, 3, f_synID},
918 {"synIDattr", 2, 3, f_synIDattr},
919 {"synIDtrans", 1, 1, f_synIDtrans},
920 {"synconcealed", 2, 2, f_synconcealed},
921 {"synstack", 2, 2, f_synstack},
922 {"system", 1, 2, f_system},
923 {"systemlist", 1, 2, f_systemlist},
924 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
925 {"tabpagenr", 0, 1, f_tabpagenr},
926 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
927 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100928 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#ifdef FEAT_FLOAT
930 {"tan", 1, 1, f_tan},
931 {"tanh", 1, 1, f_tanh},
932#endif
933 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200934#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100935 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
936 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100937 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200938 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200939# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
940 {"term_getansicolors", 1, 1, f_term_getansicolors},
941# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200942 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200943 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200944 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200945 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200946 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200947 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200948 {"term_getstatus", 1, 1, f_term_getstatus},
949 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200950 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200951 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200952 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200953 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200954# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
955 {"term_setansicolors", 2, 2, f_term_setansicolors},
956# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100957 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100958 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200959 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200960 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200961 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200962#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200963 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
964 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200965 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200966 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100967 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100968 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200969#ifdef FEAT_JOB_CHANNEL
970 {"test_null_channel", 0, 0, f_test_null_channel},
971#endif
972 {"test_null_dict", 0, 0, f_test_null_dict},
973#ifdef FEAT_JOB_CHANNEL
974 {"test_null_job", 0, 0, f_test_null_job},
975#endif
976 {"test_null_list", 0, 0, f_test_null_list},
977 {"test_null_partial", 0, 0, f_test_null_partial},
978 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200979 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100980 {"test_override", 2, 2, f_test_override},
981 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200982#ifdef FEAT_GUI
983 {"test_scrollbar", 3, 3, f_test_scrollbar},
984#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200985 {"test_settime", 1, 1, f_test_settime},
986#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200987 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200988 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200989 {"timer_start", 2, 3, f_timer_start},
990 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200991 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200992#endif
993 {"tolower", 1, 1, f_tolower},
994 {"toupper", 1, 1, f_toupper},
995 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100996 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200997#ifdef FEAT_FLOAT
998 {"trunc", 1, 1, f_trunc},
999#endif
1000 {"type", 1, 1, f_type},
1001 {"undofile", 1, 1, f_undofile},
1002 {"undotree", 0, 0, f_undotree},
1003 {"uniq", 1, 3, f_uniq},
1004 {"values", 1, 1, f_values},
1005 {"virtcol", 1, 1, f_virtcol},
1006 {"visualmode", 0, 1, f_visualmode},
1007 {"wildmenumode", 0, 0, f_wildmenumode},
1008 {"win_findbuf", 1, 1, f_win_findbuf},
1009 {"win_getid", 0, 2, f_win_getid},
1010 {"win_gotoid", 1, 1, f_win_gotoid},
1011 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1012 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001013 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014 {"winbufnr", 1, 1, f_winbufnr},
1015 {"wincol", 0, 0, f_wincol},
1016 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001017 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001018 {"winline", 0, 0, f_winline},
1019 {"winnr", 0, 1, f_winnr},
1020 {"winrestcmd", 0, 0, f_winrestcmd},
1021 {"winrestview", 1, 1, f_winrestview},
1022 {"winsaveview", 0, 0, f_winsaveview},
1023 {"winwidth", 1, 1, f_winwidth},
1024 {"wordcount", 0, 0, f_wordcount},
1025 {"writefile", 2, 3, f_writefile},
1026 {"xor", 2, 2, f_xor},
1027};
1028
1029#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1030
1031/*
1032 * Function given to ExpandGeneric() to obtain the list of internal
1033 * or user defined function names.
1034 */
1035 char_u *
1036get_function_name(expand_T *xp, int idx)
1037{
1038 static int intidx = -1;
1039 char_u *name;
1040
1041 if (idx == 0)
1042 intidx = -1;
1043 if (intidx < 0)
1044 {
1045 name = get_user_func_name(xp, idx);
1046 if (name != NULL)
1047 return name;
1048 }
1049 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1050 {
1051 STRCPY(IObuff, functions[intidx].f_name);
1052 STRCAT(IObuff, "(");
1053 if (functions[intidx].f_max_argc == 0)
1054 STRCAT(IObuff, ")");
1055 return IObuff;
1056 }
1057
1058 return NULL;
1059}
1060
1061/*
1062 * Function given to ExpandGeneric() to obtain the list of internal or
1063 * user defined variable or function names.
1064 */
1065 char_u *
1066get_expr_name(expand_T *xp, int idx)
1067{
1068 static int intidx = -1;
1069 char_u *name;
1070
1071 if (idx == 0)
1072 intidx = -1;
1073 if (intidx < 0)
1074 {
1075 name = get_function_name(xp, idx);
1076 if (name != NULL)
1077 return name;
1078 }
1079 return get_user_var_name(xp, ++intidx);
1080}
1081
1082#endif /* FEAT_CMDL_COMPL */
1083
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001084/*
1085 * Find internal function in table above.
1086 * Return index, or -1 if not found
1087 */
1088 int
1089find_internal_func(
1090 char_u *name) /* name of the function */
1091{
1092 int first = 0;
1093 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1094 int cmp;
1095 int x;
1096
1097 /*
1098 * Find the function name in the table. Binary search.
1099 */
1100 while (first <= last)
1101 {
1102 x = first + ((unsigned)(last - first) >> 1);
1103 cmp = STRCMP(name, functions[x].f_name);
1104 if (cmp < 0)
1105 last = x - 1;
1106 else if (cmp > 0)
1107 first = x + 1;
1108 else
1109 return x;
1110 }
1111 return -1;
1112}
1113
1114 int
1115call_internal_func(
1116 char_u *name,
1117 int argcount,
1118 typval_T *argvars,
1119 typval_T *rettv)
1120{
1121 int i;
1122
1123 i = find_internal_func(name);
1124 if (i < 0)
1125 return ERROR_UNKNOWN;
1126 if (argcount < functions[i].f_min_argc)
1127 return ERROR_TOOFEW;
1128 if (argcount > functions[i].f_max_argc)
1129 return ERROR_TOOMANY;
1130 argvars[argcount].v_type = VAR_UNKNOWN;
1131 functions[i].f_func(argvars, rettv);
1132 return ERROR_NONE;
1133}
1134
1135/*
1136 * Return TRUE for a non-zero Number and a non-empty String.
1137 */
1138 static int
1139non_zero_arg(typval_T *argvars)
1140{
1141 return ((argvars[0].v_type == VAR_NUMBER
1142 && argvars[0].vval.v_number != 0)
1143 || (argvars[0].v_type == VAR_SPECIAL
1144 && argvars[0].vval.v_number == VVAL_TRUE)
1145 || (argvars[0].v_type == VAR_STRING
1146 && argvars[0].vval.v_string != NULL
1147 && *argvars[0].vval.v_string != NUL));
1148}
1149
1150/*
1151 * Get the lnum from the first argument.
1152 * Also accepts ".", "$", etc., but that only works for the current buffer.
1153 * Returns -1 on error.
1154 */
1155 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001156tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001157{
1158 typval_T rettv;
1159 linenr_T lnum;
1160
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001161 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001162 if (lnum == 0) /* no valid number, try using line() */
1163 {
1164 rettv.v_type = VAR_NUMBER;
1165 f_line(argvars, &rettv);
1166 lnum = (linenr_T)rettv.vval.v_number;
1167 clear_tv(&rettv);
1168 }
1169 return lnum;
1170}
1171
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001172/*
1173 * Get the lnum from the first argument.
1174 * Also accepts "$", then "buf" is used.
1175 * Returns 0 on error.
1176 */
1177 static linenr_T
1178tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1179{
1180 if (argvars[0].v_type == VAR_STRING
1181 && argvars[0].vval.v_string != NULL
1182 && argvars[0].vval.v_string[0] == '$'
1183 && buf != NULL)
1184 return buf->b_ml.ml_line_count;
1185 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1186}
1187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001188#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001189/*
1190 * Get the float value of "argvars[0]" into "f".
1191 * Returns FAIL when the argument is not a Number or Float.
1192 */
1193 static int
1194get_float_arg(typval_T *argvars, float_T *f)
1195{
1196 if (argvars[0].v_type == VAR_FLOAT)
1197 {
1198 *f = argvars[0].vval.v_float;
1199 return OK;
1200 }
1201 if (argvars[0].v_type == VAR_NUMBER)
1202 {
1203 *f = (float_T)argvars[0].vval.v_number;
1204 return OK;
1205 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001206 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001207 return FAIL;
1208}
1209
1210/*
1211 * "abs(expr)" function
1212 */
1213 static void
1214f_abs(typval_T *argvars, typval_T *rettv)
1215{
1216 if (argvars[0].v_type == VAR_FLOAT)
1217 {
1218 rettv->v_type = VAR_FLOAT;
1219 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1220 }
1221 else
1222 {
1223 varnumber_T n;
1224 int error = FALSE;
1225
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001226 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001227 if (error)
1228 rettv->vval.v_number = -1;
1229 else if (n > 0)
1230 rettv->vval.v_number = n;
1231 else
1232 rettv->vval.v_number = -n;
1233 }
1234}
1235
1236/*
1237 * "acos()" function
1238 */
1239 static void
1240f_acos(typval_T *argvars, typval_T *rettv)
1241{
1242 float_T f = 0.0;
1243
1244 rettv->v_type = VAR_FLOAT;
1245 if (get_float_arg(argvars, &f) == OK)
1246 rettv->vval.v_float = acos(f);
1247 else
1248 rettv->vval.v_float = 0.0;
1249}
1250#endif
1251
1252/*
1253 * "add(list, item)" function
1254 */
1255 static void
1256f_add(typval_T *argvars, typval_T *rettv)
1257{
1258 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001259 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001260
1261 rettv->vval.v_number = 1; /* Default: Failed */
1262 if (argvars[0].v_type == VAR_LIST)
1263 {
1264 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001265 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001266 (char_u *)N_("add() argument"), TRUE)
1267 && list_append_tv(l, &argvars[1]) == OK)
1268 copy_tv(&argvars[0], rettv);
1269 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001270 else if (argvars[0].v_type == VAR_BLOB)
1271 {
1272 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001273 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001274 (char_u *)N_("add() argument"), TRUE))
1275 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001276 int error = FALSE;
1277 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1278
1279 if (!error)
1280 {
1281 ga_append(&b->bv_ga, (int)n);
1282 copy_tv(&argvars[0], rettv);
1283 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001284 }
1285 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001286 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001287 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001288}
1289
1290/*
1291 * "and(expr, expr)" function
1292 */
1293 static void
1294f_and(typval_T *argvars, typval_T *rettv)
1295{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001296 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1297 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001298}
1299
1300/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001301 * If there is a window for "curbuf", make it the current window.
1302 */
1303 static void
1304find_win_for_curbuf(void)
1305{
1306 wininfo_T *wip;
1307
1308 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1309 {
1310 if (wip->wi_win != NULL)
1311 {
1312 curwin = wip->wi_win;
1313 break;
1314 }
1315 }
1316}
1317
1318/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001319 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001320 */
1321 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001322set_buffer_lines(
1323 buf_T *buf,
1324 linenr_T lnum_arg,
1325 int append,
1326 typval_T *lines,
1327 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001328{
Bram Moolenaarca851592018-06-06 21:04:07 +02001329 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1330 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001331 list_T *l = NULL;
1332 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001333 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001334 linenr_T append_lnum;
1335 buf_T *curbuf_save = NULL;
1336 win_T *curwin_save = NULL;
1337 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001338
Bram Moolenaarca851592018-06-06 21:04:07 +02001339 /* When using the current buffer ml_mfp will be set if needed. Useful when
1340 * setline() is used on startup. For other buffers the buffer must be
1341 * loaded. */
1342 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 rettv->vval.v_number = 1; /* FAIL */
1345 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001346 }
1347
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001349 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001350 curbuf_save = curbuf;
1351 curwin_save = curwin;
1352 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001353 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001354 }
1355
1356 if (append)
1357 // appendbufline() uses the line number below which we insert
1358 append_lnum = lnum - 1;
1359 else
1360 // setbufline() uses the line number above which we insert, we only
1361 // append if it's below the last line
1362 append_lnum = curbuf->b_ml.ml_line_count;
1363
1364 if (lines->v_type == VAR_LIST)
1365 {
1366 l = lines->vval.v_list;
1367 li = l->lv_first;
1368 }
1369 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001370 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001371
1372 /* default result is zero == OK */
1373 for (;;)
1374 {
1375 if (l != NULL)
1376 {
1377 /* list argument, get next string */
1378 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001379 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001380 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001381 li = li->li_next;
1382 }
1383
Bram Moolenaarca851592018-06-06 21:04:07 +02001384 rettv->vval.v_number = 1; /* FAIL */
1385 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1386 break;
1387
1388 /* When coming here from Insert mode, sync undo, so that this can be
1389 * undone separately from what was previously inserted. */
1390 if (u_sync_once == 2)
1391 {
1392 u_sync_once = 1; /* notify that u_sync() was called */
1393 u_sync(TRUE);
1394 }
1395
1396 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1397 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001398 // Existing line, replace it.
1399 // Removes any existing text properties.
1400 if (u_savesub(lnum) == OK && ml_replace_len(
1401 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001402 {
1403 changed_bytes(lnum, 0);
1404 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1405 check_cursor_col();
1406 rettv->vval.v_number = 0; /* OK */
1407 }
1408 }
1409 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1410 {
1411 /* append the line */
1412 ++added;
1413 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1414 rettv->vval.v_number = 0; /* OK */
1415 }
1416
1417 if (l == NULL) /* only one string argument */
1418 break;
1419 ++lnum;
1420 }
1421
1422 if (added > 0)
1423 {
1424 win_T *wp;
1425 tabpage_T *tp;
1426
1427 appended_lines_mark(append_lnum, added);
1428 FOR_ALL_TAB_WINDOWS(tp, wp)
1429 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1430 wp->w_cursor.lnum += added;
1431 check_cursor_col();
1432
Bram Moolenaarf2732452018-06-03 14:47:35 +02001433#ifdef FEAT_JOB_CHANNEL
1434 if (bt_prompt(curbuf) && (State & INSERT))
1435 // show the line with the prompt
1436 update_topline();
1437#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001439
1440 if (!is_curbuf)
1441 {
1442 curbuf = curbuf_save;
1443 curwin = curwin_save;
1444 }
1445}
1446
1447/*
1448 * "append(lnum, string/list)" function
1449 */
1450 static void
1451f_append(typval_T *argvars, typval_T *rettv)
1452{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001453 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001454
1455 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1456}
1457
1458/*
1459 * "appendbufline(buf, lnum, string/list)" function
1460 */
1461 static void
1462f_appendbufline(typval_T *argvars, typval_T *rettv)
1463{
1464 linenr_T lnum;
1465 buf_T *buf;
1466
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001467 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001468 if (buf == NULL)
1469 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001470 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001471 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001472 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001473 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1474 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001475}
1476
1477/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001478 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001479 */
1480 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001481f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001482{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001483 win_T *wp;
1484
1485 if (argvars[0].v_type == VAR_UNKNOWN)
1486 // use the current window
1487 rettv->vval.v_number = ARGCOUNT;
1488 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001489 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001490 // use the global argument list
1491 rettv->vval.v_number = GARGCOUNT;
1492 else
1493 {
1494 // use the argument list of the specified window
1495 wp = find_win_by_nr_or_id(&argvars[0]);
1496 if (wp != NULL)
1497 rettv->vval.v_number = WARGCOUNT(wp);
1498 else
1499 rettv->vval.v_number = -1;
1500 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501}
1502
1503/*
1504 * "argidx()" function
1505 */
1506 static void
1507f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1508{
1509 rettv->vval.v_number = curwin->w_arg_idx;
1510}
1511
1512/*
1513 * "arglistid()" function
1514 */
1515 static void
1516f_arglistid(typval_T *argvars, typval_T *rettv)
1517{
1518 win_T *wp;
1519
1520 rettv->vval.v_number = -1;
1521 wp = find_tabwin(&argvars[0], &argvars[1]);
1522 if (wp != NULL)
1523 rettv->vval.v_number = wp->w_alist->id;
1524}
1525
1526/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001527 * Get the argument list for a given window
1528 */
1529 static void
1530get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1531{
1532 int idx;
1533
1534 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1535 for (idx = 0; idx < argcount; ++idx)
1536 list_append_string(rettv->vval.v_list,
1537 alist_name(&arglist[idx]), -1);
1538}
1539
1540/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001541 * "argv(nr)" function
1542 */
1543 static void
1544f_argv(typval_T *argvars, typval_T *rettv)
1545{
1546 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001547 aentry_T *arglist = NULL;
1548 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549
1550 if (argvars[0].v_type != VAR_UNKNOWN)
1551 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001552 if (argvars[1].v_type == VAR_UNKNOWN)
1553 {
1554 arglist = ARGLIST;
1555 argcount = ARGCOUNT;
1556 }
1557 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001558 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001559 {
1560 arglist = GARGLIST;
1561 argcount = GARGCOUNT;
1562 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001563 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001564 {
1565 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1566
1567 if (wp != NULL)
1568 {
1569 /* Use the argument list of the specified window */
1570 arglist = WARGLIST(wp);
1571 argcount = WARGCOUNT(wp);
1572 }
1573 }
1574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001576 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001577 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001578 if (arglist != NULL && idx >= 0 && idx < argcount)
1579 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1580 else if (idx == -1)
1581 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001582 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001583 else
1584 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001585}
1586
1587/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001588 * "assert_beeps(cmd [, error])" function
1589 */
1590 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001591f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001592{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001593 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001594}
1595
1596/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 * "assert_equal(expected, actual[, msg])" function
1598 */
1599 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001600f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001602 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603}
1604
1605/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001606 * "assert_equalfile(fname-one, fname-two)" function
1607 */
1608 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001609f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001610{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001611 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001612}
1613
1614/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001615 * "assert_notequal(expected, actual[, msg])" function
1616 */
1617 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001618f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001619{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001620 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001621}
1622
1623/*
1624 * "assert_exception(string[, msg])" function
1625 */
1626 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001627f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001628{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001629 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630}
1631
1632/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001633 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634 */
1635 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001636f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001637{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001638 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001639}
1640
1641/*
1642 * "assert_false(actual[, msg])" function
1643 */
1644 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001645f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001647 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648}
1649
1650/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001651 * "assert_inrange(lower, upper[, msg])" function
1652 */
1653 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001654f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001655{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001656 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001657}
1658
1659/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001660 * "assert_match(pattern, actual[, msg])" function
1661 */
1662 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001663f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001664{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001665 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001666}
1667
1668/*
1669 * "assert_notmatch(pattern, actual[, msg])" function
1670 */
1671 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001672f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001674 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675}
1676
1677/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001678 * "assert_report(msg)" function
1679 */
1680 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001681f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001682{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001683 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001684}
1685
1686/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 * "assert_true(actual[, msg])" function
1688 */
1689 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001690f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001692 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693}
1694
1695#ifdef FEAT_FLOAT
1696/*
1697 * "asin()" function
1698 */
1699 static void
1700f_asin(typval_T *argvars, typval_T *rettv)
1701{
1702 float_T f = 0.0;
1703
1704 rettv->v_type = VAR_FLOAT;
1705 if (get_float_arg(argvars, &f) == OK)
1706 rettv->vval.v_float = asin(f);
1707 else
1708 rettv->vval.v_float = 0.0;
1709}
1710
1711/*
1712 * "atan()" function
1713 */
1714 static void
1715f_atan(typval_T *argvars, typval_T *rettv)
1716{
1717 float_T f = 0.0;
1718
1719 rettv->v_type = VAR_FLOAT;
1720 if (get_float_arg(argvars, &f) == OK)
1721 rettv->vval.v_float = atan(f);
1722 else
1723 rettv->vval.v_float = 0.0;
1724}
1725
1726/*
1727 * "atan2()" function
1728 */
1729 static void
1730f_atan2(typval_T *argvars, typval_T *rettv)
1731{
1732 float_T fx = 0.0, fy = 0.0;
1733
1734 rettv->v_type = VAR_FLOAT;
1735 if (get_float_arg(argvars, &fx) == OK
1736 && get_float_arg(&argvars[1], &fy) == OK)
1737 rettv->vval.v_float = atan2(fx, fy);
1738 else
1739 rettv->vval.v_float = 0.0;
1740}
1741#endif
1742
1743/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001744 * "balloon_show()" function
1745 */
1746#ifdef FEAT_BEVAL
1747 static void
1748f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1749{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001750 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001751 {
1752 if (argvars[0].v_type == VAR_LIST
1753# ifdef FEAT_GUI
1754 && !gui.in_use
1755# endif
1756 )
1757 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1758 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001759 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001760 }
1761}
1762
Bram Moolenaar669a8282017-11-19 20:13:05 +01001763# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001764 static void
1765f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1766{
1767 if (rettv_list_alloc(rettv) == OK)
1768 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001769 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001770
1771 if (msg != NULL)
1772 {
1773 pumitem_T *array;
1774 int size = split_message(msg, &array);
1775 int i;
1776
1777 /* Skip the first and last item, they are always empty. */
1778 for (i = 1; i < size - 1; ++i)
1779 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001780 while (size > 0)
1781 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001782 vim_free(array);
1783 }
1784 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001785}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001786# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001787#endif
1788
1789/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 * "browse(save, title, initdir, default)" function
1791 */
1792 static void
1793f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1794{
1795#ifdef FEAT_BROWSE
1796 int save;
1797 char_u *title;
1798 char_u *initdir;
1799 char_u *defname;
1800 char_u buf[NUMBUFLEN];
1801 char_u buf2[NUMBUFLEN];
1802 int error = FALSE;
1803
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001804 save = (int)tv_get_number_chk(&argvars[0], &error);
1805 title = tv_get_string_chk(&argvars[1]);
1806 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1807 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001808
1809 if (error || title == NULL || initdir == NULL || defname == NULL)
1810 rettv->vval.v_string = NULL;
1811 else
1812 rettv->vval.v_string =
1813 do_browse(save ? BROWSE_SAVE : 0,
1814 title, defname, NULL, initdir, NULL, curbuf);
1815#else
1816 rettv->vval.v_string = NULL;
1817#endif
1818 rettv->v_type = VAR_STRING;
1819}
1820
1821/*
1822 * "browsedir(title, initdir)" function
1823 */
1824 static void
1825f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1826{
1827#ifdef FEAT_BROWSE
1828 char_u *title;
1829 char_u *initdir;
1830 char_u buf[NUMBUFLEN];
1831
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001832 title = tv_get_string_chk(&argvars[0]);
1833 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834
1835 if (title == NULL || initdir == NULL)
1836 rettv->vval.v_string = NULL;
1837 else
1838 rettv->vval.v_string = do_browse(BROWSE_DIR,
1839 title, NULL, NULL, initdir, NULL, curbuf);
1840#else
1841 rettv->vval.v_string = NULL;
1842#endif
1843 rettv->v_type = VAR_STRING;
1844}
1845
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846/*
1847 * Find a buffer by number or exact name.
1848 */
1849 static buf_T *
1850find_buffer(typval_T *avar)
1851{
1852 buf_T *buf = NULL;
1853
1854 if (avar->v_type == VAR_NUMBER)
1855 buf = buflist_findnr((int)avar->vval.v_number);
1856 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1857 {
1858 buf = buflist_findname_exp(avar->vval.v_string);
1859 if (buf == NULL)
1860 {
1861 /* No full path name match, try a match with a URL or a "nofile"
1862 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001863 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001864 if (buf->b_fname != NULL
1865 && (path_with_url(buf->b_fname)
1866#ifdef FEAT_QUICKFIX
1867 || bt_nofile(buf)
1868#endif
1869 )
1870 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1871 break;
1872 }
1873 }
1874 return buf;
1875}
1876
1877/*
1878 * "bufexists(expr)" function
1879 */
1880 static void
1881f_bufexists(typval_T *argvars, typval_T *rettv)
1882{
1883 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1884}
1885
1886/*
1887 * "buflisted(expr)" function
1888 */
1889 static void
1890f_buflisted(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_p_bl);
1896}
1897
1898/*
1899 * "bufloaded(expr)" function
1900 */
1901 static void
1902f_bufloaded(typval_T *argvars, typval_T *rettv)
1903{
1904 buf_T *buf;
1905
1906 buf = find_buffer(&argvars[0]);
1907 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1908}
1909
1910 buf_T *
1911buflist_find_by_name(char_u *name, int curtab_only)
1912{
1913 int save_magic;
1914 char_u *save_cpo;
1915 buf_T *buf;
1916
1917 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1918 save_magic = p_magic;
1919 p_magic = TRUE;
1920 save_cpo = p_cpo;
1921 p_cpo = (char_u *)"";
1922
1923 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1924 TRUE, FALSE, curtab_only));
1925
1926 p_magic = save_magic;
1927 p_cpo = save_cpo;
1928 return buf;
1929}
1930
1931/*
1932 * Get buffer by number or pattern.
1933 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001934 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001935tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936{
1937 char_u *name = tv->vval.v_string;
1938 buf_T *buf;
1939
1940 if (tv->v_type == VAR_NUMBER)
1941 return buflist_findnr((int)tv->vval.v_number);
1942 if (tv->v_type != VAR_STRING)
1943 return NULL;
1944 if (name == NULL || *name == NUL)
1945 return curbuf;
1946 if (name[0] == '$' && name[1] == NUL)
1947 return lastbuf;
1948
1949 buf = buflist_find_by_name(name, curtab_only);
1950
1951 /* If not found, try expanding the name, like done for bufexists(). */
1952 if (buf == NULL)
1953 buf = find_buffer(tv);
1954
1955 return buf;
1956}
1957
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001958#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001959/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001960 * Get the buffer from "arg" and give an error and return NULL if it is not
1961 * valid.
1962 */
1963 static buf_T *
1964get_buf_arg(typval_T *arg)
1965{
1966 buf_T *buf;
1967
1968 ++emsg_off;
1969 buf = tv_get_buf(arg, FALSE);
1970 --emsg_off;
1971 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001972 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001973 return buf;
1974}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001975#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001976
1977/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 * "bufname(expr)" function
1979 */
1980 static void
1981f_bufname(typval_T *argvars, typval_T *rettv)
1982{
1983 buf_T *buf;
1984
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001985 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001987 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988 rettv->v_type = VAR_STRING;
1989 if (buf != NULL && buf->b_fname != NULL)
1990 rettv->vval.v_string = vim_strsave(buf->b_fname);
1991 else
1992 rettv->vval.v_string = NULL;
1993 --emsg_off;
1994}
1995
1996/*
1997 * "bufnr(expr)" function
1998 */
1999 static void
2000f_bufnr(typval_T *argvars, typval_T *rettv)
2001{
2002 buf_T *buf;
2003 int error = FALSE;
2004 char_u *name;
2005
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002006 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002007 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002008 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002009 --emsg_off;
2010
2011 /* If the buffer isn't found and the second argument is not zero create a
2012 * new buffer. */
2013 if (buf == NULL
2014 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002015 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002017 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 && !error)
2019 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2020
2021 if (buf != NULL)
2022 rettv->vval.v_number = buf->b_fnum;
2023 else
2024 rettv->vval.v_number = -1;
2025}
2026
2027 static void
2028buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2029{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030 win_T *wp;
2031 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032 buf_T *buf;
2033
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002034 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002036 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002037 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002038 {
2039 ++winnr;
2040 if (wp->w_buffer == buf)
2041 break;
2042 }
2043 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002044 --emsg_off;
2045}
2046
2047/*
2048 * "bufwinid(nr)" function
2049 */
2050 static void
2051f_bufwinid(typval_T *argvars, typval_T *rettv)
2052{
2053 buf_win_common(argvars, rettv, FALSE);
2054}
2055
2056/*
2057 * "bufwinnr(nr)" function
2058 */
2059 static void
2060f_bufwinnr(typval_T *argvars, typval_T *rettv)
2061{
2062 buf_win_common(argvars, rettv, TRUE);
2063}
2064
2065/*
2066 * "byte2line(byte)" function
2067 */
2068 static void
2069f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2070{
2071#ifndef FEAT_BYTEOFF
2072 rettv->vval.v_number = -1;
2073#else
2074 long boff = 0;
2075
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002076 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077 if (boff < 0)
2078 rettv->vval.v_number = -1;
2079 else
2080 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2081 (linenr_T)0, &boff);
2082#endif
2083}
2084
2085 static void
2086byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2087{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089 char_u *str;
2090 varnumber_T idx;
2091
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002092 str = tv_get_string_chk(&argvars[0]);
2093 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002094 rettv->vval.v_number = -1;
2095 if (str == NULL || idx < 0)
2096 return;
2097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 t = str;
2099 for ( ; idx > 0; idx--)
2100 {
2101 if (*t == NUL) /* EOL reached */
2102 return;
2103 if (enc_utf8 && comp)
2104 t += utf_ptr2len(t);
2105 else
2106 t += (*mb_ptr2len)(t);
2107 }
2108 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002109}
2110
2111/*
2112 * "byteidx()" function
2113 */
2114 static void
2115f_byteidx(typval_T *argvars, typval_T *rettv)
2116{
2117 byteidx(argvars, rettv, FALSE);
2118}
2119
2120/*
2121 * "byteidxcomp()" function
2122 */
2123 static void
2124f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2125{
2126 byteidx(argvars, rettv, TRUE);
2127}
2128
2129/*
2130 * "call(func, arglist [, dict])" function
2131 */
2132 static void
2133f_call(typval_T *argvars, typval_T *rettv)
2134{
2135 char_u *func;
2136 partial_T *partial = NULL;
2137 dict_T *selfdict = NULL;
2138
2139 if (argvars[1].v_type != VAR_LIST)
2140 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002141 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002142 return;
2143 }
2144 if (argvars[1].vval.v_list == NULL)
2145 return;
2146
2147 if (argvars[0].v_type == VAR_FUNC)
2148 func = argvars[0].vval.v_string;
2149 else if (argvars[0].v_type == VAR_PARTIAL)
2150 {
2151 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002152 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 }
2154 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002155 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002156 if (*func == NUL)
2157 return; /* type error or empty name */
2158
2159 if (argvars[2].v_type != VAR_UNKNOWN)
2160 {
2161 if (argvars[2].v_type != VAR_DICT)
2162 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002163 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 return;
2165 }
2166 selfdict = argvars[2].vval.v_dict;
2167 }
2168
2169 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2170}
2171
2172#ifdef FEAT_FLOAT
2173/*
2174 * "ceil({float})" function
2175 */
2176 static void
2177f_ceil(typval_T *argvars, typval_T *rettv)
2178{
2179 float_T f = 0.0;
2180
2181 rettv->v_type = VAR_FLOAT;
2182 if (get_float_arg(argvars, &f) == OK)
2183 rettv->vval.v_float = ceil(f);
2184 else
2185 rettv->vval.v_float = 0.0;
2186}
2187#endif
2188
2189#ifdef FEAT_JOB_CHANNEL
2190/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002191 * "ch_canread()" function
2192 */
2193 static void
2194f_ch_canread(typval_T *argvars, typval_T *rettv)
2195{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002196 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002197
2198 rettv->vval.v_number = 0;
2199 if (channel != NULL)
2200 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2201 || channel_has_readahead(channel, PART_OUT)
2202 || channel_has_readahead(channel, PART_ERR);
2203}
2204
2205/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206 * "ch_close()" function
2207 */
2208 static void
2209f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2210{
2211 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2212
2213 if (channel != NULL)
2214 {
2215 channel_close(channel, FALSE);
2216 channel_clear(channel);
2217 }
2218}
2219
2220/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002221 * "ch_close()" function
2222 */
2223 static void
2224f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2225{
2226 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2227
2228 if (channel != NULL)
2229 channel_close_in(channel);
2230}
2231
2232/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002233 * "ch_getbufnr()" function
2234 */
2235 static void
2236f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2237{
2238 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2239
2240 rettv->vval.v_number = -1;
2241 if (channel != NULL)
2242 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002243 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002244 int part;
2245
2246 if (STRCMP(what, "err") == 0)
2247 part = PART_ERR;
2248 else if (STRCMP(what, "out") == 0)
2249 part = PART_OUT;
2250 else if (STRCMP(what, "in") == 0)
2251 part = PART_IN;
2252 else
2253 part = PART_SOCK;
2254 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2255 rettv->vval.v_number =
2256 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2257 }
2258}
2259
2260/*
2261 * "ch_getjob()" function
2262 */
2263 static void
2264f_ch_getjob(typval_T *argvars, typval_T *rettv)
2265{
2266 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2267
2268 if (channel != NULL)
2269 {
2270 rettv->v_type = VAR_JOB;
2271 rettv->vval.v_job = channel->ch_job;
2272 if (channel->ch_job != NULL)
2273 ++channel->ch_job->jv_refcount;
2274 }
2275}
2276
2277/*
2278 * "ch_info()" function
2279 */
2280 static void
2281f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2282{
2283 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2284
2285 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2286 channel_info(channel, rettv->vval.v_dict);
2287}
2288
2289/*
2290 * "ch_log()" function
2291 */
2292 static void
2293f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2294{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002295 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 channel_T *channel = NULL;
2297
2298 if (argvars[1].v_type != VAR_UNKNOWN)
2299 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2300
Bram Moolenaard5359b22018-04-05 22:44:39 +02002301 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002302}
2303
2304/*
2305 * "ch_logfile()" function
2306 */
2307 static void
2308f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2309{
2310 char_u *fname;
2311 char_u *opt = (char_u *)"";
2312 char_u buf[NUMBUFLEN];
2313
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002314 /* Don't open a file in restricted mode. */
2315 if (check_restricted() || check_secure())
2316 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002317 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002318 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002319 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002320 ch_logfile(fname, opt);
2321}
2322
2323/*
2324 * "ch_open()" function
2325 */
2326 static void
2327f_ch_open(typval_T *argvars, typval_T *rettv)
2328{
2329 rettv->v_type = VAR_CHANNEL;
2330 if (check_restricted() || check_secure())
2331 return;
2332 rettv->vval.v_channel = channel_open_func(argvars);
2333}
2334
2335/*
2336 * "ch_read()" function
2337 */
2338 static void
2339f_ch_read(typval_T *argvars, typval_T *rettv)
2340{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002341 common_channel_read(argvars, rettv, FALSE, FALSE);
2342}
2343
2344/*
2345 * "ch_readblob()" function
2346 */
2347 static void
2348f_ch_readblob(typval_T *argvars, typval_T *rettv)
2349{
2350 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002351}
2352
2353/*
2354 * "ch_readraw()" function
2355 */
2356 static void
2357f_ch_readraw(typval_T *argvars, typval_T *rettv)
2358{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002359 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360}
2361
2362/*
2363 * "ch_evalexpr()" function
2364 */
2365 static void
2366f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2367{
2368 ch_expr_common(argvars, rettv, TRUE);
2369}
2370
2371/*
2372 * "ch_sendexpr()" function
2373 */
2374 static void
2375f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2376{
2377 ch_expr_common(argvars, rettv, FALSE);
2378}
2379
2380/*
2381 * "ch_evalraw()" function
2382 */
2383 static void
2384f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2385{
2386 ch_raw_common(argvars, rettv, TRUE);
2387}
2388
2389/*
2390 * "ch_sendraw()" function
2391 */
2392 static void
2393f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2394{
2395 ch_raw_common(argvars, rettv, FALSE);
2396}
2397
2398/*
2399 * "ch_setoptions()" function
2400 */
2401 static void
2402f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2403{
2404 channel_T *channel;
2405 jobopt_T opt;
2406
2407 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2408 if (channel == NULL)
2409 return;
2410 clear_job_options(&opt);
2411 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002412 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002413 channel_set_options(channel, &opt);
2414 free_job_options(&opt);
2415}
2416
2417/*
2418 * "ch_status()" function
2419 */
2420 static void
2421f_ch_status(typval_T *argvars, typval_T *rettv)
2422{
2423 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002424 jobopt_T opt;
2425 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002426
2427 /* return an empty string by default */
2428 rettv->v_type = VAR_STRING;
2429 rettv->vval.v_string = NULL;
2430
2431 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002432
2433 if (argvars[1].v_type != VAR_UNKNOWN)
2434 {
2435 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002436 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002437 && (opt.jo_set & JO_PART))
2438 part = opt.jo_part;
2439 }
2440
2441 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442}
2443#endif
2444
2445/*
2446 * "changenr()" function
2447 */
2448 static void
2449f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2450{
2451 rettv->vval.v_number = curbuf->b_u_seq_cur;
2452}
2453
2454/*
2455 * "char2nr(string)" function
2456 */
2457 static void
2458f_char2nr(typval_T *argvars, typval_T *rettv)
2459{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 if (has_mbyte)
2461 {
2462 int utf8 = 0;
2463
2464 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002465 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002466
2467 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002468 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002470 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471 }
2472 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002473 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474}
2475
2476/*
2477 * "cindent(lnum)" function
2478 */
2479 static void
2480f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2481{
2482#ifdef FEAT_CINDENT
2483 pos_T pos;
2484 linenr_T lnum;
2485
2486 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002487 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002488 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2489 {
2490 curwin->w_cursor.lnum = lnum;
2491 rettv->vval.v_number = get_c_indent();
2492 curwin->w_cursor = pos;
2493 }
2494 else
2495#endif
2496 rettv->vval.v_number = -1;
2497}
2498
2499/*
2500 * "clearmatches()" function
2501 */
2502 static void
2503f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2504{
2505#ifdef FEAT_SEARCH_EXTRA
2506 clear_matches(curwin);
2507#endif
2508}
2509
2510/*
2511 * "col(string)" function
2512 */
2513 static void
2514f_col(typval_T *argvars, typval_T *rettv)
2515{
2516 colnr_T col = 0;
2517 pos_T *fp;
2518 int fnum = curbuf->b_fnum;
2519
2520 fp = var2fpos(&argvars[0], FALSE, &fnum);
2521 if (fp != NULL && fnum == curbuf->b_fnum)
2522 {
2523 if (fp->col == MAXCOL)
2524 {
2525 /* '> can be MAXCOL, get the length of the line then */
2526 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2527 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2528 else
2529 col = MAXCOL;
2530 }
2531 else
2532 {
2533 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002534 /* col(".") when the cursor is on the NUL at the end of the line
2535 * because of "coladd" can be seen as an extra column. */
2536 if (virtual_active() && fp == &curwin->w_cursor)
2537 {
2538 char_u *p = ml_get_cursor();
2539
2540 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2541 curwin->w_virtcol - curwin->w_cursor.coladd))
2542 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 int l;
2544
2545 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2546 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002547 }
2548 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002549 }
2550 }
2551 rettv->vval.v_number = col;
2552}
2553
2554#if defined(FEAT_INS_EXPAND)
2555/*
2556 * "complete()" function
2557 */
2558 static void
2559f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2560{
2561 int startcol;
2562
2563 if ((State & INSERT) == 0)
2564 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002565 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002566 return;
2567 }
2568
2569 /* Check for undo allowed here, because if something was already inserted
2570 * the line was already saved for undo and this check isn't done. */
2571 if (!undo_allowed())
2572 return;
2573
2574 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2575 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002576 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002577 return;
2578 }
2579
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002580 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 if (startcol <= 0)
2582 return;
2583
2584 set_completion(startcol - 1, argvars[1].vval.v_list);
2585}
2586
2587/*
2588 * "complete_add()" function
2589 */
2590 static void
2591f_complete_add(typval_T *argvars, typval_T *rettv)
2592{
2593 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2594}
2595
2596/*
2597 * "complete_check()" function
2598 */
2599 static void
2600f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2601{
2602 int saved = RedrawingDisabled;
2603
2604 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002605 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002606 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607 RedrawingDisabled = saved;
2608}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002609
2610/*
2611 * "complete_info()" function
2612 */
2613 static void
2614f_complete_info(typval_T *argvars, typval_T *rettv)
2615{
2616 list_T *what_list = NULL;
2617
2618 if (rettv_dict_alloc(rettv) != OK)
2619 return;
2620
2621 if (argvars[0].v_type != VAR_UNKNOWN)
2622 {
2623 if (argvars[0].v_type != VAR_LIST)
2624 {
2625 emsg(_(e_listreq));
2626 return;
2627 }
2628 what_list = argvars[0].vval.v_list;
2629 }
2630 get_complete_info(what_list, rettv->vval.v_dict);
2631}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632#endif
2633
2634/*
2635 * "confirm(message, buttons[, default [, type]])" function
2636 */
2637 static void
2638f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2639{
2640#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2641 char_u *message;
2642 char_u *buttons = NULL;
2643 char_u buf[NUMBUFLEN];
2644 char_u buf2[NUMBUFLEN];
2645 int def = 1;
2646 int type = VIM_GENERIC;
2647 char_u *typestr;
2648 int error = FALSE;
2649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002650 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 if (message == NULL)
2652 error = TRUE;
2653 if (argvars[1].v_type != VAR_UNKNOWN)
2654 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002655 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 if (buttons == NULL)
2657 error = TRUE;
2658 if (argvars[2].v_type != VAR_UNKNOWN)
2659 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002660 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002661 if (argvars[3].v_type != VAR_UNKNOWN)
2662 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002663 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002664 if (typestr == NULL)
2665 error = TRUE;
2666 else
2667 {
2668 switch (TOUPPER_ASC(*typestr))
2669 {
2670 case 'E': type = VIM_ERROR; break;
2671 case 'Q': type = VIM_QUESTION; break;
2672 case 'I': type = VIM_INFO; break;
2673 case 'W': type = VIM_WARNING; break;
2674 case 'G': type = VIM_GENERIC; break;
2675 }
2676 }
2677 }
2678 }
2679 }
2680
2681 if (buttons == NULL || *buttons == NUL)
2682 buttons = (char_u *)_("&Ok");
2683
2684 if (!error)
2685 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2686 def, NULL, FALSE);
2687#endif
2688}
2689
2690/*
2691 * "copy()" function
2692 */
2693 static void
2694f_copy(typval_T *argvars, typval_T *rettv)
2695{
2696 item_copy(&argvars[0], rettv, FALSE, 0);
2697}
2698
2699#ifdef FEAT_FLOAT
2700/*
2701 * "cos()" function
2702 */
2703 static void
2704f_cos(typval_T *argvars, typval_T *rettv)
2705{
2706 float_T f = 0.0;
2707
2708 rettv->v_type = VAR_FLOAT;
2709 if (get_float_arg(argvars, &f) == OK)
2710 rettv->vval.v_float = cos(f);
2711 else
2712 rettv->vval.v_float = 0.0;
2713}
2714
2715/*
2716 * "cosh()" function
2717 */
2718 static void
2719f_cosh(typval_T *argvars, typval_T *rettv)
2720{
2721 float_T f = 0.0;
2722
2723 rettv->v_type = VAR_FLOAT;
2724 if (get_float_arg(argvars, &f) == OK)
2725 rettv->vval.v_float = cosh(f);
2726 else
2727 rettv->vval.v_float = 0.0;
2728}
2729#endif
2730
2731/*
2732 * "count()" function
2733 */
2734 static void
2735f_count(typval_T *argvars, typval_T *rettv)
2736{
2737 long n = 0;
2738 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002739 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002740
Bram Moolenaar9966b212017-07-28 16:46:57 +02002741 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002742 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002743
2744 if (argvars[0].v_type == VAR_STRING)
2745 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002746 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002747 char_u *p = argvars[0].vval.v_string;
2748 char_u *next;
2749
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002750 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002751 {
2752 if (ic)
2753 {
2754 size_t len = STRLEN(expr);
2755
2756 while (*p != NUL)
2757 {
2758 if (MB_STRNICMP(p, expr, len) == 0)
2759 {
2760 ++n;
2761 p += len;
2762 }
2763 else
2764 MB_PTR_ADV(p);
2765 }
2766 }
2767 else
2768 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2769 != NULL)
2770 {
2771 ++n;
2772 p = next + STRLEN(expr);
2773 }
2774 }
2775
2776 }
2777 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 {
2779 listitem_T *li;
2780 list_T *l;
2781 long idx;
2782
2783 if ((l = argvars[0].vval.v_list) != NULL)
2784 {
2785 li = l->lv_first;
2786 if (argvars[2].v_type != VAR_UNKNOWN)
2787 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788 if (argvars[3].v_type != VAR_UNKNOWN)
2789 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002790 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002791 if (!error)
2792 {
2793 li = list_find(l, idx);
2794 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002795 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002796 }
2797 }
2798 if (error)
2799 li = NULL;
2800 }
2801
2802 for ( ; li != NULL; li = li->li_next)
2803 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2804 ++n;
2805 }
2806 }
2807 else if (argvars[0].v_type == VAR_DICT)
2808 {
2809 int todo;
2810 dict_T *d;
2811 hashitem_T *hi;
2812
2813 if ((d = argvars[0].vval.v_dict) != NULL)
2814 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002815 if (argvars[2].v_type != VAR_UNKNOWN)
2816 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002818 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002819 }
2820
2821 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2822 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2823 {
2824 if (!HASHITEM_EMPTY(hi))
2825 {
2826 --todo;
2827 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2828 ++n;
2829 }
2830 }
2831 }
2832 }
2833 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002834 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002835 rettv->vval.v_number = n;
2836}
2837
2838/*
2839 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2840 *
2841 * Checks the existence of a cscope connection.
2842 */
2843 static void
2844f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2845{
2846#ifdef FEAT_CSCOPE
2847 int num = 0;
2848 char_u *dbpath = NULL;
2849 char_u *prepend = NULL;
2850 char_u buf[NUMBUFLEN];
2851
2852 if (argvars[0].v_type != VAR_UNKNOWN
2853 && argvars[1].v_type != VAR_UNKNOWN)
2854 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002855 num = (int)tv_get_number(&argvars[0]);
2856 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002858 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002859 }
2860
2861 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2862#endif
2863}
2864
2865/*
2866 * "cursor(lnum, col)" function, or
2867 * "cursor(list)"
2868 *
2869 * Moves the cursor to the specified line and column.
2870 * Returns 0 when the position could be set, -1 otherwise.
2871 */
2872 static void
2873f_cursor(typval_T *argvars, typval_T *rettv)
2874{
2875 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002877 int set_curswant = TRUE;
2878
2879 rettv->vval.v_number = -1;
2880 if (argvars[1].v_type == VAR_UNKNOWN)
2881 {
2882 pos_T pos;
2883 colnr_T curswant = -1;
2884
2885 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2886 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002887 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002888 return;
2889 }
2890 line = pos.lnum;
2891 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002892 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002893 if (curswant >= 0)
2894 {
2895 curwin->w_curswant = curswant - 1;
2896 set_curswant = FALSE;
2897 }
2898 }
2899 else
2900 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002901 line = tv_get_lnum(argvars);
2902 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002903 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002904 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002905 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002906 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002907 return; /* type error; errmsg already given */
2908 if (line > 0)
2909 curwin->w_cursor.lnum = line;
2910 if (col > 0)
2911 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913
2914 /* Make sure the cursor is in a valid position. */
2915 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002916 /* Correct cursor for multi-byte character. */
2917 if (has_mbyte)
2918 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919
2920 curwin->w_set_curswant = set_curswant;
2921 rettv->vval.v_number = 0;
2922}
2923
Bram Moolenaar4f974752019-02-17 17:44:42 +01002924#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002925/*
2926 * "debugbreak()" function
2927 */
2928 static void
2929f_debugbreak(typval_T *argvars, typval_T *rettv)
2930{
2931 int pid;
2932
2933 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002934 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002935 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002936 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002937 else
2938 {
2939 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2940
2941 if (hProcess != NULL)
2942 {
2943 DebugBreakProcess(hProcess);
2944 CloseHandle(hProcess);
2945 rettv->vval.v_number = OK;
2946 }
2947 }
2948}
2949#endif
2950
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002951/*
2952 * "deepcopy()" function
2953 */
2954 static void
2955f_deepcopy(typval_T *argvars, typval_T *rettv)
2956{
2957 int noref = 0;
2958 int copyID;
2959
2960 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002961 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002962 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002963 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002964 else
2965 {
2966 copyID = get_copyID();
2967 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2968 }
2969}
2970
2971/*
2972 * "delete()" function
2973 */
2974 static void
2975f_delete(typval_T *argvars, typval_T *rettv)
2976{
2977 char_u nbuf[NUMBUFLEN];
2978 char_u *name;
2979 char_u *flags;
2980
2981 rettv->vval.v_number = -1;
2982 if (check_restricted() || check_secure())
2983 return;
2984
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002985 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002986 if (name == NULL || *name == NUL)
2987 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002988 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 return;
2990 }
2991
2992 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002993 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002994 else
2995 flags = (char_u *)"";
2996
2997 if (*flags == NUL)
2998 /* delete a file */
2999 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
3000 else if (STRCMP(flags, "d") == 0)
3001 /* delete an empty directory */
3002 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
3003 else if (STRCMP(flags, "rf") == 0)
3004 /* delete a directory recursively */
3005 rettv->vval.v_number = delete_recursive(name);
3006 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003007 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003008}
3009
3010/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02003011 * "deletebufline()" function
3012 */
3013 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02003014f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02003015{
3016 buf_T *buf;
3017 linenr_T first, last;
3018 linenr_T lnum;
3019 long count;
3020 int is_curbuf;
3021 buf_T *curbuf_save = NULL;
3022 win_T *curwin_save = NULL;
3023 tabpage_T *tp;
3024 win_T *wp;
3025
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003026 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003027 if (buf == NULL)
3028 {
3029 rettv->vval.v_number = 1; /* FAIL */
3030 return;
3031 }
3032 is_curbuf = buf == curbuf;
3033
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003034 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003035 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003036 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003037 else
3038 last = first;
3039
3040 if (buf->b_ml.ml_mfp == NULL || first < 1
3041 || first > buf->b_ml.ml_line_count || last < first)
3042 {
3043 rettv->vval.v_number = 1; /* FAIL */
3044 return;
3045 }
3046
3047 if (!is_curbuf)
3048 {
3049 curbuf_save = curbuf;
3050 curwin_save = curwin;
3051 curbuf = buf;
3052 find_win_for_curbuf();
3053 }
3054 if (last > curbuf->b_ml.ml_line_count)
3055 last = curbuf->b_ml.ml_line_count;
3056 count = last - first + 1;
3057
3058 // When coming here from Insert mode, sync undo, so that this can be
3059 // undone separately from what was previously inserted.
3060 if (u_sync_once == 2)
3061 {
3062 u_sync_once = 1; // notify that u_sync() was called
3063 u_sync(TRUE);
3064 }
3065
3066 if (u_save(first - 1, last + 1) == FAIL)
3067 {
3068 rettv->vval.v_number = 1; /* FAIL */
3069 return;
3070 }
3071
3072 for (lnum = first; lnum <= last; ++lnum)
3073 ml_delete(first, TRUE);
3074
3075 FOR_ALL_TAB_WINDOWS(tp, wp)
3076 if (wp->w_buffer == buf)
3077 {
3078 if (wp->w_cursor.lnum > last)
3079 wp->w_cursor.lnum -= count;
3080 else if (wp->w_cursor.lnum> first)
3081 wp->w_cursor.lnum = first;
3082 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3083 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3084 }
3085 check_cursor_col();
3086 deleted_lines_mark(first, count);
3087
3088 if (!is_curbuf)
3089 {
3090 curbuf = curbuf_save;
3091 curwin = curwin_save;
3092 }
3093}
3094
3095/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 * "did_filetype()" function
3097 */
3098 static void
3099f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3100{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102}
3103
3104/*
3105 * "diff_filler()" function
3106 */
3107 static void
3108f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3109{
3110#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003111 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003112#endif
3113}
3114
3115/*
3116 * "diff_hlID()" function
3117 */
3118 static void
3119f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3120{
3121#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003122 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003123 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003124 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003125 static int fnum = 0;
3126 static int change_start = 0;
3127 static int change_end = 0;
3128 static hlf_T hlID = (hlf_T)0;
3129 int filler_lines;
3130 int col;
3131
3132 if (lnum < 0) /* ignore type error in {lnum} arg */
3133 lnum = 0;
3134 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003135 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003136 || fnum != curbuf->b_fnum)
3137 {
3138 /* New line, buffer, change: need to get the values. */
3139 filler_lines = diff_check(curwin, lnum);
3140 if (filler_lines < 0)
3141 {
3142 if (filler_lines == -1)
3143 {
3144 change_start = MAXCOL;
3145 change_end = -1;
3146 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3147 hlID = HLF_ADD; /* added line */
3148 else
3149 hlID = HLF_CHD; /* changed line */
3150 }
3151 else
3152 hlID = HLF_ADD; /* added line */
3153 }
3154 else
3155 hlID = (hlf_T)0;
3156 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003157 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 fnum = curbuf->b_fnum;
3159 }
3160
3161 if (hlID == HLF_CHD || hlID == HLF_TXD)
3162 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003163 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003164 if (col >= change_start && col <= change_end)
3165 hlID = HLF_TXD; /* changed text */
3166 else
3167 hlID = HLF_CHD; /* changed line */
3168 }
3169 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3170#endif
3171}
3172
3173/*
3174 * "empty({expr})" function
3175 */
3176 static void
3177f_empty(typval_T *argvars, typval_T *rettv)
3178{
3179 int n = FALSE;
3180
3181 switch (argvars[0].v_type)
3182 {
3183 case VAR_STRING:
3184 case VAR_FUNC:
3185 n = argvars[0].vval.v_string == NULL
3186 || *argvars[0].vval.v_string == NUL;
3187 break;
3188 case VAR_PARTIAL:
3189 n = FALSE;
3190 break;
3191 case VAR_NUMBER:
3192 n = argvars[0].vval.v_number == 0;
3193 break;
3194 case VAR_FLOAT:
3195#ifdef FEAT_FLOAT
3196 n = argvars[0].vval.v_float == 0.0;
3197 break;
3198#endif
3199 case VAR_LIST:
3200 n = argvars[0].vval.v_list == NULL
3201 || argvars[0].vval.v_list->lv_first == NULL;
3202 break;
3203 case VAR_DICT:
3204 n = argvars[0].vval.v_dict == NULL
3205 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3206 break;
3207 case VAR_SPECIAL:
3208 n = argvars[0].vval.v_number != VVAL_TRUE;
3209 break;
3210
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003211 case VAR_BLOB:
3212 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003213 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3214 break;
3215
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216 case VAR_JOB:
3217#ifdef FEAT_JOB_CHANNEL
3218 n = argvars[0].vval.v_job == NULL
3219 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3220 break;
3221#endif
3222 case VAR_CHANNEL:
3223#ifdef FEAT_JOB_CHANNEL
3224 n = argvars[0].vval.v_channel == NULL
3225 || !channel_is_open(argvars[0].vval.v_channel);
3226 break;
3227#endif
3228 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003229 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 n = TRUE;
3231 break;
3232 }
3233
3234 rettv->vval.v_number = n;
3235}
3236
3237/*
3238 * "escape({string}, {chars})" function
3239 */
3240 static void
3241f_escape(typval_T *argvars, typval_T *rettv)
3242{
3243 char_u buf[NUMBUFLEN];
3244
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003245 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3246 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247 rettv->v_type = VAR_STRING;
3248}
3249
3250/*
3251 * "eval()" function
3252 */
3253 static void
3254f_eval(typval_T *argvars, typval_T *rettv)
3255{
3256 char_u *s, *p;
3257
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003258 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003259 if (s != NULL)
3260 s = skipwhite(s);
3261
3262 p = s;
3263 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3264 {
3265 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003266 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267 need_clr_eos = FALSE;
3268 rettv->v_type = VAR_NUMBER;
3269 rettv->vval.v_number = 0;
3270 }
3271 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003272 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273}
3274
3275/*
3276 * "eventhandler()" function
3277 */
3278 static void
3279f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3280{
3281 rettv->vval.v_number = vgetc_busy;
3282}
3283
3284/*
3285 * "executable()" function
3286 */
3287 static void
3288f_executable(typval_T *argvars, typval_T *rettv)
3289{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003290 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003291
3292 /* Check in $PATH and also check directly if there is a directory name. */
3293 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3294 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3295}
3296
3297static garray_T redir_execute_ga;
3298
3299/*
3300 * Append "value[value_len]" to the execute() output.
3301 */
3302 void
3303execute_redir_str(char_u *value, int value_len)
3304{
3305 int len;
3306
3307 if (value_len == -1)
3308 len = (int)STRLEN(value); /* Append the entire string */
3309 else
3310 len = value_len; /* Append only "value_len" characters */
3311 if (ga_grow(&redir_execute_ga, len) == OK)
3312 {
3313 mch_memmove((char *)redir_execute_ga.ga_data
3314 + redir_execute_ga.ga_len, value, len);
3315 redir_execute_ga.ga_len += len;
3316 }
3317}
3318
3319/*
3320 * Get next line from a list.
3321 * Called by do_cmdline() to get the next line.
3322 * Returns allocated string, or NULL for end of function.
3323 */
3324
3325 static char_u *
3326get_list_line(
3327 int c UNUSED,
3328 void *cookie,
3329 int indent UNUSED)
3330{
3331 listitem_T **p = (listitem_T **)cookie;
3332 listitem_T *item = *p;
3333 char_u buf[NUMBUFLEN];
3334 char_u *s;
3335
3336 if (item == NULL)
3337 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003338 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003339 *p = item->li_next;
3340 return s == NULL ? NULL : vim_strsave(s);
3341}
3342
3343/*
3344 * "execute()" function
3345 */
3346 static void
3347f_execute(typval_T *argvars, typval_T *rettv)
3348{
3349 char_u *cmd = NULL;
3350 list_T *list = NULL;
3351 int save_msg_silent = msg_silent;
3352 int save_emsg_silent = emsg_silent;
3353 int save_emsg_noredir = emsg_noredir;
3354 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003355 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003357 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003358 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003359
3360 rettv->vval.v_string = NULL;
3361 rettv->v_type = VAR_STRING;
3362
3363 if (argvars[0].v_type == VAR_LIST)
3364 {
3365 list = argvars[0].vval.v_list;
3366 if (list == NULL || list->lv_first == NULL)
3367 /* empty list, no commands, empty output */
3368 return;
3369 ++list->lv_refcount;
3370 }
3371 else
3372 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003373 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003374 if (cmd == NULL)
3375 return;
3376 }
3377
3378 if (argvars[1].v_type != VAR_UNKNOWN)
3379 {
3380 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003381 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003382
3383 if (s == NULL)
3384 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003385 if (*s == NUL)
3386 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003387 if (STRNCMP(s, "silent", 6) == 0)
3388 ++msg_silent;
3389 if (STRCMP(s, "silent!") == 0)
3390 {
3391 emsg_silent = TRUE;
3392 emsg_noredir = TRUE;
3393 }
3394 }
3395 else
3396 ++msg_silent;
3397
3398 if (redir_execute)
3399 save_ga = redir_execute_ga;
3400 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3401 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003402 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003403 if (!echo_output)
3404 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003405
3406 if (cmd != NULL)
3407 do_cmdline_cmd(cmd);
3408 else
3409 {
3410 listitem_T *item = list->lv_first;
3411
3412 do_cmdline(NULL, get_list_line, (void *)&item,
3413 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3414 --list->lv_refcount;
3415 }
3416
Bram Moolenaard297f352017-01-29 20:31:21 +01003417 /* Need to append a NUL to the result. */
3418 if (ga_grow(&redir_execute_ga, 1) == OK)
3419 {
3420 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3421 rettv->vval.v_string = redir_execute_ga.ga_data;
3422 }
3423 else
3424 {
3425 ga_clear(&redir_execute_ga);
3426 rettv->vval.v_string = NULL;
3427 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 msg_silent = save_msg_silent;
3429 emsg_silent = save_emsg_silent;
3430 emsg_noredir = save_emsg_noredir;
3431
3432 redir_execute = save_redir_execute;
3433 if (redir_execute)
3434 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003435 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003437 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003438 if (echo_output)
3439 // When not working silently: put it in column zero. A following
3440 // "echon" will overwrite the message, unavoidably.
3441 msg_col = 0;
3442 else
3443 // When working silently: Put it back where it was, since nothing
3444 // should have been written.
3445 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003446}
3447
3448/*
3449 * "exepath()" function
3450 */
3451 static void
3452f_exepath(typval_T *argvars, typval_T *rettv)
3453{
3454 char_u *p = NULL;
3455
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003456 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457 rettv->v_type = VAR_STRING;
3458 rettv->vval.v_string = p;
3459}
3460
3461/*
3462 * "exists()" function
3463 */
3464 static void
3465f_exists(typval_T *argvars, typval_T *rettv)
3466{
3467 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003470 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471 if (*p == '$') /* environment variable */
3472 {
3473 /* first try "normal" environment variables (fast) */
3474 if (mch_getenv(p + 1) != NULL)
3475 n = TRUE;
3476 else
3477 {
3478 /* try expanding things like $VIM and ${HOME} */
3479 p = expand_env_save(p);
3480 if (p != NULL && *p != '$')
3481 n = TRUE;
3482 vim_free(p);
3483 }
3484 }
3485 else if (*p == '&' || *p == '+') /* option */
3486 {
3487 n = (get_option_tv(&p, NULL, TRUE) == OK);
3488 if (*skipwhite(p) != NUL)
3489 n = FALSE; /* trailing garbage */
3490 }
3491 else if (*p == '*') /* internal or user defined function */
3492 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003493 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494 }
3495 else if (*p == ':')
3496 {
3497 n = cmd_exists(p + 1);
3498 }
3499 else if (*p == '#')
3500 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003501 if (p[1] == '#')
3502 n = autocmd_supported(p + 2);
3503 else
3504 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 }
3506 else /* internal variable */
3507 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003508 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509 }
3510
3511 rettv->vval.v_number = n;
3512}
3513
3514#ifdef FEAT_FLOAT
3515/*
3516 * "exp()" function
3517 */
3518 static void
3519f_exp(typval_T *argvars, typval_T *rettv)
3520{
3521 float_T f = 0.0;
3522
3523 rettv->v_type = VAR_FLOAT;
3524 if (get_float_arg(argvars, &f) == OK)
3525 rettv->vval.v_float = exp(f);
3526 else
3527 rettv->vval.v_float = 0.0;
3528}
3529#endif
3530
3531/*
3532 * "expand()" function
3533 */
3534 static void
3535f_expand(typval_T *argvars, typval_T *rettv)
3536{
3537 char_u *s;
3538 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003539 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003540 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3541 expand_T xpc;
3542 int error = FALSE;
3543 char_u *result;
3544
3545 rettv->v_type = VAR_STRING;
3546 if (argvars[1].v_type != VAR_UNKNOWN
3547 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003548 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003549 && !error)
3550 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003551 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003552 }
3553
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003554 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003555 if (*s == '%' || *s == '#' || *s == '<')
3556 {
3557 ++emsg_off;
3558 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3559 --emsg_off;
3560 if (rettv->v_type == VAR_LIST)
3561 {
3562 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3563 list_append_string(rettv->vval.v_list, result, -1);
3564 else
3565 vim_free(result);
3566 }
3567 else
3568 rettv->vval.v_string = result;
3569 }
3570 else
3571 {
3572 /* When the optional second argument is non-zero, don't remove matches
3573 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3574 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003575 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576 options |= WILD_KEEP_ALL;
3577 if (!error)
3578 {
3579 ExpandInit(&xpc);
3580 xpc.xp_context = EXPAND_FILES;
3581 if (p_wic)
3582 options += WILD_ICASE;
3583 if (rettv->v_type == VAR_STRING)
3584 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3585 options, WILD_ALL);
3586 else if (rettv_list_alloc(rettv) != FAIL)
3587 {
3588 int i;
3589
3590 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3591 for (i = 0; i < xpc.xp_numfiles; i++)
3592 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3593 ExpandCleanup(&xpc);
3594 }
3595 }
3596 else
3597 rettv->vval.v_string = NULL;
3598 }
3599}
3600
3601/*
3602 * "extend(list, list [, idx])" function
3603 * "extend(dict, dict [, action])" function
3604 */
3605 static void
3606f_extend(typval_T *argvars, typval_T *rettv)
3607{
3608 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3609
3610 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3611 {
3612 list_T *l1, *l2;
3613 listitem_T *item;
3614 long before;
3615 int error = FALSE;
3616
3617 l1 = argvars[0].vval.v_list;
3618 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003619 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003620 && l2 != NULL)
3621 {
3622 if (argvars[2].v_type != VAR_UNKNOWN)
3623 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003624 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003625 if (error)
3626 return; /* type error; errmsg already given */
3627
3628 if (before == l1->lv_len)
3629 item = NULL;
3630 else
3631 {
3632 item = list_find(l1, before);
3633 if (item == NULL)
3634 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003635 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636 return;
3637 }
3638 }
3639 }
3640 else
3641 item = NULL;
3642 list_extend(l1, l2, item);
3643
3644 copy_tv(&argvars[0], rettv);
3645 }
3646 }
3647 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3648 {
3649 dict_T *d1, *d2;
3650 char_u *action;
3651 int i;
3652
3653 d1 = argvars[0].vval.v_dict;
3654 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003655 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656 && d2 != NULL)
3657 {
3658 /* Check the third argument. */
3659 if (argvars[2].v_type != VAR_UNKNOWN)
3660 {
3661 static char *(av[]) = {"keep", "force", "error"};
3662
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003663 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003664 if (action == NULL)
3665 return; /* type error; errmsg already given */
3666 for (i = 0; i < 3; ++i)
3667 if (STRCMP(action, av[i]) == 0)
3668 break;
3669 if (i == 3)
3670 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003671 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003672 return;
3673 }
3674 }
3675 else
3676 action = (char_u *)"force";
3677
3678 dict_extend(d1, d2, action);
3679
3680 copy_tv(&argvars[0], rettv);
3681 }
3682 }
3683 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003684 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685}
3686
3687/*
3688 * "feedkeys()" function
3689 */
3690 static void
3691f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3692{
3693 int remap = TRUE;
3694 int insert = FALSE;
3695 char_u *keys, *flags;
3696 char_u nbuf[NUMBUFLEN];
3697 int typed = FALSE;
3698 int execute = FALSE;
3699 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003700 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003701 char_u *keys_esc;
3702
3703 /* This is not allowed in the sandbox. If the commands would still be
3704 * executed in the sandbox it would be OK, but it probably happens later,
3705 * when "sandbox" is no longer set. */
3706 if (check_secure())
3707 return;
3708
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003709 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003710
3711 if (argvars[1].v_type != VAR_UNKNOWN)
3712 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003713 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 for ( ; *flags != NUL; ++flags)
3715 {
3716 switch (*flags)
3717 {
3718 case 'n': remap = FALSE; break;
3719 case 'm': remap = TRUE; break;
3720 case 't': typed = TRUE; break;
3721 case 'i': insert = TRUE; break;
3722 case 'x': execute = TRUE; break;
3723 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003724 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725 }
3726 }
3727 }
3728
3729 if (*keys != NUL || execute)
3730 {
3731 /* Need to escape K_SPECIAL and CSI before putting the string in the
3732 * typeahead buffer. */
3733 keys_esc = vim_strsave_escape_csi(keys);
3734 if (keys_esc != NULL)
3735 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003736 if (lowlevel)
3737 {
3738#ifdef USE_INPUT_BUF
3739 add_to_input_buf(keys, (int)STRLEN(keys));
3740#else
3741 emsg(_("E980: lowlevel input not supported"));
3742#endif
3743 }
3744 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003745 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003746 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003748 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003749#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003750 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003751#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003752 )
3753 typebuf_was_filled = TRUE;
3754 }
3755 vim_free(keys_esc);
3756
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003757 if (execute)
3758 {
3759 int save_msg_scroll = msg_scroll;
3760
3761 /* Avoid a 1 second delay when the keys start Insert mode. */
3762 msg_scroll = FALSE;
3763
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003764 if (!dangerous)
3765 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003766 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003767 if (!dangerous)
3768 --ex_normal_busy;
3769
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770 msg_scroll |= save_msg_scroll;
3771 }
3772 }
3773 }
3774}
3775
3776/*
3777 * "filereadable()" function
3778 */
3779 static void
3780f_filereadable(typval_T *argvars, typval_T *rettv)
3781{
3782 int fd;
3783 char_u *p;
3784 int n;
3785
3786#ifndef O_NONBLOCK
3787# define O_NONBLOCK 0
3788#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003789 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003790 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3791 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3792 {
3793 n = TRUE;
3794 close(fd);
3795 }
3796 else
3797 n = FALSE;
3798
3799 rettv->vval.v_number = n;
3800}
3801
3802/*
3803 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3804 * rights to write into.
3805 */
3806 static void
3807f_filewritable(typval_T *argvars, typval_T *rettv)
3808{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003809 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810}
3811
3812 static void
3813findfilendir(
3814 typval_T *argvars UNUSED,
3815 typval_T *rettv,
3816 int find_what UNUSED)
3817{
3818#ifdef FEAT_SEARCHPATH
3819 char_u *fname;
3820 char_u *fresult = NULL;
3821 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3822 char_u *p;
3823 char_u pathbuf[NUMBUFLEN];
3824 int count = 1;
3825 int first = TRUE;
3826 int error = FALSE;
3827#endif
3828
3829 rettv->vval.v_string = NULL;
3830 rettv->v_type = VAR_STRING;
3831
3832#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003833 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834
3835 if (argvars[1].v_type != VAR_UNKNOWN)
3836 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003837 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003838 if (p == NULL)
3839 error = TRUE;
3840 else
3841 {
3842 if (*p != NUL)
3843 path = p;
3844
3845 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003846 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847 }
3848 }
3849
3850 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3851 error = TRUE;
3852
3853 if (*fname != NUL && !error)
3854 {
3855 do
3856 {
3857 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3858 vim_free(fresult);
3859 fresult = find_file_in_path_option(first ? fname : NULL,
3860 first ? (int)STRLEN(fname) : 0,
3861 0, first, path,
3862 find_what,
3863 curbuf->b_ffname,
3864 find_what == FINDFILE_DIR
3865 ? (char_u *)"" : curbuf->b_p_sua);
3866 first = FALSE;
3867
3868 if (fresult != NULL && rettv->v_type == VAR_LIST)
3869 list_append_string(rettv->vval.v_list, fresult, -1);
3870
3871 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3872 }
3873
3874 if (rettv->v_type == VAR_STRING)
3875 rettv->vval.v_string = fresult;
3876#endif
3877}
3878
3879/*
3880 * "filter()" function
3881 */
3882 static void
3883f_filter(typval_T *argvars, typval_T *rettv)
3884{
3885 filter_map(argvars, rettv, FALSE);
3886}
3887
3888/*
3889 * "finddir({fname}[, {path}[, {count}]])" function
3890 */
3891 static void
3892f_finddir(typval_T *argvars, typval_T *rettv)
3893{
3894 findfilendir(argvars, rettv, FINDFILE_DIR);
3895}
3896
3897/*
3898 * "findfile({fname}[, {path}[, {count}]])" function
3899 */
3900 static void
3901f_findfile(typval_T *argvars, typval_T *rettv)
3902{
3903 findfilendir(argvars, rettv, FINDFILE_FILE);
3904}
3905
3906#ifdef FEAT_FLOAT
3907/*
3908 * "float2nr({float})" function
3909 */
3910 static void
3911f_float2nr(typval_T *argvars, typval_T *rettv)
3912{
3913 float_T f = 0.0;
3914
3915 if (get_float_arg(argvars, &f) == OK)
3916 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003917 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003918 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003919 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003920 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 else
3922 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 }
3924}
3925
3926/*
3927 * "floor({float})" function
3928 */
3929 static void
3930f_floor(typval_T *argvars, typval_T *rettv)
3931{
3932 float_T f = 0.0;
3933
3934 rettv->v_type = VAR_FLOAT;
3935 if (get_float_arg(argvars, &f) == OK)
3936 rettv->vval.v_float = floor(f);
3937 else
3938 rettv->vval.v_float = 0.0;
3939}
3940
3941/*
3942 * "fmod()" function
3943 */
3944 static void
3945f_fmod(typval_T *argvars, typval_T *rettv)
3946{
3947 float_T fx = 0.0, fy = 0.0;
3948
3949 rettv->v_type = VAR_FLOAT;
3950 if (get_float_arg(argvars, &fx) == OK
3951 && get_float_arg(&argvars[1], &fy) == OK)
3952 rettv->vval.v_float = fmod(fx, fy);
3953 else
3954 rettv->vval.v_float = 0.0;
3955}
3956#endif
3957
3958/*
3959 * "fnameescape({string})" function
3960 */
3961 static void
3962f_fnameescape(typval_T *argvars, typval_T *rettv)
3963{
3964 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003965 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003966 rettv->v_type = VAR_STRING;
3967}
3968
3969/*
3970 * "fnamemodify({fname}, {mods})" function
3971 */
3972 static void
3973f_fnamemodify(typval_T *argvars, typval_T *rettv)
3974{
3975 char_u *fname;
3976 char_u *mods;
3977 int usedlen = 0;
3978 int len;
3979 char_u *fbuf = NULL;
3980 char_u buf[NUMBUFLEN];
3981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003982 fname = tv_get_string_chk(&argvars[0]);
3983 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 if (fname == NULL || mods == NULL)
3985 fname = NULL;
3986 else
3987 {
3988 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003989 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003990 }
3991
3992 rettv->v_type = VAR_STRING;
3993 if (fname == NULL)
3994 rettv->vval.v_string = NULL;
3995 else
3996 rettv->vval.v_string = vim_strnsave(fname, len);
3997 vim_free(fbuf);
3998}
3999
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000/*
4001 * "foldclosed()" function
4002 */
4003 static void
4004foldclosed_both(
4005 typval_T *argvars UNUSED,
4006 typval_T *rettv,
4007 int end UNUSED)
4008{
4009#ifdef FEAT_FOLDING
4010 linenr_T lnum;
4011 linenr_T first, last;
4012
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004013 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4015 {
4016 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4017 {
4018 if (end)
4019 rettv->vval.v_number = (varnumber_T)last;
4020 else
4021 rettv->vval.v_number = (varnumber_T)first;
4022 return;
4023 }
4024 }
4025#endif
4026 rettv->vval.v_number = -1;
4027}
4028
4029/*
4030 * "foldclosed()" function
4031 */
4032 static void
4033f_foldclosed(typval_T *argvars, typval_T *rettv)
4034{
4035 foldclosed_both(argvars, rettv, FALSE);
4036}
4037
4038/*
4039 * "foldclosedend()" function
4040 */
4041 static void
4042f_foldclosedend(typval_T *argvars, typval_T *rettv)
4043{
4044 foldclosed_both(argvars, rettv, TRUE);
4045}
4046
4047/*
4048 * "foldlevel()" function
4049 */
4050 static void
4051f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4052{
4053#ifdef FEAT_FOLDING
4054 linenr_T lnum;
4055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004056 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4058 rettv->vval.v_number = foldLevel(lnum);
4059#endif
4060}
4061
4062/*
4063 * "foldtext()" function
4064 */
4065 static void
4066f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4067{
4068#ifdef FEAT_FOLDING
4069 linenr_T foldstart;
4070 linenr_T foldend;
4071 char_u *dashes;
4072 linenr_T lnum;
4073 char_u *s;
4074 char_u *r;
4075 int len;
4076 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004077 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078#endif
4079
4080 rettv->v_type = VAR_STRING;
4081 rettv->vval.v_string = NULL;
4082#ifdef FEAT_FOLDING
4083 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4084 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4085 dashes = get_vim_var_str(VV_FOLDDASHES);
4086 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4087 && dashes != NULL)
4088 {
4089 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004090 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 if (!linewhite(lnum))
4092 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093
4094 /* Find interesting text in this line. */
4095 s = skipwhite(ml_get(lnum));
4096 /* skip C comment-start */
4097 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4098 {
4099 s = skipwhite(s + 2);
4100 if (*skipwhite(s) == NUL
4101 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4102 {
4103 s = skipwhite(ml_get(lnum + 1));
4104 if (*s == '*')
4105 s = skipwhite(s + 1);
4106 }
4107 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004108 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004109 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004110 r = alloc((unsigned)(STRLEN(txt)
4111 + STRLEN(dashes) /* for %s */
4112 + 20 /* for %3ld */
4113 + STRLEN(s))); /* concatenated */
4114 if (r != NULL)
4115 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004116 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004117 len = (int)STRLEN(r);
4118 STRCAT(r, s);
4119 /* remove 'foldmarker' and 'commentstring' */
4120 foldtext_cleanup(r + len);
4121 rettv->vval.v_string = r;
4122 }
4123 }
4124#endif
4125}
4126
4127/*
4128 * "foldtextresult(lnum)" function
4129 */
4130 static void
4131f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4132{
4133#ifdef FEAT_FOLDING
4134 linenr_T lnum;
4135 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004136 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004137 foldinfo_T foldinfo;
4138 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004139 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004140#endif
4141
4142 rettv->v_type = VAR_STRING;
4143 rettv->vval.v_string = NULL;
4144#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004145 if (entered)
4146 return; /* reject recursive use */
4147 entered = TRUE;
4148
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004149 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150 /* treat illegal types and illegal string values for {lnum} the same */
4151 if (lnum < 0)
4152 lnum = 0;
4153 fold_count = foldedCount(curwin, lnum, &foldinfo);
4154 if (fold_count > 0)
4155 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004156 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4157 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 if (text == buf)
4159 text = vim_strsave(text);
4160 rettv->vval.v_string = text;
4161 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004162
4163 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004164#endif
4165}
4166
4167/*
4168 * "foreground()" function
4169 */
4170 static void
4171f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4172{
4173#ifdef FEAT_GUI
4174 if (gui.in_use)
4175 gui_mch_set_foreground();
4176#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004177# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004178 win32_set_foreground();
4179# endif
4180#endif
4181}
4182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004183 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004184common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004185{
4186 char_u *s;
4187 char_u *name;
4188 int use_string = FALSE;
4189 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004190 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004191
4192 if (argvars[0].v_type == VAR_FUNC)
4193 {
4194 /* function(MyFunc, [arg], dict) */
4195 s = argvars[0].vval.v_string;
4196 }
4197 else if (argvars[0].v_type == VAR_PARTIAL
4198 && argvars[0].vval.v_partial != NULL)
4199 {
4200 /* function(dict.MyFunc, [arg]) */
4201 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004202 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 }
4204 else
4205 {
4206 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004207 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004208 use_string = TRUE;
4209 }
4210
Bram Moolenaar843b8842016-08-21 14:36:15 +02004211 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004212 {
4213 name = s;
4214 trans_name = trans_function_name(&name, FALSE,
4215 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4216 if (*name != NUL)
4217 s = NULL;
4218 }
4219
Bram Moolenaar843b8842016-08-21 14:36:15 +02004220 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4221 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004222 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004223 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004224 else if (trans_name != NULL && (is_funcref
4225 ? find_func(trans_name) == NULL
4226 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004227 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004228 else
4229 {
4230 int dict_idx = 0;
4231 int arg_idx = 0;
4232 list_T *list = NULL;
4233
4234 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4235 {
4236 char sid_buf[25];
4237 int off = *s == 's' ? 2 : 5;
4238
4239 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4240 * also be called from another script. Using trans_function_name()
4241 * would also work, but some plugins depend on the name being
4242 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004243 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004244 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4245 if (name != NULL)
4246 {
4247 STRCPY(name, sid_buf);
4248 STRCAT(name, s + off);
4249 }
4250 }
4251 else
4252 name = vim_strsave(s);
4253
4254 if (argvars[1].v_type != VAR_UNKNOWN)
4255 {
4256 if (argvars[2].v_type != VAR_UNKNOWN)
4257 {
4258 /* function(name, [args], dict) */
4259 arg_idx = 1;
4260 dict_idx = 2;
4261 }
4262 else if (argvars[1].v_type == VAR_DICT)
4263 /* function(name, dict) */
4264 dict_idx = 1;
4265 else
4266 /* function(name, [args]) */
4267 arg_idx = 1;
4268 if (dict_idx > 0)
4269 {
4270 if (argvars[dict_idx].v_type != VAR_DICT)
4271 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004272 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004273 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004274 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 }
4276 if (argvars[dict_idx].vval.v_dict == NULL)
4277 dict_idx = 0;
4278 }
4279 if (arg_idx > 0)
4280 {
4281 if (argvars[arg_idx].v_type != VAR_LIST)
4282 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004283 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004284 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004285 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 }
4287 list = argvars[arg_idx].vval.v_list;
4288 if (list == NULL || list->lv_len == 0)
4289 arg_idx = 0;
4290 }
4291 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004292 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293 {
4294 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4295
4296 /* result is a VAR_PARTIAL */
4297 if (pt == NULL)
4298 vim_free(name);
4299 else
4300 {
4301 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4302 {
4303 listitem_T *li;
4304 int i = 0;
4305 int arg_len = 0;
4306 int lv_len = 0;
4307
4308 if (arg_pt != NULL)
4309 arg_len = arg_pt->pt_argc;
4310 if (list != NULL)
4311 lv_len = list->lv_len;
4312 pt->pt_argc = arg_len + lv_len;
4313 pt->pt_argv = (typval_T *)alloc(
4314 sizeof(typval_T) * pt->pt_argc);
4315 if (pt->pt_argv == NULL)
4316 {
4317 vim_free(pt);
4318 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004319 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004320 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004321 for (i = 0; i < arg_len; i++)
4322 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4323 if (lv_len > 0)
4324 for (li = list->lv_first; li != NULL;
4325 li = li->li_next)
4326 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004327 }
4328
4329 /* For "function(dict.func, [], dict)" and "func" is a partial
4330 * use "dict". That is backwards compatible. */
4331 if (dict_idx > 0)
4332 {
4333 /* The dict is bound explicitly, pt_auto is FALSE. */
4334 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4335 ++pt->pt_dict->dv_refcount;
4336 }
4337 else if (arg_pt != NULL)
4338 {
4339 /* If the dict was bound automatically the result is also
4340 * bound automatically. */
4341 pt->pt_dict = arg_pt->pt_dict;
4342 pt->pt_auto = arg_pt->pt_auto;
4343 if (pt->pt_dict != NULL)
4344 ++pt->pt_dict->dv_refcount;
4345 }
4346
4347 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004348 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4349 {
4350 pt->pt_func = arg_pt->pt_func;
4351 func_ptr_ref(pt->pt_func);
4352 vim_free(name);
4353 }
4354 else if (is_funcref)
4355 {
4356 pt->pt_func = find_func(trans_name);
4357 func_ptr_ref(pt->pt_func);
4358 vim_free(name);
4359 }
4360 else
4361 {
4362 pt->pt_name = name;
4363 func_ref(name);
4364 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004365 }
4366 rettv->v_type = VAR_PARTIAL;
4367 rettv->vval.v_partial = pt;
4368 }
4369 else
4370 {
4371 /* result is a VAR_FUNC */
4372 rettv->v_type = VAR_FUNC;
4373 rettv->vval.v_string = name;
4374 func_ref(name);
4375 }
4376 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004377theend:
4378 vim_free(trans_name);
4379}
4380
4381/*
4382 * "funcref()" function
4383 */
4384 static void
4385f_funcref(typval_T *argvars, typval_T *rettv)
4386{
4387 common_function(argvars, rettv, TRUE);
4388}
4389
4390/*
4391 * "function()" function
4392 */
4393 static void
4394f_function(typval_T *argvars, typval_T *rettv)
4395{
4396 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397}
4398
4399/*
4400 * "garbagecollect()" function
4401 */
4402 static void
4403f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4404{
4405 /* This is postponed until we are back at the toplevel, because we may be
4406 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4407 want_garbage_collect = TRUE;
4408
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004409 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004410 garbage_collect_at_exit = TRUE;
4411}
4412
4413/*
4414 * "get()" function
4415 */
4416 static void
4417f_get(typval_T *argvars, typval_T *rettv)
4418{
4419 listitem_T *li;
4420 list_T *l;
4421 dictitem_T *di;
4422 dict_T *d;
4423 typval_T *tv = NULL;
4424
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004425 if (argvars[0].v_type == VAR_BLOB)
4426 {
4427 int error = FALSE;
4428 int idx = tv_get_number_chk(&argvars[1], &error);
4429
4430 if (!error)
4431 {
4432 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004433 if (idx < 0)
4434 idx = blob_len(argvars[0].vval.v_blob) + idx;
4435 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4436 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004437 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004438 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004439 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004440 tv = rettv;
4441 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004442 }
4443 }
4444 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004445 {
4446 if ((l = argvars[0].vval.v_list) != NULL)
4447 {
4448 int error = FALSE;
4449
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004450 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004451 if (!error && li != NULL)
4452 tv = &li->li_tv;
4453 }
4454 }
4455 else if (argvars[0].v_type == VAR_DICT)
4456 {
4457 if ((d = argvars[0].vval.v_dict) != NULL)
4458 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004459 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004460 if (di != NULL)
4461 tv = &di->di_tv;
4462 }
4463 }
4464 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4465 {
4466 partial_T *pt;
4467 partial_T fref_pt;
4468
4469 if (argvars[0].v_type == VAR_PARTIAL)
4470 pt = argvars[0].vval.v_partial;
4471 else
4472 {
4473 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4474 fref_pt.pt_name = argvars[0].vval.v_string;
4475 pt = &fref_pt;
4476 }
4477
4478 if (pt != NULL)
4479 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004480 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004481 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004482
4483 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4484 {
4485 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004486 n = partial_name(pt);
4487 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004488 rettv->vval.v_string = NULL;
4489 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004490 {
4491 rettv->vval.v_string = vim_strsave(n);
4492 if (rettv->v_type == VAR_FUNC)
4493 func_ref(rettv->vval.v_string);
4494 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004495 }
4496 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004497 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004498 else if (STRCMP(what, "args") == 0)
4499 {
4500 rettv->v_type = VAR_LIST;
4501 if (rettv_list_alloc(rettv) == OK)
4502 {
4503 int i;
4504
4505 for (i = 0; i < pt->pt_argc; ++i)
4506 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4507 }
4508 }
4509 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004510 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004511 return;
4512 }
4513 }
4514 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004515 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004516
4517 if (tv == NULL)
4518 {
4519 if (argvars[2].v_type != VAR_UNKNOWN)
4520 copy_tv(&argvars[2], rettv);
4521 }
4522 else
4523 copy_tv(tv, rettv);
4524}
4525
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004526/*
4527 * Returns buffer options, variables and other attributes in a dictionary.
4528 */
4529 static dict_T *
4530get_buffer_info(buf_T *buf)
4531{
4532 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004533 tabpage_T *tp;
4534 win_T *wp;
4535 list_T *windows;
4536
4537 dict = dict_alloc();
4538 if (dict == NULL)
4539 return NULL;
4540
Bram Moolenaare0be1672018-07-08 16:50:37 +02004541 dict_add_number(dict, "bufnr", buf->b_fnum);
4542 dict_add_string(dict, "name", buf->b_ffname);
4543 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4544 : buflist_findlnum(buf));
4545 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4546 dict_add_number(dict, "listed", buf->b_p_bl);
4547 dict_add_number(dict, "changed", bufIsChanged(buf));
4548 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4549 dict_add_number(dict, "hidden",
4550 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004551
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004552 /* Get a reference to buffer variables */
4553 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004554
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004555 /* List of windows displaying this buffer */
4556 windows = list_alloc();
4557 if (windows != NULL)
4558 {
4559 FOR_ALL_TAB_WINDOWS(tp, wp)
4560 if (wp->w_buffer == buf)
4561 list_append_number(windows, (varnumber_T)wp->w_id);
4562 dict_add_list(dict, "windows", windows);
4563 }
4564
4565#ifdef FEAT_SIGNS
4566 if (buf->b_signlist != NULL)
4567 {
4568 /* List of signs placed in this buffer */
4569 list_T *signs = list_alloc();
4570 if (signs != NULL)
4571 {
4572 get_buffer_signs(buf, signs);
4573 dict_add_list(dict, "signs", signs);
4574 }
4575 }
4576#endif
4577
4578 return dict;
4579}
4580
4581/*
4582 * "getbufinfo()" function
4583 */
4584 static void
4585f_getbufinfo(typval_T *argvars, typval_T *rettv)
4586{
4587 buf_T *buf = NULL;
4588 buf_T *argbuf = NULL;
4589 dict_T *d;
4590 int filtered = FALSE;
4591 int sel_buflisted = FALSE;
4592 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004593 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004594
4595 if (rettv_list_alloc(rettv) != OK)
4596 return;
4597
4598 /* List of all the buffers or selected buffers */
4599 if (argvars[0].v_type == VAR_DICT)
4600 {
4601 dict_T *sel_d = argvars[0].vval.v_dict;
4602
4603 if (sel_d != NULL)
4604 {
4605 dictitem_T *di;
4606
4607 filtered = TRUE;
4608
4609 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004610 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004611 sel_buflisted = TRUE;
4612
4613 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004614 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004615 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004616
4617 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004618 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004619 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004620 }
4621 }
4622 else if (argvars[0].v_type != VAR_UNKNOWN)
4623 {
4624 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004625 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004626 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004627 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004628 --emsg_off;
4629 if (argbuf == NULL)
4630 return;
4631 }
4632
4633 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004634 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004635 {
4636 if (argbuf != NULL && argbuf != buf)
4637 continue;
4638 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004639 || (sel_buflisted && !buf->b_p_bl)
4640 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004641 continue;
4642
4643 d = get_buffer_info(buf);
4644 if (d != NULL)
4645 list_append_dict(rettv->vval.v_list, d);
4646 if (argbuf != NULL)
4647 return;
4648 }
4649}
4650
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004651/*
4652 * Get line or list of lines from buffer "buf" into "rettv".
4653 * Return a range (from start to end) of lines in rettv from the specified
4654 * buffer.
4655 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4656 */
4657 static void
4658get_buffer_lines(
4659 buf_T *buf,
4660 linenr_T start,
4661 linenr_T end,
4662 int retlist,
4663 typval_T *rettv)
4664{
4665 char_u *p;
4666
4667 rettv->v_type = VAR_STRING;
4668 rettv->vval.v_string = NULL;
4669 if (retlist && rettv_list_alloc(rettv) == FAIL)
4670 return;
4671
4672 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4673 return;
4674
4675 if (!retlist)
4676 {
4677 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4678 p = ml_get_buf(buf, start, FALSE);
4679 else
4680 p = (char_u *)"";
4681 rettv->vval.v_string = vim_strsave(p);
4682 }
4683 else
4684 {
4685 if (end < start)
4686 return;
4687
4688 if (start < 1)
4689 start = 1;
4690 if (end > buf->b_ml.ml_line_count)
4691 end = buf->b_ml.ml_line_count;
4692 while (start <= end)
4693 if (list_append_string(rettv->vval.v_list,
4694 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4695 break;
4696 }
4697}
4698
4699/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 * "getbufline()" function
4701 */
4702 static void
4703f_getbufline(typval_T *argvars, typval_T *rettv)
4704{
4705 linenr_T lnum;
4706 linenr_T end;
4707 buf_T *buf;
4708
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004709 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004711 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004712 --emsg_off;
4713
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004714 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004715 if (argvars[2].v_type == VAR_UNKNOWN)
4716 end = lnum;
4717 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004718 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719
4720 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4721}
4722
4723/*
4724 * "getbufvar()" function
4725 */
4726 static void
4727f_getbufvar(typval_T *argvars, typval_T *rettv)
4728{
4729 buf_T *buf;
4730 buf_T *save_curbuf;
4731 char_u *varname;
4732 dictitem_T *v;
4733 int done = FALSE;
4734
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004735 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4736 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004738 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004739
4740 rettv->v_type = VAR_STRING;
4741 rettv->vval.v_string = NULL;
4742
4743 if (buf != NULL && varname != NULL)
4744 {
4745 /* set curbuf to be our buf, temporarily */
4746 save_curbuf = curbuf;
4747 curbuf = buf;
4748
Bram Moolenaar30567352016-08-27 21:25:44 +02004749 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004750 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004751 if (varname[1] == NUL)
4752 {
4753 /* get all buffer-local options in a dict */
4754 dict_T *opts = get_winbuf_options(TRUE);
4755
4756 if (opts != NULL)
4757 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004758 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004759 done = TRUE;
4760 }
4761 }
4762 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4763 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004764 done = TRUE;
4765 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766 else
4767 {
4768 /* Look up the variable. */
4769 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4770 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4771 'b', varname, FALSE);
4772 if (v != NULL)
4773 {
4774 copy_tv(&v->di_tv, rettv);
4775 done = TRUE;
4776 }
4777 }
4778
4779 /* restore previous notion of curbuf */
4780 curbuf = save_curbuf;
4781 }
4782
4783 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4784 /* use the default value */
4785 copy_tv(&argvars[2], rettv);
4786
4787 --emsg_off;
4788}
4789
4790/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004791 * "getchangelist()" function
4792 */
4793 static void
4794f_getchangelist(typval_T *argvars, typval_T *rettv)
4795{
4796#ifdef FEAT_JUMPLIST
4797 buf_T *buf;
4798 int i;
4799 list_T *l;
4800 dict_T *d;
4801#endif
4802
4803 if (rettv_list_alloc(rettv) != OK)
4804 return;
4805
4806#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004807 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004808 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004809 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004810 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004811 if (buf == NULL)
4812 return;
4813
4814 l = list_alloc();
4815 if (l == NULL)
4816 return;
4817
4818 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4819 return;
4820 /*
4821 * The current window change list index tracks only the position in the
4822 * current buffer change list. For other buffers, use the change list
4823 * length as the current index.
4824 */
4825 list_append_number(rettv->vval.v_list,
4826 (varnumber_T)((buf == curwin->w_buffer)
4827 ? curwin->w_changelistidx : buf->b_changelistlen));
4828
4829 for (i = 0; i < buf->b_changelistlen; ++i)
4830 {
4831 if (buf->b_changelist[i].lnum == 0)
4832 continue;
4833 if ((d = dict_alloc()) == NULL)
4834 return;
4835 if (list_append_dict(l, d) == FAIL)
4836 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004837 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4838 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004839 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004840 }
4841#endif
4842}
4843/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844 * "getchar()" function
4845 */
4846 static void
4847f_getchar(typval_T *argvars, typval_T *rettv)
4848{
4849 varnumber_T n;
4850 int error = FALSE;
4851
Bram Moolenaar84d93902018-09-11 20:10:20 +02004852#ifdef MESSAGE_QUEUE
4853 // vpeekc() used to check for messages, but that caused problems, invoking
4854 // a callback where it was not expected. Some plugins use getchar(1) in a
4855 // loop to await a message, therefore make sure we check for messages here.
4856 parse_queued_messages();
4857#endif
4858
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 /* Position the cursor. Needed after a message that ends in a space. */
4860 windgoto(msg_row, msg_col);
4861
4862 ++no_mapping;
4863 ++allow_keys;
4864 for (;;)
4865 {
4866 if (argvars[0].v_type == VAR_UNKNOWN)
4867 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004868 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004869 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004870 /* getchar(1): only check if char avail */
4871 n = vpeekc_any();
4872 else if (error || vpeekc_any() == NUL)
4873 /* illegal argument or getchar(0) and no char avail: return zero */
4874 n = 0;
4875 else
4876 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004877 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878
4879 if (n == K_IGNORE)
4880 continue;
4881 break;
4882 }
4883 --no_mapping;
4884 --allow_keys;
4885
4886 set_vim_var_nr(VV_MOUSE_WIN, 0);
4887 set_vim_var_nr(VV_MOUSE_WINID, 0);
4888 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4889 set_vim_var_nr(VV_MOUSE_COL, 0);
4890
4891 rettv->vval.v_number = n;
4892 if (IS_SPECIAL(n) || mod_mask != 0)
4893 {
4894 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4895 int i = 0;
4896
4897 /* Turn a special key into three bytes, plus modifier. */
4898 if (mod_mask != 0)
4899 {
4900 temp[i++] = K_SPECIAL;
4901 temp[i++] = KS_MODIFIER;
4902 temp[i++] = mod_mask;
4903 }
4904 if (IS_SPECIAL(n))
4905 {
4906 temp[i++] = K_SPECIAL;
4907 temp[i++] = K_SECOND(n);
4908 temp[i++] = K_THIRD(n);
4909 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 else if (has_mbyte)
4911 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004912 else
4913 temp[i++] = n;
4914 temp[i++] = NUL;
4915 rettv->v_type = VAR_STRING;
4916 rettv->vval.v_string = vim_strsave(temp);
4917
4918#ifdef FEAT_MOUSE
4919 if (is_mouse_key(n))
4920 {
4921 int row = mouse_row;
4922 int col = mouse_col;
4923 win_T *win;
4924 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004925 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004926 int winnr = 1;
4927
4928 if (row >= 0 && col >= 0)
4929 {
4930 /* Find the window at the mouse coordinates and compute the
4931 * text position. */
4932 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004933 if (win == NULL)
4934 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936 for (wp = firstwin; wp != win; wp = wp->w_next)
4937 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004938 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4939 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4940 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4941 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4942 }
4943 }
4944#endif
4945 }
4946}
4947
4948/*
4949 * "getcharmod()" function
4950 */
4951 static void
4952f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4953{
4954 rettv->vval.v_number = mod_mask;
4955}
4956
4957/*
4958 * "getcharsearch()" function
4959 */
4960 static void
4961f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4962{
4963 if (rettv_dict_alloc(rettv) != FAIL)
4964 {
4965 dict_T *dict = rettv->vval.v_dict;
4966
Bram Moolenaare0be1672018-07-08 16:50:37 +02004967 dict_add_string(dict, "char", last_csearch());
4968 dict_add_number(dict, "forward", last_csearch_forward());
4969 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970 }
4971}
4972
4973/*
4974 * "getcmdline()" function
4975 */
4976 static void
4977f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4978{
4979 rettv->v_type = VAR_STRING;
4980 rettv->vval.v_string = get_cmdline_str();
4981}
4982
4983/*
4984 * "getcmdpos()" function
4985 */
4986 static void
4987f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4988{
4989 rettv->vval.v_number = get_cmdline_pos() + 1;
4990}
4991
4992/*
4993 * "getcmdtype()" function
4994 */
4995 static void
4996f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4997{
4998 rettv->v_type = VAR_STRING;
4999 rettv->vval.v_string = alloc(2);
5000 if (rettv->vval.v_string != NULL)
5001 {
5002 rettv->vval.v_string[0] = get_cmdline_type();
5003 rettv->vval.v_string[1] = NUL;
5004 }
5005}
5006
5007/*
5008 * "getcmdwintype()" function
5009 */
5010 static void
5011f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5012{
5013 rettv->v_type = VAR_STRING;
5014 rettv->vval.v_string = NULL;
5015#ifdef FEAT_CMDWIN
5016 rettv->vval.v_string = alloc(2);
5017 if (rettv->vval.v_string != NULL)
5018 {
5019 rettv->vval.v_string[0] = cmdwin_type;
5020 rettv->vval.v_string[1] = NUL;
5021 }
5022#endif
5023}
5024
5025#if defined(FEAT_CMDL_COMPL)
5026/*
5027 * "getcompletion()" function
5028 */
5029 static void
5030f_getcompletion(typval_T *argvars, typval_T *rettv)
5031{
5032 char_u *pat;
5033 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005034 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005035 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5036 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005038 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005039 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005040
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005041 if (p_wic)
5042 options |= WILD_ICASE;
5043
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005044 /* For filtered results, 'wildignore' is used */
5045 if (!filtered)
5046 options |= WILD_KEEP_ALL;
5047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005048 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005049 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005050 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005051 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005052 if (xpc.xp_context == EXPAND_NOTHING)
5053 {
5054 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005055 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005056 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005057 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005058 return;
5059 }
5060
5061# if defined(FEAT_MENU)
5062 if (xpc.xp_context == EXPAND_MENUS)
5063 {
5064 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5065 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5066 }
5067# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005068#ifdef FEAT_CSCOPE
5069 if (xpc.xp_context == EXPAND_CSCOPE)
5070 {
5071 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5072 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5073 }
5074#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005075#ifdef FEAT_SIGNS
5076 if (xpc.xp_context == EXPAND_SIGN)
5077 {
5078 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5079 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5080 }
5081#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005082
5083 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5084 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5085 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005086 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005087
5088 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5089
5090 for (i = 0; i < xpc.xp_numfiles; i++)
5091 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5092 }
5093 vim_free(pat);
5094 ExpandCleanup(&xpc);
5095}
5096#endif
5097
5098/*
5099 * "getcwd()" function
5100 */
5101 static void
5102f_getcwd(typval_T *argvars, typval_T *rettv)
5103{
5104 win_T *wp = NULL;
5105 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005106 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107
5108 rettv->v_type = VAR_STRING;
5109 rettv->vval.v_string = NULL;
5110
Bram Moolenaar54591292018-02-09 20:53:59 +01005111 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5112 global = TRUE;
5113 else
5114 wp = find_tabwin(&argvars[0], &argvars[1]);
5115
5116 if (wp != NULL && wp->w_localdir != NULL)
5117 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5118 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005119 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005120 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005121 rettv->vval.v_string = vim_strsave(globaldir);
5122 else
5123 {
5124 cwd = alloc(MAXPATHL);
5125 if (cwd != NULL)
5126 {
5127 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5128 rettv->vval.v_string = vim_strsave(cwd);
5129 vim_free(cwd);
5130 }
5131 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005132 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005133#ifdef BACKSLASH_IN_FILENAME
5134 if (rettv->vval.v_string != NULL)
5135 slash_adjust(rettv->vval.v_string);
5136#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137}
5138
5139/*
5140 * "getfontname()" function
5141 */
5142 static void
5143f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5144{
5145 rettv->v_type = VAR_STRING;
5146 rettv->vval.v_string = NULL;
5147#ifdef FEAT_GUI
5148 if (gui.in_use)
5149 {
5150 GuiFont font;
5151 char_u *name = NULL;
5152
5153 if (argvars[0].v_type == VAR_UNKNOWN)
5154 {
5155 /* Get the "Normal" font. Either the name saved by
5156 * hl_set_font_name() or from the font ID. */
5157 font = gui.norm_font;
5158 name = hl_get_font_name();
5159 }
5160 else
5161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005162 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005163 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5164 return;
5165 font = gui_mch_get_font(name, FALSE);
5166 if (font == NOFONT)
5167 return; /* Invalid font name, return empty string. */
5168 }
5169 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5170 if (argvars[0].v_type != VAR_UNKNOWN)
5171 gui_mch_free_font(font);
5172 }
5173#endif
5174}
5175
5176/*
5177 * "getfperm({fname})" function
5178 */
5179 static void
5180f_getfperm(typval_T *argvars, typval_T *rettv)
5181{
5182 char_u *fname;
5183 stat_T st;
5184 char_u *perm = NULL;
5185 char_u flags[] = "rwx";
5186 int i;
5187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005188 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005189
5190 rettv->v_type = VAR_STRING;
5191 if (mch_stat((char *)fname, &st) >= 0)
5192 {
5193 perm = vim_strsave((char_u *)"---------");
5194 if (perm != NULL)
5195 {
5196 for (i = 0; i < 9; i++)
5197 {
5198 if (st.st_mode & (1 << (8 - i)))
5199 perm[i] = flags[i % 3];
5200 }
5201 }
5202 }
5203 rettv->vval.v_string = perm;
5204}
5205
5206/*
5207 * "getfsize({fname})" function
5208 */
5209 static void
5210f_getfsize(typval_T *argvars, typval_T *rettv)
5211{
5212 char_u *fname;
5213 stat_T st;
5214
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005215 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005216
5217 rettv->v_type = VAR_NUMBER;
5218
5219 if (mch_stat((char *)fname, &st) >= 0)
5220 {
5221 if (mch_isdir(fname))
5222 rettv->vval.v_number = 0;
5223 else
5224 {
5225 rettv->vval.v_number = (varnumber_T)st.st_size;
5226
5227 /* non-perfect check for overflow */
5228 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5229 rettv->vval.v_number = -2;
5230 }
5231 }
5232 else
5233 rettv->vval.v_number = -1;
5234}
5235
5236/*
5237 * "getftime({fname})" function
5238 */
5239 static void
5240f_getftime(typval_T *argvars, typval_T *rettv)
5241{
5242 char_u *fname;
5243 stat_T st;
5244
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005245 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246
5247 if (mch_stat((char *)fname, &st) >= 0)
5248 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5249 else
5250 rettv->vval.v_number = -1;
5251}
5252
5253/*
5254 * "getftype({fname})" function
5255 */
5256 static void
5257f_getftype(typval_T *argvars, typval_T *rettv)
5258{
5259 char_u *fname;
5260 stat_T st;
5261 char_u *type = NULL;
5262 char *t;
5263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005264 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005265
5266 rettv->v_type = VAR_STRING;
5267 if (mch_lstat((char *)fname, &st) >= 0)
5268 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005269 if (S_ISREG(st.st_mode))
5270 t = "file";
5271 else if (S_ISDIR(st.st_mode))
5272 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005273 else if (S_ISLNK(st.st_mode))
5274 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005275 else if (S_ISBLK(st.st_mode))
5276 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005277 else if (S_ISCHR(st.st_mode))
5278 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005279 else if (S_ISFIFO(st.st_mode))
5280 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005282 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005283 else
5284 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285 type = vim_strsave((char_u *)t);
5286 }
5287 rettv->vval.v_string = type;
5288}
5289
5290/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005291 * "getjumplist()" function
5292 */
5293 static void
5294f_getjumplist(typval_T *argvars, typval_T *rettv)
5295{
5296#ifdef FEAT_JUMPLIST
5297 win_T *wp;
5298 int i;
5299 list_T *l;
5300 dict_T *d;
5301#endif
5302
5303 if (rettv_list_alloc(rettv) != OK)
5304 return;
5305
5306#ifdef FEAT_JUMPLIST
5307 wp = find_tabwin(&argvars[0], &argvars[1]);
5308 if (wp == NULL)
5309 return;
5310
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005311 cleanup_jumplist(wp, TRUE);
5312
Bram Moolenaar4f505882018-02-10 21:06:32 +01005313 l = list_alloc();
5314 if (l == NULL)
5315 return;
5316
5317 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5318 return;
5319 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5320
5321 for (i = 0; i < wp->w_jumplistlen; ++i)
5322 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005323 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5324 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005325 if ((d = dict_alloc()) == NULL)
5326 return;
5327 if (list_append_dict(l, d) == FAIL)
5328 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005329 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5330 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005331 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005332 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005333 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005334 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005335 }
5336#endif
5337}
5338
5339/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005340 * "getline(lnum, [end])" function
5341 */
5342 static void
5343f_getline(typval_T *argvars, typval_T *rettv)
5344{
5345 linenr_T lnum;
5346 linenr_T end;
5347 int retlist;
5348
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005349 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005350 if (argvars[1].v_type == VAR_UNKNOWN)
5351 {
5352 end = 0;
5353 retlist = FALSE;
5354 }
5355 else
5356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005357 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005358 retlist = TRUE;
5359 }
5360
5361 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5362}
5363
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005364#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005365 static void
5366get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5367{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005368 if (what_arg->v_type == VAR_UNKNOWN)
5369 {
5370 if (rettv_list_alloc(rettv) == OK)
5371 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005372 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005373 }
5374 else
5375 {
5376 if (rettv_dict_alloc(rettv) == OK)
5377 if (is_qf || (wp != NULL))
5378 {
5379 if (what_arg->v_type == VAR_DICT)
5380 {
5381 dict_T *d = what_arg->vval.v_dict;
5382
5383 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005384 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005385 }
5386 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005387 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005388 }
5389 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005390}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005391#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005392
5393/*
5394 * "getloclist()" function
5395 */
5396 static void
5397f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5398{
5399#ifdef FEAT_QUICKFIX
5400 win_T *wp;
5401
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005402 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005403 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5404#endif
5405}
5406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005407/*
5408 * "getmatches()" function
5409 */
5410 static void
5411f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5412{
5413#ifdef FEAT_SEARCH_EXTRA
5414 dict_T *dict;
5415 matchitem_T *cur = curwin->w_match_head;
5416 int i;
5417
5418 if (rettv_list_alloc(rettv) == OK)
5419 {
5420 while (cur != NULL)
5421 {
5422 dict = dict_alloc();
5423 if (dict == NULL)
5424 return;
5425 if (cur->match.regprog == NULL)
5426 {
5427 /* match added with matchaddpos() */
5428 for (i = 0; i < MAXPOSMATCH; ++i)
5429 {
5430 llpos_T *llpos;
5431 char buf[6];
5432 list_T *l;
5433
5434 llpos = &cur->pos.pos[i];
5435 if (llpos->lnum == 0)
5436 break;
5437 l = list_alloc();
5438 if (l == NULL)
5439 break;
5440 list_append_number(l, (varnumber_T)llpos->lnum);
5441 if (llpos->col > 0)
5442 {
5443 list_append_number(l, (varnumber_T)llpos->col);
5444 list_append_number(l, (varnumber_T)llpos->len);
5445 }
5446 sprintf(buf, "pos%d", i + 1);
5447 dict_add_list(dict, buf, l);
5448 }
5449 }
5450 else
5451 {
Bram Moolenaare0be1672018-07-08 16:50:37 +02005452 dict_add_string(dict, "pattern", cur->pattern);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005453 }
Bram Moolenaare0be1672018-07-08 16:50:37 +02005454 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5455 dict_add_number(dict, "priority", (long)cur->priority);
5456 dict_add_number(dict, "id", (long)cur->id);
Bram Moolenaar13505972019-01-24 15:04:48 +01005457# if defined(FEAT_CONCEAL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005458 if (cur->conceal_char)
5459 {
5460 char_u buf[MB_MAXBYTES + 1];
5461
5462 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005463 dict_add_string(dict, "conceal", (char_u *)&buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464 }
5465# endif
5466 list_append_dict(rettv->vval.v_list, dict);
5467 cur = cur->next;
5468 }
5469 }
5470#endif
5471}
5472
5473/*
5474 * "getpid()" function
5475 */
5476 static void
5477f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5478{
5479 rettv->vval.v_number = mch_get_pid();
5480}
5481
5482 static void
5483getpos_both(
5484 typval_T *argvars,
5485 typval_T *rettv,
5486 int getcurpos)
5487{
5488 pos_T *fp;
5489 list_T *l;
5490 int fnum = -1;
5491
5492 if (rettv_list_alloc(rettv) == OK)
5493 {
5494 l = rettv->vval.v_list;
5495 if (getcurpos)
5496 fp = &curwin->w_cursor;
5497 else
5498 fp = var2fpos(&argvars[0], TRUE, &fnum);
5499 if (fnum != -1)
5500 list_append_number(l, (varnumber_T)fnum);
5501 else
5502 list_append_number(l, (varnumber_T)0);
5503 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5504 : (varnumber_T)0);
5505 list_append_number(l, (fp != NULL)
5506 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5507 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005508 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005509 (varnumber_T)0);
5510 if (getcurpos)
5511 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005512 int save_set_curswant = curwin->w_set_curswant;
5513 colnr_T save_curswant = curwin->w_curswant;
5514 colnr_T save_virtcol = curwin->w_virtcol;
5515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 update_curswant();
5517 list_append_number(l, curwin->w_curswant == MAXCOL ?
5518 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005519
5520 // Do not change "curswant", as it is unexpected that a get
5521 // function has a side effect.
5522 if (save_set_curswant)
5523 {
5524 curwin->w_set_curswant = save_set_curswant;
5525 curwin->w_curswant = save_curswant;
5526 curwin->w_virtcol = save_virtcol;
5527 curwin->w_valid &= ~VALID_VIRTCOL;
5528 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005529 }
5530 }
5531 else
5532 rettv->vval.v_number = FALSE;
5533}
5534
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005535/*
5536 * "getcurpos()" function
5537 */
5538 static void
5539f_getcurpos(typval_T *argvars, typval_T *rettv)
5540{
5541 getpos_both(argvars, rettv, TRUE);
5542}
5543
5544/*
5545 * "getpos(string)" function
5546 */
5547 static void
5548f_getpos(typval_T *argvars, typval_T *rettv)
5549{
5550 getpos_both(argvars, rettv, FALSE);
5551}
5552
5553/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005554 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005555 */
5556 static void
5557f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5558{
5559#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005560 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005561#endif
5562}
5563
5564/*
5565 * "getreg()" function
5566 */
5567 static void
5568f_getreg(typval_T *argvars, typval_T *rettv)
5569{
5570 char_u *strregname;
5571 int regname;
5572 int arg2 = FALSE;
5573 int return_list = FALSE;
5574 int error = FALSE;
5575
5576 if (argvars[0].v_type != VAR_UNKNOWN)
5577 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005578 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005579 error = strregname == NULL;
5580 if (argvars[1].v_type != VAR_UNKNOWN)
5581 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005582 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005583 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005584 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005585 }
5586 }
5587 else
5588 strregname = get_vim_var_str(VV_REG);
5589
5590 if (error)
5591 return;
5592
5593 regname = (strregname == NULL ? '"' : *strregname);
5594 if (regname == 0)
5595 regname = '"';
5596
5597 if (return_list)
5598 {
5599 rettv->v_type = VAR_LIST;
5600 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5601 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5602 if (rettv->vval.v_list == NULL)
5603 (void)rettv_list_alloc(rettv);
5604 else
5605 ++rettv->vval.v_list->lv_refcount;
5606 }
5607 else
5608 {
5609 rettv->v_type = VAR_STRING;
5610 rettv->vval.v_string = get_reg_contents(regname,
5611 arg2 ? GREG_EXPR_SRC : 0);
5612 }
5613}
5614
5615/*
5616 * "getregtype()" function
5617 */
5618 static void
5619f_getregtype(typval_T *argvars, typval_T *rettv)
5620{
5621 char_u *strregname;
5622 int regname;
5623 char_u buf[NUMBUFLEN + 2];
5624 long reglen = 0;
5625
5626 if (argvars[0].v_type != VAR_UNKNOWN)
5627 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005628 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005629 if (strregname == NULL) /* type error; errmsg already given */
5630 {
5631 rettv->v_type = VAR_STRING;
5632 rettv->vval.v_string = NULL;
5633 return;
5634 }
5635 }
5636 else
5637 /* Default to v:register */
5638 strregname = get_vim_var_str(VV_REG);
5639
5640 regname = (strregname == NULL ? '"' : *strregname);
5641 if (regname == 0)
5642 regname = '"';
5643
5644 buf[0] = NUL;
5645 buf[1] = NUL;
5646 switch (get_reg_type(regname, &reglen))
5647 {
5648 case MLINE: buf[0] = 'V'; break;
5649 case MCHAR: buf[0] = 'v'; break;
5650 case MBLOCK:
5651 buf[0] = Ctrl_V;
5652 sprintf((char *)buf + 1, "%ld", reglen + 1);
5653 break;
5654 }
5655 rettv->v_type = VAR_STRING;
5656 rettv->vval.v_string = vim_strsave(buf);
5657}
5658
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005659/*
5660 * Returns information (variables, options, etc.) about a tab page
5661 * as a dictionary.
5662 */
5663 static dict_T *
5664get_tabpage_info(tabpage_T *tp, int tp_idx)
5665{
5666 win_T *wp;
5667 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005668 list_T *l;
5669
5670 dict = dict_alloc();
5671 if (dict == NULL)
5672 return NULL;
5673
Bram Moolenaare0be1672018-07-08 16:50:37 +02005674 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005675
5676 l = list_alloc();
5677 if (l != NULL)
5678 {
5679 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5680 wp; wp = wp->w_next)
5681 list_append_number(l, (varnumber_T)wp->w_id);
5682 dict_add_list(dict, "windows", l);
5683 }
5684
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005685 /* Make a reference to tabpage variables */
5686 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005687
5688 return dict;
5689}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005690
5691/*
5692 * "gettabinfo()" function
5693 */
5694 static void
5695f_gettabinfo(typval_T *argvars, typval_T *rettv)
5696{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005697 tabpage_T *tp, *tparg = NULL;
5698 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005699 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005700
5701 if (rettv_list_alloc(rettv) != OK)
5702 return;
5703
5704 if (argvars[0].v_type != VAR_UNKNOWN)
5705 {
5706 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005707 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005708 if (tparg == NULL)
5709 return;
5710 }
5711
5712 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005713 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005714 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005715 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005716 if (tparg != NULL && tp != tparg)
5717 continue;
5718 d = get_tabpage_info(tp, tpnr);
5719 if (d != NULL)
5720 list_append_dict(rettv->vval.v_list, d);
5721 if (tparg != NULL)
5722 return;
5723 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005724}
5725
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005726/*
5727 * "gettabvar()" function
5728 */
5729 static void
5730f_gettabvar(typval_T *argvars, typval_T *rettv)
5731{
5732 win_T *oldcurwin;
5733 tabpage_T *tp, *oldtabpage;
5734 dictitem_T *v;
5735 char_u *varname;
5736 int done = FALSE;
5737
5738 rettv->v_type = VAR_STRING;
5739 rettv->vval.v_string = NULL;
5740
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005741 varname = tv_get_string_chk(&argvars[1]);
5742 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743 if (tp != NULL && varname != NULL)
5744 {
5745 /* Set tp to be our tabpage, temporarily. Also set the window to the
5746 * first window in the tabpage, otherwise the window is not valid. */
5747 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005748 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5749 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005750 {
5751 /* look up the variable */
5752 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5753 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5754 if (v != NULL)
5755 {
5756 copy_tv(&v->di_tv, rettv);
5757 done = TRUE;
5758 }
5759 }
5760
5761 /* restore previous notion of curwin */
5762 restore_win(oldcurwin, oldtabpage, TRUE);
5763 }
5764
5765 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5766 copy_tv(&argvars[2], rettv);
5767}
5768
5769/*
5770 * "gettabwinvar()" function
5771 */
5772 static void
5773f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5774{
5775 getwinvar(argvars, rettv, 1);
5776}
5777
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005778/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005779 * "gettagstack()" function
5780 */
5781 static void
5782f_gettagstack(typval_T *argvars, typval_T *rettv)
5783{
5784 win_T *wp = curwin; // default is current window
5785
5786 if (rettv_dict_alloc(rettv) != OK)
5787 return;
5788
5789 if (argvars[0].v_type != VAR_UNKNOWN)
5790 {
5791 wp = find_win_by_nr_or_id(&argvars[0]);
5792 if (wp == NULL)
5793 return;
5794 }
5795
5796 get_tagstack(wp, rettv->vval.v_dict);
5797}
5798
5799/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005800 * Returns information about a window as a dictionary.
5801 */
5802 static dict_T *
5803get_win_info(win_T *wp, short tpnr, short winnr)
5804{
5805 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005806
5807 dict = dict_alloc();
5808 if (dict == NULL)
5809 return NULL;
5810
Bram Moolenaare0be1672018-07-08 16:50:37 +02005811 dict_add_number(dict, "tabnr", tpnr);
5812 dict_add_number(dict, "winnr", winnr);
5813 dict_add_number(dict, "winid", wp->w_id);
5814 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005815 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005816 dict_add_number(dict, "topline", wp->w_topline);
5817 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005818#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005819 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005820#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005821 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005822 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005823 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005824
Bram Moolenaar69905d12017-08-13 18:14:47 +02005825#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005826 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005827#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005828#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005829 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5830 dict_add_number(dict, "loclist",
5831 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005832#endif
5833
Bram Moolenaar30567352016-08-27 21:25:44 +02005834 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005835 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005836
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005837 return dict;
5838}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005839
5840/*
5841 * "getwininfo()" function
5842 */
5843 static void
5844f_getwininfo(typval_T *argvars, typval_T *rettv)
5845{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005846 tabpage_T *tp;
5847 win_T *wp = NULL, *wparg = NULL;
5848 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005849 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005850
5851 if (rettv_list_alloc(rettv) != OK)
5852 return;
5853
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005854 if (argvars[0].v_type != VAR_UNKNOWN)
5855 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005856 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005857 if (wparg == NULL)
5858 return;
5859 }
5860
5861 /* Collect information about either all the windows across all the tab
5862 * pages or one particular window.
5863 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005864 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005865 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005866 tabnr++;
5867 winnr = 0;
5868 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005869 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005870 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005871 if (wparg != NULL && wp != wparg)
5872 continue;
5873 d = get_win_info(wp, tabnr, winnr);
5874 if (d != NULL)
5875 list_append_dict(rettv->vval.v_list, d);
5876 if (wparg != NULL)
5877 /* found information about a specific window */
5878 return;
5879 }
5880 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005881}
5882
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005884 * "win_findbuf()" function
5885 */
5886 static void
5887f_win_findbuf(typval_T *argvars, typval_T *rettv)
5888{
5889 if (rettv_list_alloc(rettv) != FAIL)
5890 win_findbuf(argvars, rettv->vval.v_list);
5891}
5892
5893/*
5894 * "win_getid()" function
5895 */
5896 static void
5897f_win_getid(typval_T *argvars, typval_T *rettv)
5898{
5899 rettv->vval.v_number = win_getid(argvars);
5900}
5901
5902/*
5903 * "win_gotoid()" function
5904 */
5905 static void
5906f_win_gotoid(typval_T *argvars, typval_T *rettv)
5907{
5908 rettv->vval.v_number = win_gotoid(argvars);
5909}
5910
5911/*
5912 * "win_id2tabwin()" function
5913 */
5914 static void
5915f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5916{
5917 if (rettv_list_alloc(rettv) != FAIL)
5918 win_id2tabwin(argvars, rettv->vval.v_list);
5919}
5920
5921/*
5922 * "win_id2win()" function
5923 */
5924 static void
5925f_win_id2win(typval_T *argvars, typval_T *rettv)
5926{
5927 rettv->vval.v_number = win_id2win(argvars);
5928}
5929
5930/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005931 * "win_screenpos()" function
5932 */
5933 static void
5934f_win_screenpos(typval_T *argvars, typval_T *rettv)
5935{
5936 win_T *wp;
5937
5938 if (rettv_list_alloc(rettv) == FAIL)
5939 return;
5940
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005941 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005942 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5943 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5944}
5945
5946/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005947 * "getwinpos({timeout})" function
5948 */
5949 static void
5950f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5951{
5952 int x = -1;
5953 int y = -1;
5954
5955 if (rettv_list_alloc(rettv) == FAIL)
5956 return;
5957#ifdef FEAT_GUI
5958 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005959 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005960# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5961 else
5962# endif
5963#endif
5964#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5965 {
5966 varnumber_T timeout = 100;
5967
5968 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005969 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005970 term_get_winpos(&x, &y, timeout);
5971 }
5972#endif
5973 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5974 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5975}
5976
5977
5978/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005979 * "getwinposx()" function
5980 */
5981 static void
5982f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5983{
5984 rettv->vval.v_number = -1;
5985#ifdef FEAT_GUI
5986 if (gui.in_use)
5987 {
5988 int x, y;
5989
5990 if (gui_mch_get_winpos(&x, &y) == OK)
5991 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02005992 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005993 }
5994#endif
5995#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5996 {
5997 int x, y;
5998
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005999 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006000 rettv->vval.v_number = x;
6001 }
6002#endif
6003}
6004
6005/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 * "getwinposy()" function
6007 */
6008 static void
6009f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6010{
6011 rettv->vval.v_number = -1;
6012#ifdef FEAT_GUI
6013 if (gui.in_use)
6014 {
6015 int x, y;
6016
6017 if (gui_mch_get_winpos(&x, &y) == OK)
6018 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006019 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006020 }
6021#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006022#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6023 {
6024 int x, y;
6025
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006026 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006027 rettv->vval.v_number = y;
6028 }
6029#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030}
6031
6032/*
6033 * "getwinvar()" function
6034 */
6035 static void
6036f_getwinvar(typval_T *argvars, typval_T *rettv)
6037{
6038 getwinvar(argvars, rettv, 0);
6039}
6040
6041/*
6042 * "glob()" function
6043 */
6044 static void
6045f_glob(typval_T *argvars, typval_T *rettv)
6046{
6047 int options = WILD_SILENT|WILD_USE_NL;
6048 expand_T xpc;
6049 int error = FALSE;
6050
6051 /* When the optional second argument is non-zero, don't remove matches
6052 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6053 rettv->v_type = VAR_STRING;
6054 if (argvars[1].v_type != VAR_UNKNOWN)
6055 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006056 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006057 options |= WILD_KEEP_ALL;
6058 if (argvars[2].v_type != VAR_UNKNOWN)
6059 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006060 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006061 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006062 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063 }
6064 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006065 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066 options |= WILD_ALLLINKS;
6067 }
6068 }
6069 if (!error)
6070 {
6071 ExpandInit(&xpc);
6072 xpc.xp_context = EXPAND_FILES;
6073 if (p_wic)
6074 options += WILD_ICASE;
6075 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006076 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006077 NULL, options, WILD_ALL);
6078 else if (rettv_list_alloc(rettv) != FAIL)
6079 {
6080 int i;
6081
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006082 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083 NULL, options, WILD_ALL_KEEP);
6084 for (i = 0; i < xpc.xp_numfiles; i++)
6085 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6086
6087 ExpandCleanup(&xpc);
6088 }
6089 }
6090 else
6091 rettv->vval.v_string = NULL;
6092}
6093
6094/*
6095 * "globpath()" function
6096 */
6097 static void
6098f_globpath(typval_T *argvars, typval_T *rettv)
6099{
6100 int flags = 0;
6101 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006102 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006103 int error = FALSE;
6104 garray_T ga;
6105 int i;
6106
6107 /* When the optional second argument is non-zero, don't remove matches
6108 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6109 rettv->v_type = VAR_STRING;
6110 if (argvars[2].v_type != VAR_UNKNOWN)
6111 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006112 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006113 flags |= WILD_KEEP_ALL;
6114 if (argvars[3].v_type != VAR_UNKNOWN)
6115 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006116 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006117 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006118 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006119 }
6120 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006121 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006122 flags |= WILD_ALLLINKS;
6123 }
6124 }
6125 if (file != NULL && !error)
6126 {
6127 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006128 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006129 if (rettv->v_type == VAR_STRING)
6130 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6131 else if (rettv_list_alloc(rettv) != FAIL)
6132 for (i = 0; i < ga.ga_len; ++i)
6133 list_append_string(rettv->vval.v_list,
6134 ((char_u **)(ga.ga_data))[i], -1);
6135 ga_clear_strings(&ga);
6136 }
6137 else
6138 rettv->vval.v_string = NULL;
6139}
6140
6141/*
6142 * "glob2regpat()" function
6143 */
6144 static void
6145f_glob2regpat(typval_T *argvars, typval_T *rettv)
6146{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006147 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006148
6149 rettv->v_type = VAR_STRING;
6150 rettv->vval.v_string = (pat == NULL)
6151 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6152}
6153
6154/* for VIM_VERSION_ defines */
6155#include "version.h"
6156
6157/*
6158 * "has()" function
6159 */
6160 static void
6161f_has(typval_T *argvars, typval_T *rettv)
6162{
6163 int i;
6164 char_u *name;
6165 int n = FALSE;
6166 static char *(has_list[]) =
6167 {
6168#ifdef AMIGA
6169 "amiga",
6170# ifdef FEAT_ARP
6171 "arp",
6172# endif
6173#endif
6174#ifdef __BEOS__
6175 "beos",
6176#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006177#if defined(BSD) && !defined(MACOS_X)
6178 "bsd",
6179#endif
6180#ifdef hpux
6181 "hpux",
6182#endif
6183#ifdef __linux__
6184 "linux",
6185#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006186#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006187 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6188 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006189# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006190 "macunix", /* Mac OS X, with the darwin feature */
6191 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006192# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006193#endif
6194#ifdef __QNX__
6195 "qnx",
6196#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006197#ifdef SUN_SYSTEM
6198 "sun",
6199#else
6200 "moon",
6201#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202#ifdef UNIX
6203 "unix",
6204#endif
6205#ifdef VMS
6206 "vms",
6207#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006208#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006209 "win32",
6210#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006211#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212 "win32unix",
6213#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006214#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215 "win64",
6216#endif
6217#ifdef EBCDIC
6218 "ebcdic",
6219#endif
6220#ifndef CASE_INSENSITIVE_FILENAME
6221 "fname_case",
6222#endif
6223#ifdef HAVE_ACL
6224 "acl",
6225#endif
6226#ifdef FEAT_ARABIC
6227 "arabic",
6228#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006229 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006230#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006231 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006232#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006233#ifdef FEAT_AUTOSERVERNAME
6234 "autoservername",
6235#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006236#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006237 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006238# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006239 "balloon_multiline",
6240# endif
6241#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006242#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006243 "balloon_eval_term",
6244#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006245#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6246 "builtin_terms",
6247# ifdef ALL_BUILTIN_TCAPS
6248 "all_builtin_terms",
6249# endif
6250#endif
6251#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006252 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006253 || defined(FEAT_GUI_MOTIF))
6254 "browsefilter",
6255#endif
6256#ifdef FEAT_BYTEOFF
6257 "byte_offset",
6258#endif
6259#ifdef FEAT_JOB_CHANNEL
6260 "channel",
6261#endif
6262#ifdef FEAT_CINDENT
6263 "cindent",
6264#endif
6265#ifdef FEAT_CLIENTSERVER
6266 "clientserver",
6267#endif
6268#ifdef FEAT_CLIPBOARD
6269 "clipboard",
6270#endif
6271#ifdef FEAT_CMDL_COMPL
6272 "cmdline_compl",
6273#endif
6274#ifdef FEAT_CMDHIST
6275 "cmdline_hist",
6276#endif
6277#ifdef FEAT_COMMENTS
6278 "comments",
6279#endif
6280#ifdef FEAT_CONCEAL
6281 "conceal",
6282#endif
6283#ifdef FEAT_CRYPT
6284 "cryptv",
6285 "crypt-blowfish",
6286 "crypt-blowfish2",
6287#endif
6288#ifdef FEAT_CSCOPE
6289 "cscope",
6290#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006292#ifdef CURSOR_SHAPE
6293 "cursorshape",
6294#endif
6295#ifdef DEBUG
6296 "debug",
6297#endif
6298#ifdef FEAT_CON_DIALOG
6299 "dialog_con",
6300#endif
6301#ifdef FEAT_GUI_DIALOG
6302 "dialog_gui",
6303#endif
6304#ifdef FEAT_DIFF
6305 "diff",
6306#endif
6307#ifdef FEAT_DIGRAPHS
6308 "digraphs",
6309#endif
6310#ifdef FEAT_DIRECTX
6311 "directx",
6312#endif
6313#ifdef FEAT_DND
6314 "dnd",
6315#endif
6316#ifdef FEAT_EMACS_TAGS
6317 "emacs_tags",
6318#endif
6319 "eval", /* always present, of course! */
6320 "ex_extra", /* graduated feature */
6321#ifdef FEAT_SEARCH_EXTRA
6322 "extra_search",
6323#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006324#ifdef FEAT_SEARCHPATH
6325 "file_in_path",
6326#endif
6327#ifdef FEAT_FILTERPIPE
6328 "filterpipe",
6329#endif
6330#ifdef FEAT_FIND_ID
6331 "find_in_path",
6332#endif
6333#ifdef FEAT_FLOAT
6334 "float",
6335#endif
6336#ifdef FEAT_FOLDING
6337 "folding",
6338#endif
6339#ifdef FEAT_FOOTER
6340 "footer",
6341#endif
6342#if !defined(USE_SYSTEM) && defined(UNIX)
6343 "fork",
6344#endif
6345#ifdef FEAT_GETTEXT
6346 "gettext",
6347#endif
6348#ifdef FEAT_GUI
6349 "gui",
6350#endif
6351#ifdef FEAT_GUI_ATHENA
6352# ifdef FEAT_GUI_NEXTAW
6353 "gui_neXtaw",
6354# else
6355 "gui_athena",
6356# endif
6357#endif
6358#ifdef FEAT_GUI_GTK
6359 "gui_gtk",
6360# ifdef USE_GTK3
6361 "gui_gtk3",
6362# else
6363 "gui_gtk2",
6364# endif
6365#endif
6366#ifdef FEAT_GUI_GNOME
6367 "gui_gnome",
6368#endif
6369#ifdef FEAT_GUI_MAC
6370 "gui_mac",
6371#endif
6372#ifdef FEAT_GUI_MOTIF
6373 "gui_motif",
6374#endif
6375#ifdef FEAT_GUI_PHOTON
6376 "gui_photon",
6377#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006378#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006379 "gui_win32",
6380#endif
6381#ifdef FEAT_HANGULIN
6382 "hangul_input",
6383#endif
6384#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6385 "iconv",
6386#endif
6387#ifdef FEAT_INS_EXPAND
6388 "insert_expand",
6389#endif
6390#ifdef FEAT_JOB_CHANNEL
6391 "job",
6392#endif
6393#ifdef FEAT_JUMPLIST
6394 "jumplist",
6395#endif
6396#ifdef FEAT_KEYMAP
6397 "keymap",
6398#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006399 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400#ifdef FEAT_LANGMAP
6401 "langmap",
6402#endif
6403#ifdef FEAT_LIBCALL
6404 "libcall",
6405#endif
6406#ifdef FEAT_LINEBREAK
6407 "linebreak",
6408#endif
6409#ifdef FEAT_LISP
6410 "lispindent",
6411#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006413#ifdef FEAT_LOCALMAP
6414 "localmap",
6415#endif
6416#ifdef FEAT_LUA
6417# ifndef DYNAMIC_LUA
6418 "lua",
6419# endif
6420#endif
6421#ifdef FEAT_MENU
6422 "menu",
6423#endif
6424#ifdef FEAT_SESSION
6425 "mksession",
6426#endif
6427#ifdef FEAT_MODIFY_FNAME
6428 "modify_fname",
6429#endif
6430#ifdef FEAT_MOUSE
6431 "mouse",
6432#endif
6433#ifdef FEAT_MOUSESHAPE
6434 "mouseshape",
6435#endif
6436#if defined(UNIX) || defined(VMS)
6437# ifdef FEAT_MOUSE_DEC
6438 "mouse_dec",
6439# endif
6440# ifdef FEAT_MOUSE_GPM
6441 "mouse_gpm",
6442# endif
6443# ifdef FEAT_MOUSE_JSB
6444 "mouse_jsbterm",
6445# endif
6446# ifdef FEAT_MOUSE_NET
6447 "mouse_netterm",
6448# endif
6449# ifdef FEAT_MOUSE_PTERM
6450 "mouse_pterm",
6451# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006452# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453 "mouse_sgr",
6454# endif
6455# ifdef FEAT_SYSMOUSE
6456 "mouse_sysmouse",
6457# endif
6458# ifdef FEAT_MOUSE_URXVT
6459 "mouse_urxvt",
6460# endif
6461# ifdef FEAT_MOUSE_XTERM
6462 "mouse_xterm",
6463# endif
6464#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466#ifdef FEAT_MBYTE_IME
6467 "multi_byte_ime",
6468#endif
6469#ifdef FEAT_MULTI_LANG
6470 "multi_lang",
6471#endif
6472#ifdef FEAT_MZSCHEME
6473#ifndef DYNAMIC_MZSCHEME
6474 "mzscheme",
6475#endif
6476#endif
6477#ifdef FEAT_NUM64
6478 "num64",
6479#endif
6480#ifdef FEAT_OLE
6481 "ole",
6482#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006483#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006485#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486#ifdef FEAT_PATH_EXTRA
6487 "path_extra",
6488#endif
6489#ifdef FEAT_PERL
6490#ifndef DYNAMIC_PERL
6491 "perl",
6492#endif
6493#endif
6494#ifdef FEAT_PERSISTENT_UNDO
6495 "persistent_undo",
6496#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006497#if defined(FEAT_PYTHON)
6498 "python_compiled",
6499# if defined(DYNAMIC_PYTHON)
6500 "python_dynamic",
6501# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006503 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006504# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006506#if defined(FEAT_PYTHON3)
6507 "python3_compiled",
6508# if defined(DYNAMIC_PYTHON3)
6509 "python3_dynamic",
6510# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006511 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006512 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006513# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514#endif
6515#ifdef FEAT_POSTSCRIPT
6516 "postscript",
6517#endif
6518#ifdef FEAT_PRINTER
6519 "printer",
6520#endif
6521#ifdef FEAT_PROFILE
6522 "profile",
6523#endif
6524#ifdef FEAT_RELTIME
6525 "reltime",
6526#endif
6527#ifdef FEAT_QUICKFIX
6528 "quickfix",
6529#endif
6530#ifdef FEAT_RIGHTLEFT
6531 "rightleft",
6532#endif
6533#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6534 "ruby",
6535#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006536 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537#ifdef FEAT_CMDL_INFO
6538 "showcmd",
6539 "cmdline_info",
6540#endif
6541#ifdef FEAT_SIGNS
6542 "signs",
6543#endif
6544#ifdef FEAT_SMARTINDENT
6545 "smartindent",
6546#endif
6547#ifdef STARTUPTIME
6548 "startuptime",
6549#endif
6550#ifdef FEAT_STL_OPT
6551 "statusline",
6552#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553#ifdef FEAT_NETBEANS_INTG
6554 "netbeans_intg",
6555#endif
6556#ifdef FEAT_SPELL
6557 "spell",
6558#endif
6559#ifdef FEAT_SYN_HL
6560 "syntax",
6561#endif
6562#if defined(USE_SYSTEM) || !defined(UNIX)
6563 "system",
6564#endif
6565#ifdef FEAT_TAG_BINS
6566 "tag_binary",
6567#endif
6568#ifdef FEAT_TAG_OLDSTATIC
6569 "tag_old_static",
6570#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006571#ifdef FEAT_TCL
6572# ifndef DYNAMIC_TCL
6573 "tcl",
6574# endif
6575#endif
6576#ifdef FEAT_TERMGUICOLORS
6577 "termguicolors",
6578#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006579#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006580 "terminal",
6581#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006582#ifdef TERMINFO
6583 "terminfo",
6584#endif
6585#ifdef FEAT_TERMRESPONSE
6586 "termresponse",
6587#endif
6588#ifdef FEAT_TEXTOBJ
6589 "textobjects",
6590#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006591#ifdef FEAT_TEXT_PROP
6592 "textprop",
6593#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594#ifdef HAVE_TGETENT
6595 "tgetent",
6596#endif
6597#ifdef FEAT_TIMERS
6598 "timers",
6599#endif
6600#ifdef FEAT_TITLE
6601 "title",
6602#endif
6603#ifdef FEAT_TOOLBAR
6604 "toolbar",
6605#endif
6606#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6607 "unnamedplus",
6608#endif
6609#ifdef FEAT_USR_CMDS
6610 "user-commands", /* was accidentally included in 5.4 */
6611 "user_commands",
6612#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006613#ifdef FEAT_VARTABS
6614 "vartabs",
6615#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616#ifdef FEAT_VIMINFO
6617 "viminfo",
6618#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006619 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006621 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006622 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006624#ifdef FEAT_VTP
6625 "vtp",
6626#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006627#ifdef FEAT_WILDIGN
6628 "wildignore",
6629#endif
6630#ifdef FEAT_WILDMENU
6631 "wildmenu",
6632#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006633 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006634#ifdef FEAT_WAK
6635 "winaltkeys",
6636#endif
6637#ifdef FEAT_WRITEBACKUP
6638 "writebackup",
6639#endif
6640#ifdef FEAT_XIM
6641 "xim",
6642#endif
6643#ifdef FEAT_XFONTSET
6644 "xfontset",
6645#endif
6646#ifdef FEAT_XPM_W32
6647 "xpm",
6648 "xpm_w32", /* for backward compatibility */
6649#else
6650# if defined(HAVE_XPM)
6651 "xpm",
6652# endif
6653#endif
6654#ifdef USE_XSMP
6655 "xsmp",
6656#endif
6657#ifdef USE_XSMP_INTERACT
6658 "xsmp_interact",
6659#endif
6660#ifdef FEAT_XCLIPBOARD
6661 "xterm_clipboard",
6662#endif
6663#ifdef FEAT_XTERM_SAVE
6664 "xterm_save",
6665#endif
6666#if defined(UNIX) && defined(FEAT_X11)
6667 "X11",
6668#endif
6669 NULL
6670 };
6671
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006672 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006673 for (i = 0; has_list[i] != NULL; ++i)
6674 if (STRICMP(name, has_list[i]) == 0)
6675 {
6676 n = TRUE;
6677 break;
6678 }
6679
6680 if (n == FALSE)
6681 {
6682 if (STRNICMP(name, "patch", 5) == 0)
6683 {
6684 if (name[5] == '-'
6685 && STRLEN(name) >= 11
6686 && vim_isdigit(name[6])
6687 && vim_isdigit(name[8])
6688 && vim_isdigit(name[10]))
6689 {
6690 int major = atoi((char *)name + 6);
6691 int minor = atoi((char *)name + 8);
6692
6693 /* Expect "patch-9.9.01234". */
6694 n = (major < VIM_VERSION_MAJOR
6695 || (major == VIM_VERSION_MAJOR
6696 && (minor < VIM_VERSION_MINOR
6697 || (minor == VIM_VERSION_MINOR
6698 && has_patch(atoi((char *)name + 10))))));
6699 }
6700 else
6701 n = has_patch(atoi((char *)name + 5));
6702 }
6703 else if (STRICMP(name, "vim_starting") == 0)
6704 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006705 else if (STRICMP(name, "ttyin") == 0)
6706 n = mch_input_isatty();
6707 else if (STRICMP(name, "ttyout") == 0)
6708 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006709 else if (STRICMP(name, "multi_byte_encoding") == 0)
6710 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006711#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006712 else if (STRICMP(name, "balloon_multiline") == 0)
6713 n = multiline_balloon_available();
6714#endif
6715#ifdef DYNAMIC_TCL
6716 else if (STRICMP(name, "tcl") == 0)
6717 n = tcl_enabled(FALSE);
6718#endif
6719#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6720 else if (STRICMP(name, "iconv") == 0)
6721 n = iconv_enabled(FALSE);
6722#endif
6723#ifdef DYNAMIC_LUA
6724 else if (STRICMP(name, "lua") == 0)
6725 n = lua_enabled(FALSE);
6726#endif
6727#ifdef DYNAMIC_MZSCHEME
6728 else if (STRICMP(name, "mzscheme") == 0)
6729 n = mzscheme_enabled(FALSE);
6730#endif
6731#ifdef DYNAMIC_RUBY
6732 else if (STRICMP(name, "ruby") == 0)
6733 n = ruby_enabled(FALSE);
6734#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006735#ifdef DYNAMIC_PYTHON
6736 else if (STRICMP(name, "python") == 0)
6737 n = python_enabled(FALSE);
6738#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739#ifdef DYNAMIC_PYTHON3
6740 else if (STRICMP(name, "python3") == 0)
6741 n = python3_enabled(FALSE);
6742#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006743#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6744 else if (STRICMP(name, "pythonx") == 0)
6745 {
6746# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6747 if (p_pyx == 0)
6748 n = python3_enabled(FALSE) || python_enabled(FALSE);
6749 else if (p_pyx == 3)
6750 n = python3_enabled(FALSE);
6751 else if (p_pyx == 2)
6752 n = python_enabled(FALSE);
6753# elif defined(DYNAMIC_PYTHON)
6754 n = python_enabled(FALSE);
6755# elif defined(DYNAMIC_PYTHON3)
6756 n = python3_enabled(FALSE);
6757# endif
6758 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759#endif
6760#ifdef DYNAMIC_PERL
6761 else if (STRICMP(name, "perl") == 0)
6762 n = perl_enabled(FALSE);
6763#endif
6764#ifdef FEAT_GUI
6765 else if (STRICMP(name, "gui_running") == 0)
6766 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006767# ifdef FEAT_BROWSE
6768 else if (STRICMP(name, "browse") == 0)
6769 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6770# endif
6771#endif
6772#ifdef FEAT_SYN_HL
6773 else if (STRICMP(name, "syntax_items") == 0)
6774 n = syntax_present(curwin);
6775#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006776#ifdef FEAT_VTP
6777 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006778 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779#endif
6780#ifdef FEAT_NETBEANS_INTG
6781 else if (STRICMP(name, "netbeans_enabled") == 0)
6782 n = netbeans_active();
6783#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006784#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006785 else if (STRICMP(name, "terminal") == 0)
6786 n = terminal_enabled();
6787#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006788#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006789 else if (STRICMP(name, "conpty") == 0)
6790 n = use_conpty();
6791#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006792 }
6793
6794 rettv->vval.v_number = n;
6795}
6796
6797/*
6798 * "has_key()" function
6799 */
6800 static void
6801f_has_key(typval_T *argvars, typval_T *rettv)
6802{
6803 if (argvars[0].v_type != VAR_DICT)
6804 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006805 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006806 return;
6807 }
6808 if (argvars[0].vval.v_dict == NULL)
6809 return;
6810
6811 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006812 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813}
6814
6815/*
6816 * "haslocaldir()" function
6817 */
6818 static void
6819f_haslocaldir(typval_T *argvars, typval_T *rettv)
6820{
6821 win_T *wp = NULL;
6822
6823 wp = find_tabwin(&argvars[0], &argvars[1]);
6824 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6825}
6826
6827/*
6828 * "hasmapto()" function
6829 */
6830 static void
6831f_hasmapto(typval_T *argvars, typval_T *rettv)
6832{
6833 char_u *name;
6834 char_u *mode;
6835 char_u buf[NUMBUFLEN];
6836 int abbr = FALSE;
6837
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006838 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 if (argvars[1].v_type == VAR_UNKNOWN)
6840 mode = (char_u *)"nvo";
6841 else
6842 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006843 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006844 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006845 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006846 }
6847
6848 if (map_to_exists(name, mode, abbr))
6849 rettv->vval.v_number = TRUE;
6850 else
6851 rettv->vval.v_number = FALSE;
6852}
6853
6854/*
6855 * "histadd()" function
6856 */
6857 static void
6858f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6859{
6860#ifdef FEAT_CMDHIST
6861 int histype;
6862 char_u *str;
6863 char_u buf[NUMBUFLEN];
6864#endif
6865
6866 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006867 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 return;
6869#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006870 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006871 histype = str != NULL ? get_histtype(str) : -1;
6872 if (histype >= 0)
6873 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006874 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006875 if (*str != NUL)
6876 {
6877 init_history();
6878 add_to_history(histype, str, FALSE, NUL);
6879 rettv->vval.v_number = TRUE;
6880 return;
6881 }
6882 }
6883#endif
6884}
6885
6886/*
6887 * "histdel()" function
6888 */
6889 static void
6890f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6891{
6892#ifdef FEAT_CMDHIST
6893 int n;
6894 char_u buf[NUMBUFLEN];
6895 char_u *str;
6896
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006897 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006898 if (str == NULL)
6899 n = 0;
6900 else if (argvars[1].v_type == VAR_UNKNOWN)
6901 /* only one argument: clear entire history */
6902 n = clr_history(get_histtype(str));
6903 else if (argvars[1].v_type == VAR_NUMBER)
6904 /* index given: remove that entry */
6905 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006906 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006907 else
6908 /* string given: remove all matching entries */
6909 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006910 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 rettv->vval.v_number = n;
6912#endif
6913}
6914
6915/*
6916 * "histget()" function
6917 */
6918 static void
6919f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6920{
6921#ifdef FEAT_CMDHIST
6922 int type;
6923 int idx;
6924 char_u *str;
6925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006926 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006927 if (str == NULL)
6928 rettv->vval.v_string = NULL;
6929 else
6930 {
6931 type = get_histtype(str);
6932 if (argvars[1].v_type == VAR_UNKNOWN)
6933 idx = get_history_idx(type);
6934 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006935 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 /* -1 on type error */
6937 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6938 }
6939#else
6940 rettv->vval.v_string = NULL;
6941#endif
6942 rettv->v_type = VAR_STRING;
6943}
6944
6945/*
6946 * "histnr()" function
6947 */
6948 static void
6949f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6950{
6951 int i;
6952
6953#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006954 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955
6956 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6957 if (i >= HIST_CMD && i < HIST_COUNT)
6958 i = get_history_idx(i);
6959 else
6960#endif
6961 i = -1;
6962 rettv->vval.v_number = i;
6963}
6964
6965/*
6966 * "highlightID(name)" function
6967 */
6968 static void
6969f_hlID(typval_T *argvars, typval_T *rettv)
6970{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006971 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006972}
6973
6974/*
6975 * "highlight_exists()" function
6976 */
6977 static void
6978f_hlexists(typval_T *argvars, typval_T *rettv)
6979{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006980 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981}
6982
6983/*
6984 * "hostname()" function
6985 */
6986 static void
6987f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6988{
6989 char_u hostname[256];
6990
6991 mch_get_host_name(hostname, 256);
6992 rettv->v_type = VAR_STRING;
6993 rettv->vval.v_string = vim_strsave(hostname);
6994}
6995
6996/*
6997 * iconv() function
6998 */
6999 static void
7000f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7001{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007002 char_u buf1[NUMBUFLEN];
7003 char_u buf2[NUMBUFLEN];
7004 char_u *from, *to, *str;
7005 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007006
7007 rettv->v_type = VAR_STRING;
7008 rettv->vval.v_string = NULL;
7009
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007010 str = tv_get_string(&argvars[0]);
7011 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7012 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007013 vimconv.vc_type = CONV_NONE;
7014 convert_setup(&vimconv, from, to);
7015
7016 /* If the encodings are equal, no conversion needed. */
7017 if (vimconv.vc_type == CONV_NONE)
7018 rettv->vval.v_string = vim_strsave(str);
7019 else
7020 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7021
7022 convert_setup(&vimconv, NULL, NULL);
7023 vim_free(from);
7024 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025}
7026
7027/*
7028 * "indent()" function
7029 */
7030 static void
7031f_indent(typval_T *argvars, typval_T *rettv)
7032{
7033 linenr_T lnum;
7034
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007035 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7037 rettv->vval.v_number = get_indent_lnum(lnum);
7038 else
7039 rettv->vval.v_number = -1;
7040}
7041
7042/*
7043 * "index()" function
7044 */
7045 static void
7046f_index(typval_T *argvars, typval_T *rettv)
7047{
7048 list_T *l;
7049 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007050 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007051 long idx = 0;
7052 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007053 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007054
7055 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007056 if (argvars[0].v_type == VAR_BLOB)
7057 {
7058 typval_T tv;
7059 int start = 0;
7060
7061 if (argvars[2].v_type != VAR_UNKNOWN)
7062 {
7063 start = tv_get_number_chk(&argvars[2], &error);
7064 if (error)
7065 return;
7066 }
7067 b = argvars[0].vval.v_blob;
7068 if (b == NULL)
7069 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007070 if (start < 0)
7071 {
7072 start = blob_len(b) + start;
7073 if (start < 0)
7074 start = 0;
7075 }
7076
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007077 for (idx = start; idx < blob_len(b); ++idx)
7078 {
7079 tv.v_type = VAR_NUMBER;
7080 tv.vval.v_number = blob_get(b, idx);
7081 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7082 {
7083 rettv->vval.v_number = idx;
7084 return;
7085 }
7086 }
7087 return;
7088 }
7089 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007090 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007091 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 return;
7093 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007094
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 l = argvars[0].vval.v_list;
7096 if (l != NULL)
7097 {
7098 item = l->lv_first;
7099 if (argvars[2].v_type != VAR_UNKNOWN)
7100 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007101 /* Start at specified item. Use the cached index that list_find()
7102 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007103 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007104 idx = l->lv_idx;
7105 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007106 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007107 if (error)
7108 item = NULL;
7109 }
7110
7111 for ( ; item != NULL; item = item->li_next, ++idx)
7112 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7113 {
7114 rettv->vval.v_number = idx;
7115 break;
7116 }
7117 }
7118}
7119
7120static int inputsecret_flag = 0;
7121
7122/*
7123 * "input()" function
7124 * Also handles inputsecret() when inputsecret is set.
7125 */
7126 static void
7127f_input(typval_T *argvars, typval_T *rettv)
7128{
7129 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7130}
7131
7132/*
7133 * "inputdialog()" function
7134 */
7135 static void
7136f_inputdialog(typval_T *argvars, typval_T *rettv)
7137{
7138#if defined(FEAT_GUI_TEXTDIALOG)
7139 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7140 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7141 {
7142 char_u *message;
7143 char_u buf[NUMBUFLEN];
7144 char_u *defstr = (char_u *)"";
7145
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007146 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007147 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007148 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7150 else
7151 IObuff[0] = NUL;
7152 if (message != NULL && defstr != NULL
7153 && do_dialog(VIM_QUESTION, NULL, message,
7154 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7155 rettv->vval.v_string = vim_strsave(IObuff);
7156 else
7157 {
7158 if (message != NULL && defstr != NULL
7159 && argvars[1].v_type != VAR_UNKNOWN
7160 && argvars[2].v_type != VAR_UNKNOWN)
7161 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007162 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007163 else
7164 rettv->vval.v_string = NULL;
7165 }
7166 rettv->v_type = VAR_STRING;
7167 }
7168 else
7169#endif
7170 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7171}
7172
7173/*
7174 * "inputlist()" function
7175 */
7176 static void
7177f_inputlist(typval_T *argvars, typval_T *rettv)
7178{
7179 listitem_T *li;
7180 int selected;
7181 int mouse_used;
7182
7183#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007184 /* While starting up, there is no place to enter text. When running tests
7185 * with --not-a-term we assume feedkeys() will be used. */
7186 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187 return;
7188#endif
7189 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7190 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007191 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007192 return;
7193 }
7194
7195 msg_start();
7196 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7197 lines_left = Rows; /* avoid more prompt */
7198 msg_scroll = TRUE;
7199 msg_clr_eos();
7200
7201 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7202 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007203 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007204 msg_putchar('\n');
7205 }
7206
7207 /* Ask for choice. */
7208 selected = prompt_for_number(&mouse_used);
7209 if (mouse_used)
7210 selected -= lines_left;
7211
7212 rettv->vval.v_number = selected;
7213}
7214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7216
7217/*
7218 * "inputrestore()" function
7219 */
7220 static void
7221f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7222{
7223 if (ga_userinput.ga_len > 0)
7224 {
7225 --ga_userinput.ga_len;
7226 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7227 + ga_userinput.ga_len);
7228 /* default return is zero == OK */
7229 }
7230 else if (p_verbose > 1)
7231 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007232 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 rettv->vval.v_number = 1; /* Failed */
7234 }
7235}
7236
7237/*
7238 * "inputsave()" function
7239 */
7240 static void
7241f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7242{
7243 /* Add an entry to the stack of typeahead storage. */
7244 if (ga_grow(&ga_userinput, 1) == OK)
7245 {
7246 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7247 + ga_userinput.ga_len);
7248 ++ga_userinput.ga_len;
7249 /* default return is zero == OK */
7250 }
7251 else
7252 rettv->vval.v_number = 1; /* Failed */
7253}
7254
7255/*
7256 * "inputsecret()" function
7257 */
7258 static void
7259f_inputsecret(typval_T *argvars, typval_T *rettv)
7260{
7261 ++cmdline_star;
7262 ++inputsecret_flag;
7263 f_input(argvars, rettv);
7264 --cmdline_star;
7265 --inputsecret_flag;
7266}
7267
7268/*
7269 * "insert()" function
7270 */
7271 static void
7272f_insert(typval_T *argvars, typval_T *rettv)
7273{
7274 long before = 0;
7275 listitem_T *item;
7276 list_T *l;
7277 int error = FALSE;
7278
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007279 if (argvars[0].v_type == VAR_BLOB)
7280 {
7281 int val, len;
7282 char_u *p;
7283
7284 len = blob_len(argvars[0].vval.v_blob);
7285 if (argvars[2].v_type != VAR_UNKNOWN)
7286 {
7287 before = (long)tv_get_number_chk(&argvars[2], &error);
7288 if (error)
7289 return; // type error; errmsg already given
7290 if (before < 0 || before > len)
7291 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007292 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007293 return;
7294 }
7295 }
7296 val = tv_get_number_chk(&argvars[1], &error);
7297 if (error)
7298 return;
7299 if (val < 0 || val > 255)
7300 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007301 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007302 return;
7303 }
7304
7305 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7306 return;
7307 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7308 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7309 *(p + before) = val;
7310 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7311
7312 copy_tv(&argvars[0], rettv);
7313 }
7314 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007315 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007316 else if ((l = argvars[0].vval.v_list) != NULL
7317 && !var_check_lock(l->lv_lock,
7318 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 {
7320 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007321 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007322 if (error)
7323 return; /* type error; errmsg already given */
7324
7325 if (before == l->lv_len)
7326 item = NULL;
7327 else
7328 {
7329 item = list_find(l, before);
7330 if (item == NULL)
7331 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007332 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333 l = NULL;
7334 }
7335 }
7336 if (l != NULL)
7337 {
7338 list_insert_tv(l, &argvars[1], item);
7339 copy_tv(&argvars[0], rettv);
7340 }
7341 }
7342}
7343
7344/*
7345 * "invert(expr)" function
7346 */
7347 static void
7348f_invert(typval_T *argvars, typval_T *rettv)
7349{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007350 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351}
7352
7353/*
7354 * "isdirectory()" function
7355 */
7356 static void
7357f_isdirectory(typval_T *argvars, typval_T *rettv)
7358{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007359 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007360}
7361
7362/*
7363 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7364 * or it refers to a List or Dictionary that is locked.
7365 */
7366 static int
7367tv_islocked(typval_T *tv)
7368{
7369 return (tv->v_lock & VAR_LOCKED)
7370 || (tv->v_type == VAR_LIST
7371 && tv->vval.v_list != NULL
7372 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7373 || (tv->v_type == VAR_DICT
7374 && tv->vval.v_dict != NULL
7375 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7376}
7377
7378/*
7379 * "islocked()" function
7380 */
7381 static void
7382f_islocked(typval_T *argvars, typval_T *rettv)
7383{
7384 lval_T lv;
7385 char_u *end;
7386 dictitem_T *di;
7387
7388 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007389 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007390 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007391 if (end != NULL && lv.ll_name != NULL)
7392 {
7393 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007394 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007395 else
7396 {
7397 if (lv.ll_tv == NULL)
7398 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007399 di = find_var(lv.ll_name, NULL, TRUE);
7400 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007401 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007402 /* Consider a variable locked when:
7403 * 1. the variable itself is locked
7404 * 2. the value of the variable is locked.
7405 * 3. the List or Dict value is locked.
7406 */
7407 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7408 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 }
7410 }
7411 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007412 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007413 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007414 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 else if (lv.ll_list != NULL)
7416 /* List item. */
7417 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7418 else
7419 /* Dictionary item. */
7420 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7421 }
7422 }
7423
7424 clear_lval(&lv);
7425}
7426
7427#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7428/*
7429 * "isnan()" function
7430 */
7431 static void
7432f_isnan(typval_T *argvars, typval_T *rettv)
7433{
7434 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7435 && isnan(argvars[0].vval.v_float);
7436}
7437#endif
7438
7439/*
7440 * "items(dict)" function
7441 */
7442 static void
7443f_items(typval_T *argvars, typval_T *rettv)
7444{
7445 dict_list(argvars, rettv, 2);
7446}
7447
7448#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7449/*
7450 * Get the job from the argument.
7451 * Returns NULL if the job is invalid.
7452 */
7453 static job_T *
7454get_job_arg(typval_T *tv)
7455{
7456 job_T *job;
7457
7458 if (tv->v_type != VAR_JOB)
7459 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007460 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007461 return NULL;
7462 }
7463 job = tv->vval.v_job;
7464
7465 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007466 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007467 return job;
7468}
7469
7470/*
7471 * "job_getchannel()" function
7472 */
7473 static void
7474f_job_getchannel(typval_T *argvars, typval_T *rettv)
7475{
7476 job_T *job = get_job_arg(&argvars[0]);
7477
7478 if (job != NULL)
7479 {
7480 rettv->v_type = VAR_CHANNEL;
7481 rettv->vval.v_channel = job->jv_channel;
7482 if (job->jv_channel != NULL)
7483 ++job->jv_channel->ch_refcount;
7484 }
7485}
7486
7487/*
7488 * "job_info()" function
7489 */
7490 static void
7491f_job_info(typval_T *argvars, typval_T *rettv)
7492{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007493 if (argvars[0].v_type != VAR_UNKNOWN)
7494 {
7495 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007496
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007497 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7498 job_info(job, rettv->vval.v_dict);
7499 }
7500 else if (rettv_list_alloc(rettv) == OK)
7501 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502}
7503
7504/*
7505 * "job_setoptions()" function
7506 */
7507 static void
7508f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7509{
7510 job_T *job = get_job_arg(&argvars[0]);
7511 jobopt_T opt;
7512
7513 if (job == NULL)
7514 return;
7515 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007516 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 job_set_options(job, &opt);
7518 free_job_options(&opt);
7519}
7520
7521/*
7522 * "job_start()" function
7523 */
7524 static void
7525f_job_start(typval_T *argvars, typval_T *rettv)
7526{
7527 rettv->v_type = VAR_JOB;
7528 if (check_restricted() || check_secure())
7529 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007530 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531}
7532
7533/*
7534 * "job_status()" function
7535 */
7536 static void
7537f_job_status(typval_T *argvars, typval_T *rettv)
7538{
7539 job_T *job = get_job_arg(&argvars[0]);
7540
7541 if (job != NULL)
7542 {
7543 rettv->v_type = VAR_STRING;
7544 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7545 }
7546}
7547
7548/*
7549 * "job_stop()" function
7550 */
7551 static void
7552f_job_stop(typval_T *argvars, typval_T *rettv)
7553{
7554 job_T *job = get_job_arg(&argvars[0]);
7555
7556 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007557 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558}
7559#endif
7560
7561/*
7562 * "join()" function
7563 */
7564 static void
7565f_join(typval_T *argvars, typval_T *rettv)
7566{
7567 garray_T ga;
7568 char_u *sep;
7569
7570 if (argvars[0].v_type != VAR_LIST)
7571 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007572 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007573 return;
7574 }
7575 if (argvars[0].vval.v_list == NULL)
7576 return;
7577 if (argvars[1].v_type == VAR_UNKNOWN)
7578 sep = (char_u *)" ";
7579 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007580 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581
7582 rettv->v_type = VAR_STRING;
7583
7584 if (sep != NULL)
7585 {
7586 ga_init2(&ga, (int)sizeof(char), 80);
7587 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7588 ga_append(&ga, NUL);
7589 rettv->vval.v_string = (char_u *)ga.ga_data;
7590 }
7591 else
7592 rettv->vval.v_string = NULL;
7593}
7594
7595/*
7596 * "js_decode()" function
7597 */
7598 static void
7599f_js_decode(typval_T *argvars, typval_T *rettv)
7600{
7601 js_read_T reader;
7602
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007603 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007604 reader.js_fill = NULL;
7605 reader.js_used = 0;
7606 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007607 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608}
7609
7610/*
7611 * "js_encode()" function
7612 */
7613 static void
7614f_js_encode(typval_T *argvars, typval_T *rettv)
7615{
7616 rettv->v_type = VAR_STRING;
7617 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7618}
7619
7620/*
7621 * "json_decode()" function
7622 */
7623 static void
7624f_json_decode(typval_T *argvars, typval_T *rettv)
7625{
7626 js_read_T reader;
7627
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007628 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007629 reader.js_fill = NULL;
7630 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007631 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632}
7633
7634/*
7635 * "json_encode()" function
7636 */
7637 static void
7638f_json_encode(typval_T *argvars, typval_T *rettv)
7639{
7640 rettv->v_type = VAR_STRING;
7641 rettv->vval.v_string = json_encode(&argvars[0], 0);
7642}
7643
7644/*
7645 * "keys()" function
7646 */
7647 static void
7648f_keys(typval_T *argvars, typval_T *rettv)
7649{
7650 dict_list(argvars, rettv, 0);
7651}
7652
7653/*
7654 * "last_buffer_nr()" function.
7655 */
7656 static void
7657f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7658{
7659 int n = 0;
7660 buf_T *buf;
7661
Bram Moolenaar29323592016-07-24 22:04:11 +02007662 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007663 if (n < buf->b_fnum)
7664 n = buf->b_fnum;
7665
7666 rettv->vval.v_number = n;
7667}
7668
7669/*
7670 * "len()" function
7671 */
7672 static void
7673f_len(typval_T *argvars, typval_T *rettv)
7674{
7675 switch (argvars[0].v_type)
7676 {
7677 case VAR_STRING:
7678 case VAR_NUMBER:
7679 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007680 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007681 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007682 case VAR_BLOB:
7683 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7684 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007685 case VAR_LIST:
7686 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7687 break;
7688 case VAR_DICT:
7689 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7690 break;
7691 case VAR_UNKNOWN:
7692 case VAR_SPECIAL:
7693 case VAR_FLOAT:
7694 case VAR_FUNC:
7695 case VAR_PARTIAL:
7696 case VAR_JOB:
7697 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007698 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007699 break;
7700 }
7701}
7702
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007703 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007704libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007705{
7706#ifdef FEAT_LIBCALL
7707 char_u *string_in;
7708 char_u **string_result;
7709 int nr_result;
7710#endif
7711
7712 rettv->v_type = type;
7713 if (type != VAR_NUMBER)
7714 rettv->vval.v_string = NULL;
7715
7716 if (check_restricted() || check_secure())
7717 return;
7718
7719#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007720 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7722 {
7723 string_in = NULL;
7724 if (argvars[2].v_type == VAR_STRING)
7725 string_in = argvars[2].vval.v_string;
7726 if (type == VAR_NUMBER)
7727 string_result = NULL;
7728 else
7729 string_result = &rettv->vval.v_string;
7730 if (mch_libcall(argvars[0].vval.v_string,
7731 argvars[1].vval.v_string,
7732 string_in,
7733 argvars[2].vval.v_number,
7734 string_result,
7735 &nr_result) == OK
7736 && type == VAR_NUMBER)
7737 rettv->vval.v_number = nr_result;
7738 }
7739#endif
7740}
7741
7742/*
7743 * "libcall()" function
7744 */
7745 static void
7746f_libcall(typval_T *argvars, typval_T *rettv)
7747{
7748 libcall_common(argvars, rettv, VAR_STRING);
7749}
7750
7751/*
7752 * "libcallnr()" function
7753 */
7754 static void
7755f_libcallnr(typval_T *argvars, typval_T *rettv)
7756{
7757 libcall_common(argvars, rettv, VAR_NUMBER);
7758}
7759
7760/*
7761 * "line(string)" function
7762 */
7763 static void
7764f_line(typval_T *argvars, typval_T *rettv)
7765{
7766 linenr_T lnum = 0;
7767 pos_T *fp;
7768 int fnum;
7769
7770 fp = var2fpos(&argvars[0], TRUE, &fnum);
7771 if (fp != NULL)
7772 lnum = fp->lnum;
7773 rettv->vval.v_number = lnum;
7774}
7775
7776/*
7777 * "line2byte(lnum)" function
7778 */
7779 static void
7780f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7781{
7782#ifndef FEAT_BYTEOFF
7783 rettv->vval.v_number = -1;
7784#else
7785 linenr_T lnum;
7786
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007787 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007788 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7789 rettv->vval.v_number = -1;
7790 else
7791 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7792 if (rettv->vval.v_number >= 0)
7793 ++rettv->vval.v_number;
7794#endif
7795}
7796
7797/*
7798 * "lispindent(lnum)" function
7799 */
7800 static void
7801f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7802{
7803#ifdef FEAT_LISP
7804 pos_T pos;
7805 linenr_T lnum;
7806
7807 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007808 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7810 {
7811 curwin->w_cursor.lnum = lnum;
7812 rettv->vval.v_number = get_lisp_indent();
7813 curwin->w_cursor = pos;
7814 }
7815 else
7816#endif
7817 rettv->vval.v_number = -1;
7818}
7819
7820/*
7821 * "localtime()" function
7822 */
7823 static void
7824f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7825{
7826 rettv->vval.v_number = (varnumber_T)time(NULL);
7827}
7828
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007829 static void
7830get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7831{
7832 char_u *keys;
7833 char_u *which;
7834 char_u buf[NUMBUFLEN];
7835 char_u *keys_buf = NULL;
7836 char_u *rhs;
7837 int mode;
7838 int abbr = FALSE;
7839 int get_dict = FALSE;
7840 mapblock_T *mp;
7841 int buffer_local;
7842
7843 /* return empty string for failure */
7844 rettv->v_type = VAR_STRING;
7845 rettv->vval.v_string = NULL;
7846
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007847 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 if (*keys == NUL)
7849 return;
7850
7851 if (argvars[1].v_type != VAR_UNKNOWN)
7852 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007853 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 if (argvars[2].v_type != VAR_UNKNOWN)
7855 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007856 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007858 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 }
7860 }
7861 else
7862 which = (char_u *)"";
7863 if (which == NULL)
7864 return;
7865
7866 mode = get_map_mode(&which, 0);
7867
7868 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7869 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7870 vim_free(keys_buf);
7871
7872 if (!get_dict)
7873 {
7874 /* Return a string. */
7875 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007876 {
7877 if (*rhs == NUL)
7878 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7879 else
7880 rettv->vval.v_string = str2special_save(rhs, FALSE);
7881 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882
7883 }
7884 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7885 {
7886 /* Return a dictionary. */
7887 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7888 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7889 dict_T *dict = rettv->vval.v_dict;
7890
Bram Moolenaare0be1672018-07-08 16:50:37 +02007891 dict_add_string(dict, "lhs", lhs);
7892 dict_add_string(dict, "rhs", mp->m_orig_str);
7893 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7894 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7895 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007896 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7897 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007898 dict_add_number(dict, "buffer", (long)buffer_local);
7899 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7900 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007901
7902 vim_free(lhs);
7903 vim_free(mapmode);
7904 }
7905}
7906
7907#ifdef FEAT_FLOAT
7908/*
7909 * "log()" function
7910 */
7911 static void
7912f_log(typval_T *argvars, typval_T *rettv)
7913{
7914 float_T f = 0.0;
7915
7916 rettv->v_type = VAR_FLOAT;
7917 if (get_float_arg(argvars, &f) == OK)
7918 rettv->vval.v_float = log(f);
7919 else
7920 rettv->vval.v_float = 0.0;
7921}
7922
7923/*
7924 * "log10()" function
7925 */
7926 static void
7927f_log10(typval_T *argvars, typval_T *rettv)
7928{
7929 float_T f = 0.0;
7930
7931 rettv->v_type = VAR_FLOAT;
7932 if (get_float_arg(argvars, &f) == OK)
7933 rettv->vval.v_float = log10(f);
7934 else
7935 rettv->vval.v_float = 0.0;
7936}
7937#endif
7938
7939#ifdef FEAT_LUA
7940/*
7941 * "luaeval()" function
7942 */
7943 static void
7944f_luaeval(typval_T *argvars, typval_T *rettv)
7945{
7946 char_u *str;
7947 char_u buf[NUMBUFLEN];
7948
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007949 if (check_restricted() || check_secure())
7950 return;
7951
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007952 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007953 do_luaeval(str, argvars + 1, rettv);
7954}
7955#endif
7956
7957/*
7958 * "map()" function
7959 */
7960 static void
7961f_map(typval_T *argvars, typval_T *rettv)
7962{
7963 filter_map(argvars, rettv, TRUE);
7964}
7965
7966/*
7967 * "maparg()" function
7968 */
7969 static void
7970f_maparg(typval_T *argvars, typval_T *rettv)
7971{
7972 get_maparg(argvars, rettv, TRUE);
7973}
7974
7975/*
7976 * "mapcheck()" function
7977 */
7978 static void
7979f_mapcheck(typval_T *argvars, typval_T *rettv)
7980{
7981 get_maparg(argvars, rettv, FALSE);
7982}
7983
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007984typedef enum
7985{
7986 MATCH_END, /* matchend() */
7987 MATCH_MATCH, /* match() */
7988 MATCH_STR, /* matchstr() */
7989 MATCH_LIST, /* matchlist() */
7990 MATCH_POS /* matchstrpos() */
7991} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992
7993 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007994find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995{
7996 char_u *str = NULL;
7997 long len = 0;
7998 char_u *expr = NULL;
7999 char_u *pat;
8000 regmatch_T regmatch;
8001 char_u patbuf[NUMBUFLEN];
8002 char_u strbuf[NUMBUFLEN];
8003 char_u *save_cpo;
8004 long start = 0;
8005 long nth = 1;
8006 colnr_T startcol = 0;
8007 int match = 0;
8008 list_T *l = NULL;
8009 listitem_T *li = NULL;
8010 long idx = 0;
8011 char_u *tofree = NULL;
8012
8013 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8014 save_cpo = p_cpo;
8015 p_cpo = (char_u *)"";
8016
8017 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008018 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008020 /* type MATCH_LIST: return empty list when there are no matches.
8021 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022 if (rettv_list_alloc(rettv) == FAIL)
8023 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008024 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008025 && (list_append_string(rettv->vval.v_list,
8026 (char_u *)"", 0) == FAIL
8027 || list_append_number(rettv->vval.v_list,
8028 (varnumber_T)-1) == FAIL
8029 || list_append_number(rettv->vval.v_list,
8030 (varnumber_T)-1) == FAIL
8031 || list_append_number(rettv->vval.v_list,
8032 (varnumber_T)-1) == FAIL))
8033 {
8034 list_free(rettv->vval.v_list);
8035 rettv->vval.v_list = NULL;
8036 goto theend;
8037 }
8038 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008039 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040 {
8041 rettv->v_type = VAR_STRING;
8042 rettv->vval.v_string = NULL;
8043 }
8044
8045 if (argvars[0].v_type == VAR_LIST)
8046 {
8047 if ((l = argvars[0].vval.v_list) == NULL)
8048 goto theend;
8049 li = l->lv_first;
8050 }
8051 else
8052 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008053 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054 len = (long)STRLEN(str);
8055 }
8056
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008057 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008058 if (pat == NULL)
8059 goto theend;
8060
8061 if (argvars[2].v_type != VAR_UNKNOWN)
8062 {
8063 int error = FALSE;
8064
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008065 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 if (error)
8067 goto theend;
8068 if (l != NULL)
8069 {
8070 li = list_find(l, start);
8071 if (li == NULL)
8072 goto theend;
8073 idx = l->lv_idx; /* use the cached index */
8074 }
8075 else
8076 {
8077 if (start < 0)
8078 start = 0;
8079 if (start > len)
8080 goto theend;
8081 /* When "count" argument is there ignore matches before "start",
8082 * otherwise skip part of the string. Differs when pattern is "^"
8083 * or "\<". */
8084 if (argvars[3].v_type != VAR_UNKNOWN)
8085 startcol = start;
8086 else
8087 {
8088 str += start;
8089 len -= start;
8090 }
8091 }
8092
8093 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008094 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095 if (error)
8096 goto theend;
8097 }
8098
8099 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8100 if (regmatch.regprog != NULL)
8101 {
8102 regmatch.rm_ic = p_ic;
8103
8104 for (;;)
8105 {
8106 if (l != NULL)
8107 {
8108 if (li == NULL)
8109 {
8110 match = FALSE;
8111 break;
8112 }
8113 vim_free(tofree);
8114 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8115 if (str == NULL)
8116 break;
8117 }
8118
8119 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8120
8121 if (match && --nth <= 0)
8122 break;
8123 if (l == NULL && !match)
8124 break;
8125
8126 /* Advance to just after the match. */
8127 if (l != NULL)
8128 {
8129 li = li->li_next;
8130 ++idx;
8131 }
8132 else
8133 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008134 startcol = (colnr_T)(regmatch.startp[0]
8135 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136 if (startcol > (colnr_T)len
8137 || str + startcol <= regmatch.startp[0])
8138 {
8139 match = FALSE;
8140 break;
8141 }
8142 }
8143 }
8144
8145 if (match)
8146 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008147 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 {
8149 listitem_T *li1 = rettv->vval.v_list->lv_first;
8150 listitem_T *li2 = li1->li_next;
8151 listitem_T *li3 = li2->li_next;
8152 listitem_T *li4 = li3->li_next;
8153
8154 vim_free(li1->li_tv.vval.v_string);
8155 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8156 (int)(regmatch.endp[0] - regmatch.startp[0]));
8157 li3->li_tv.vval.v_number =
8158 (varnumber_T)(regmatch.startp[0] - expr);
8159 li4->li_tv.vval.v_number =
8160 (varnumber_T)(regmatch.endp[0] - expr);
8161 if (l != NULL)
8162 li2->li_tv.vval.v_number = (varnumber_T)idx;
8163 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008164 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165 {
8166 int i;
8167
8168 /* return list with matched string and submatches */
8169 for (i = 0; i < NSUBEXP; ++i)
8170 {
8171 if (regmatch.endp[i] == NULL)
8172 {
8173 if (list_append_string(rettv->vval.v_list,
8174 (char_u *)"", 0) == FAIL)
8175 break;
8176 }
8177 else if (list_append_string(rettv->vval.v_list,
8178 regmatch.startp[i],
8179 (int)(regmatch.endp[i] - regmatch.startp[i]))
8180 == FAIL)
8181 break;
8182 }
8183 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008184 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008185 {
8186 /* return matched string */
8187 if (l != NULL)
8188 copy_tv(&li->li_tv, rettv);
8189 else
8190 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8191 (int)(regmatch.endp[0] - regmatch.startp[0]));
8192 }
8193 else if (l != NULL)
8194 rettv->vval.v_number = idx;
8195 else
8196 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008197 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198 rettv->vval.v_number =
8199 (varnumber_T)(regmatch.startp[0] - str);
8200 else
8201 rettv->vval.v_number =
8202 (varnumber_T)(regmatch.endp[0] - str);
8203 rettv->vval.v_number += (varnumber_T)(str - expr);
8204 }
8205 }
8206 vim_regfree(regmatch.regprog);
8207 }
8208
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008209theend:
8210 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 /* matchstrpos() without a list: drop the second item. */
8212 listitem_remove(rettv->vval.v_list,
8213 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008214 vim_free(tofree);
8215 p_cpo = save_cpo;
8216}
8217
8218/*
8219 * "match()" function
8220 */
8221 static void
8222f_match(typval_T *argvars, typval_T *rettv)
8223{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008224 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225}
8226
Bram Moolenaar95e51472018-07-28 16:55:56 +02008227#ifdef FEAT_SEARCH_EXTRA
8228 static int
8229matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8230{
8231 dictitem_T *di;
8232
8233 if (tv->v_type != VAR_DICT)
8234 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008235 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008236 return FAIL;
8237 }
8238
8239 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008240 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008241 (char_u *)"conceal", FALSE);
8242
8243 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8244 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008245 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008246 if (*win == NULL)
8247 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008248 emsg(_("E957: Invalid window number"));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008249 return FAIL;
8250 }
8251 }
8252
8253 return OK;
8254}
8255#endif
8256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257/*
8258 * "matchadd()" function
8259 */
8260 static void
8261f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8262{
8263#ifdef FEAT_SEARCH_EXTRA
8264 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008265 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8266 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008267 int prio = 10; /* default priority */
8268 int id = -1;
8269 int error = FALSE;
8270 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008271 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272
8273 rettv->vval.v_number = -1;
8274
8275 if (grp == NULL || pat == NULL)
8276 return;
8277 if (argvars[2].v_type != VAR_UNKNOWN)
8278 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008279 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008280 if (argvars[3].v_type != VAR_UNKNOWN)
8281 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008282 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008283 if (argvars[4].v_type != VAR_UNKNOWN
8284 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8285 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008286 }
8287 }
8288 if (error == TRUE)
8289 return;
8290 if (id >= 1 && id <= 3)
8291 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008292 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008293 return;
8294 }
8295
Bram Moolenaar95e51472018-07-28 16:55:56 +02008296 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008297 conceal_char);
8298#endif
8299}
8300
8301/*
8302 * "matchaddpos()" function
8303 */
8304 static void
8305f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8306{
8307#ifdef FEAT_SEARCH_EXTRA
8308 char_u buf[NUMBUFLEN];
8309 char_u *group;
8310 int prio = 10;
8311 int id = -1;
8312 int error = FALSE;
8313 list_T *l;
8314 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008315 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316
8317 rettv->vval.v_number = -1;
8318
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008319 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008320 if (group == NULL)
8321 return;
8322
8323 if (argvars[1].v_type != VAR_LIST)
8324 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008325 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326 return;
8327 }
8328 l = argvars[1].vval.v_list;
8329 if (l == NULL)
8330 return;
8331
8332 if (argvars[2].v_type != VAR_UNKNOWN)
8333 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008334 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335 if (argvars[3].v_type != VAR_UNKNOWN)
8336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008337 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008338
8339 if (argvars[4].v_type != VAR_UNKNOWN
8340 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8341 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 }
8343 }
8344 if (error == TRUE)
8345 return;
8346
8347 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8348 if (id == 1 || id == 2)
8349 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008350 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008351 return;
8352 }
8353
Bram Moolenaar95e51472018-07-28 16:55:56 +02008354 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 conceal_char);
8356#endif
8357}
8358
8359/*
8360 * "matcharg()" function
8361 */
8362 static void
8363f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8364{
8365 if (rettv_list_alloc(rettv) == OK)
8366 {
8367#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008368 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 matchitem_T *m;
8370
8371 if (id >= 1 && id <= 3)
8372 {
8373 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8374 {
8375 list_append_string(rettv->vval.v_list,
8376 syn_id2name(m->hlg_id), -1);
8377 list_append_string(rettv->vval.v_list, m->pattern, -1);
8378 }
8379 else
8380 {
8381 list_append_string(rettv->vval.v_list, NULL, -1);
8382 list_append_string(rettv->vval.v_list, NULL, -1);
8383 }
8384 }
8385#endif
8386 }
8387}
8388
8389/*
8390 * "matchdelete()" function
8391 */
8392 static void
8393f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8394{
8395#ifdef FEAT_SEARCH_EXTRA
8396 rettv->vval.v_number = match_delete(curwin,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008397 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398#endif
8399}
8400
8401/*
8402 * "matchend()" function
8403 */
8404 static void
8405f_matchend(typval_T *argvars, typval_T *rettv)
8406{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008407 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008408}
8409
8410/*
8411 * "matchlist()" function
8412 */
8413 static void
8414f_matchlist(typval_T *argvars, typval_T *rettv)
8415{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008416 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008417}
8418
8419/*
8420 * "matchstr()" function
8421 */
8422 static void
8423f_matchstr(typval_T *argvars, typval_T *rettv)
8424{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008425 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008426}
8427
8428/*
8429 * "matchstrpos()" function
8430 */
8431 static void
8432f_matchstrpos(typval_T *argvars, typval_T *rettv)
8433{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008434 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008435}
8436
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008437 static void
8438max_min(typval_T *argvars, typval_T *rettv, int domax)
8439{
8440 varnumber_T n = 0;
8441 varnumber_T i;
8442 int error = FALSE;
8443
8444 if (argvars[0].v_type == VAR_LIST)
8445 {
8446 list_T *l;
8447 listitem_T *li;
8448
8449 l = argvars[0].vval.v_list;
8450 if (l != NULL)
8451 {
8452 li = l->lv_first;
8453 if (li != NULL)
8454 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008455 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008456 for (;;)
8457 {
8458 li = li->li_next;
8459 if (li == NULL)
8460 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008461 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008462 if (domax ? i > n : i < n)
8463 n = i;
8464 }
8465 }
8466 }
8467 }
8468 else if (argvars[0].v_type == VAR_DICT)
8469 {
8470 dict_T *d;
8471 int first = TRUE;
8472 hashitem_T *hi;
8473 int todo;
8474
8475 d = argvars[0].vval.v_dict;
8476 if (d != NULL)
8477 {
8478 todo = (int)d->dv_hashtab.ht_used;
8479 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8480 {
8481 if (!HASHITEM_EMPTY(hi))
8482 {
8483 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008484 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008485 if (first)
8486 {
8487 n = i;
8488 first = FALSE;
8489 }
8490 else if (domax ? i > n : i < n)
8491 n = i;
8492 }
8493 }
8494 }
8495 }
8496 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008497 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498 rettv->vval.v_number = error ? 0 : n;
8499}
8500
8501/*
8502 * "max()" function
8503 */
8504 static void
8505f_max(typval_T *argvars, typval_T *rettv)
8506{
8507 max_min(argvars, rettv, TRUE);
8508}
8509
8510/*
8511 * "min()" function
8512 */
8513 static void
8514f_min(typval_T *argvars, typval_T *rettv)
8515{
8516 max_min(argvars, rettv, FALSE);
8517}
8518
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008519/*
8520 * Create the directory in which "dir" is located, and higher levels when
8521 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008522 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523 */
8524 static int
8525mkdir_recurse(char_u *dir, int prot)
8526{
8527 char_u *p;
8528 char_u *updir;
8529 int r = FAIL;
8530
8531 /* Get end of directory name in "dir".
8532 * We're done when it's "/" or "c:/". */
8533 p = gettail_sep(dir);
8534 if (p <= get_past_head(dir))
8535 return OK;
8536
8537 /* If the directory exists we're done. Otherwise: create it.*/
8538 updir = vim_strnsave(dir, (int)(p - dir));
8539 if (updir == NULL)
8540 return FAIL;
8541 if (mch_isdir(updir))
8542 r = OK;
8543 else if (mkdir_recurse(updir, prot) == OK)
8544 r = vim_mkdir_emsg(updir, prot);
8545 vim_free(updir);
8546 return r;
8547}
8548
8549#ifdef vim_mkdir
8550/*
8551 * "mkdir()" function
8552 */
8553 static void
8554f_mkdir(typval_T *argvars, typval_T *rettv)
8555{
8556 char_u *dir;
8557 char_u buf[NUMBUFLEN];
8558 int prot = 0755;
8559
8560 rettv->vval.v_number = FAIL;
8561 if (check_restricted() || check_secure())
8562 return;
8563
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008564 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008566 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008567
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008568 if (*gettail(dir) == NUL)
8569 /* remove trailing slashes */
8570 *gettail_sep(dir) = NUL;
8571
8572 if (argvars[1].v_type != VAR_UNKNOWN)
8573 {
8574 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008575 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008576 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008577 if (prot == -1)
8578 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008579 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008580 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008581 {
8582 if (mch_isdir(dir))
8583 {
8584 /* With the "p" flag it's OK if the dir already exists. */
8585 rettv->vval.v_number = OK;
8586 return;
8587 }
8588 mkdir_recurse(dir, prot);
8589 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008590 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008591 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008592}
8593#endif
8594
8595/*
8596 * "mode()" function
8597 */
8598 static void
8599f_mode(typval_T *argvars, typval_T *rettv)
8600{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008601 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008602
Bram Moolenaar612cc382018-07-29 15:34:26 +02008603 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008604
8605 if (time_for_testing == 93784)
8606 {
8607 /* Testing the two-character code. */
8608 buf[0] = 'x';
8609 buf[1] = '!';
8610 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008611#ifdef FEAT_TERMINAL
8612 else if (term_use_loop())
8613 buf[0] = 't';
8614#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008615 else if (VIsual_active)
8616 {
8617 if (VIsual_select)
8618 buf[0] = VIsual_mode + 's' - 'v';
8619 else
8620 buf[0] = VIsual_mode;
8621 }
8622 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8623 || State == CONFIRM)
8624 {
8625 buf[0] = 'r';
8626 if (State == ASKMORE)
8627 buf[1] = 'm';
8628 else if (State == CONFIRM)
8629 buf[1] = '?';
8630 }
8631 else if (State == EXTERNCMD)
8632 buf[0] = '!';
8633 else if (State & INSERT)
8634 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008635 if (State & VREPLACE_FLAG)
8636 {
8637 buf[0] = 'R';
8638 buf[1] = 'v';
8639 }
8640 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008641 {
8642 if (State & REPLACE_FLAG)
8643 buf[0] = 'R';
8644 else
8645 buf[0] = 'i';
8646#ifdef FEAT_INS_EXPAND
8647 if (ins_compl_active())
8648 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008649 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008650 buf[1] = 'x';
8651#endif
8652 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008653 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008654 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008655 {
8656 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008657 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008658 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008659 else if (exmode_active == EXMODE_NORMAL)
8660 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008661 }
8662 else
8663 {
8664 buf[0] = 'n';
8665 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008666 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008667 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008668 // to be able to detect force-linewise/blockwise/characterwise operations
8669 buf[2] = motion_force;
8670 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008671 else if (restart_edit == 'I' || restart_edit == 'R'
8672 || restart_edit == 'V')
8673 {
8674 buf[1] = 'i';
8675 buf[2] = restart_edit;
8676 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008677 }
8678
8679 /* Clear out the minor mode when the argument is not a non-zero number or
8680 * non-empty string. */
8681 if (!non_zero_arg(&argvars[0]))
8682 buf[1] = NUL;
8683
8684 rettv->vval.v_string = vim_strsave(buf);
8685 rettv->v_type = VAR_STRING;
8686}
8687
8688#if defined(FEAT_MZSCHEME) || defined(PROTO)
8689/*
8690 * "mzeval()" function
8691 */
8692 static void
8693f_mzeval(typval_T *argvars, typval_T *rettv)
8694{
8695 char_u *str;
8696 char_u buf[NUMBUFLEN];
8697
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008698 if (check_restricted() || check_secure())
8699 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008700 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008701 do_mzeval(str, rettv);
8702}
8703
8704 void
8705mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8706{
8707 typval_T argvars[3];
8708
8709 argvars[0].v_type = VAR_STRING;
8710 argvars[0].vval.v_string = name;
8711 copy_tv(args, &argvars[1]);
8712 argvars[2].v_type = VAR_UNKNOWN;
8713 f_call(argvars, rettv);
8714 clear_tv(&argvars[1]);
8715}
8716#endif
8717
8718/*
8719 * "nextnonblank()" function
8720 */
8721 static void
8722f_nextnonblank(typval_T *argvars, typval_T *rettv)
8723{
8724 linenr_T lnum;
8725
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008726 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008727 {
8728 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8729 {
8730 lnum = 0;
8731 break;
8732 }
8733 if (*skipwhite(ml_get(lnum)) != NUL)
8734 break;
8735 }
8736 rettv->vval.v_number = lnum;
8737}
8738
8739/*
8740 * "nr2char()" function
8741 */
8742 static void
8743f_nr2char(typval_T *argvars, typval_T *rettv)
8744{
8745 char_u buf[NUMBUFLEN];
8746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008747 if (has_mbyte)
8748 {
8749 int utf8 = 0;
8750
8751 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008752 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008753 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008754 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008755 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008756 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008757 }
8758 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008759 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008760 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761 buf[1] = NUL;
8762 }
8763 rettv->v_type = VAR_STRING;
8764 rettv->vval.v_string = vim_strsave(buf);
8765}
8766
8767/*
8768 * "or(expr, expr)" function
8769 */
8770 static void
8771f_or(typval_T *argvars, typval_T *rettv)
8772{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008773 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8774 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008775}
8776
8777/*
8778 * "pathshorten()" function
8779 */
8780 static void
8781f_pathshorten(typval_T *argvars, typval_T *rettv)
8782{
8783 char_u *p;
8784
8785 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008786 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008787 if (p == NULL)
8788 rettv->vval.v_string = NULL;
8789 else
8790 {
8791 p = vim_strsave(p);
8792 rettv->vval.v_string = p;
8793 if (p != NULL)
8794 shorten_dir(p);
8795 }
8796}
8797
8798#ifdef FEAT_PERL
8799/*
8800 * "perleval()" function
8801 */
8802 static void
8803f_perleval(typval_T *argvars, typval_T *rettv)
8804{
8805 char_u *str;
8806 char_u buf[NUMBUFLEN];
8807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008808 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008809 do_perleval(str, rettv);
8810}
8811#endif
8812
8813#ifdef FEAT_FLOAT
8814/*
8815 * "pow()" function
8816 */
8817 static void
8818f_pow(typval_T *argvars, typval_T *rettv)
8819{
8820 float_T fx = 0.0, fy = 0.0;
8821
8822 rettv->v_type = VAR_FLOAT;
8823 if (get_float_arg(argvars, &fx) == OK
8824 && get_float_arg(&argvars[1], &fy) == OK)
8825 rettv->vval.v_float = pow(fx, fy);
8826 else
8827 rettv->vval.v_float = 0.0;
8828}
8829#endif
8830
8831/*
8832 * "prevnonblank()" function
8833 */
8834 static void
8835f_prevnonblank(typval_T *argvars, typval_T *rettv)
8836{
8837 linenr_T lnum;
8838
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008839 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008840 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8841 lnum = 0;
8842 else
8843 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8844 --lnum;
8845 rettv->vval.v_number = lnum;
8846}
8847
8848/* This dummy va_list is here because:
8849 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8850 * - locally in the function results in a "used before set" warning
8851 * - using va_start() to initialize it gives "function with fixed args" error */
8852static va_list ap;
8853
8854/*
8855 * "printf()" function
8856 */
8857 static void
8858f_printf(typval_T *argvars, typval_T *rettv)
8859{
8860 char_u buf[NUMBUFLEN];
8861 int len;
8862 char_u *s;
8863 int saved_did_emsg = did_emsg;
8864 char *fmt;
8865
8866 rettv->v_type = VAR_STRING;
8867 rettv->vval.v_string = NULL;
8868
8869 /* Get the required length, allocate the buffer and do it for real. */
8870 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008871 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008872 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008873 if (!did_emsg)
8874 {
8875 s = alloc(len + 1);
8876 if (s != NULL)
8877 {
8878 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008879 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8880 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008881 }
8882 }
8883 did_emsg |= saved_did_emsg;
8884}
8885
Bram Moolenaarf2732452018-06-03 14:47:35 +02008886#ifdef FEAT_JOB_CHANNEL
8887/*
8888 * "prompt_setcallback({buffer}, {callback})" function
8889 */
8890 static void
8891f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8892{
8893 buf_T *buf;
8894 char_u *callback;
8895 partial_T *partial;
8896
8897 if (check_secure())
8898 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008899 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008900 if (buf == NULL)
8901 return;
8902
8903 callback = get_callback(&argvars[1], &partial);
8904 if (callback == NULL)
8905 return;
8906
8907 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8908 if (partial == NULL)
8909 buf->b_prompt_callback = vim_strsave(callback);
8910 else
8911 /* pointer into the partial */
8912 buf->b_prompt_callback = callback;
8913 buf->b_prompt_partial = partial;
8914}
8915
8916/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008917 * "prompt_setinterrupt({buffer}, {callback})" function
8918 */
8919 static void
8920f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8921{
8922 buf_T *buf;
8923 char_u *callback;
8924 partial_T *partial;
8925
8926 if (check_secure())
8927 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008928 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008929 if (buf == NULL)
8930 return;
8931
8932 callback = get_callback(&argvars[1], &partial);
8933 if (callback == NULL)
8934 return;
8935
8936 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8937 if (partial == NULL)
8938 buf->b_prompt_interrupt = vim_strsave(callback);
8939 else
8940 /* pointer into the partial */
8941 buf->b_prompt_interrupt = callback;
8942 buf->b_prompt_int_partial = partial;
8943}
8944
8945/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008946 * "prompt_setprompt({buffer}, {text})" function
8947 */
8948 static void
8949f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8950{
8951 buf_T *buf;
8952 char_u *text;
8953
8954 if (check_secure())
8955 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008956 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008957 if (buf == NULL)
8958 return;
8959
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008960 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008961 vim_free(buf->b_prompt_text);
8962 buf->b_prompt_text = vim_strsave(text);
8963}
8964#endif
8965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008966/*
8967 * "pumvisible()" function
8968 */
8969 static void
8970f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8971{
8972#ifdef FEAT_INS_EXPAND
8973 if (pum_visible())
8974 rettv->vval.v_number = 1;
8975#endif
8976}
8977
8978#ifdef FEAT_PYTHON3
8979/*
8980 * "py3eval()" function
8981 */
8982 static void
8983f_py3eval(typval_T *argvars, typval_T *rettv)
8984{
8985 char_u *str;
8986 char_u buf[NUMBUFLEN];
8987
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008988 if (check_restricted() || check_secure())
8989 return;
8990
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008991 if (p_pyx == 0)
8992 p_pyx = 3;
8993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008994 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008995 do_py3eval(str, rettv);
8996}
8997#endif
8998
8999#ifdef FEAT_PYTHON
9000/*
9001 * "pyeval()" function
9002 */
9003 static void
9004f_pyeval(typval_T *argvars, typval_T *rettv)
9005{
9006 char_u *str;
9007 char_u buf[NUMBUFLEN];
9008
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009009 if (check_restricted() || check_secure())
9010 return;
9011
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009012 if (p_pyx == 0)
9013 p_pyx = 2;
9014
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009015 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009016 do_pyeval(str, rettv);
9017}
9018#endif
9019
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009020#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9021/*
9022 * "pyxeval()" function
9023 */
9024 static void
9025f_pyxeval(typval_T *argvars, typval_T *rettv)
9026{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009027 if (check_restricted() || check_secure())
9028 return;
9029
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009030# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9031 init_pyxversion();
9032 if (p_pyx == 2)
9033 f_pyeval(argvars, rettv);
9034 else
9035 f_py3eval(argvars, rettv);
9036# elif defined(FEAT_PYTHON)
9037 f_pyeval(argvars, rettv);
9038# elif defined(FEAT_PYTHON3)
9039 f_py3eval(argvars, rettv);
9040# endif
9041}
9042#endif
9043
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009044/*
9045 * "range()" function
9046 */
9047 static void
9048f_range(typval_T *argvars, typval_T *rettv)
9049{
9050 varnumber_T start;
9051 varnumber_T end;
9052 varnumber_T stride = 1;
9053 varnumber_T i;
9054 int error = FALSE;
9055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009056 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009057 if (argvars[1].v_type == VAR_UNKNOWN)
9058 {
9059 end = start - 1;
9060 start = 0;
9061 }
9062 else
9063 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009064 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009065 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009066 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009067 }
9068
9069 if (error)
9070 return; /* type error; errmsg already given */
9071 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009072 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009073 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009074 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009075 else
9076 {
9077 if (rettv_list_alloc(rettv) == OK)
9078 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9079 if (list_append_number(rettv->vval.v_list,
9080 (varnumber_T)i) == FAIL)
9081 break;
9082 }
9083}
9084
9085/*
9086 * "readfile()" function
9087 */
9088 static void
9089f_readfile(typval_T *argvars, typval_T *rettv)
9090{
9091 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009092 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009093 int failed = FALSE;
9094 char_u *fname;
9095 FILE *fd;
9096 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9097 int io_size = sizeof(buf);
9098 int readlen; /* size of last fread() */
9099 char_u *prev = NULL; /* previously read bytes, if any */
9100 long prevlen = 0; /* length of data in prev */
9101 long prevsize = 0; /* size of prev buffer */
9102 long maxline = MAXLNUM;
9103 long cnt = 0;
9104 char_u *p; /* position in buf */
9105 char_u *start; /* start of current line */
9106
9107 if (argvars[1].v_type != VAR_UNKNOWN)
9108 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009109 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009110 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009111 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9112 blob = TRUE;
9113
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009114 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009115 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009116 }
9117
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009118 if (blob)
9119 {
9120 if (rettv_blob_alloc(rettv) == FAIL)
9121 return;
9122 }
9123 else
9124 {
9125 if (rettv_list_alloc(rettv) == FAIL)
9126 return;
9127 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009128
9129 /* Always open the file in binary mode, library functions have a mind of
9130 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009131 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009132 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9133 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009134 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009135 return;
9136 }
9137
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009138 if (blob)
9139 {
9140 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9141 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009142 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009143 blob_free(rettv->vval.v_blob);
9144 }
9145 fclose(fd);
9146 return;
9147 }
9148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009149 while (cnt < maxline || maxline < 0)
9150 {
9151 readlen = (int)fread(buf, 1, io_size, fd);
9152
9153 /* This for loop processes what was read, but is also entered at end
9154 * of file so that either:
9155 * - an incomplete line gets written
9156 * - a "binary" file gets an empty line at the end if it ends in a
9157 * newline. */
9158 for (p = buf, start = buf;
9159 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9160 ++p)
9161 {
9162 if (*p == '\n' || readlen <= 0)
9163 {
9164 listitem_T *li;
9165 char_u *s = NULL;
9166 long_u len = p - start;
9167
9168 /* Finished a line. Remove CRs before NL. */
9169 if (readlen > 0 && !binary)
9170 {
9171 while (len > 0 && start[len - 1] == '\r')
9172 --len;
9173 /* removal may cross back to the "prev" string */
9174 if (len == 0)
9175 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9176 --prevlen;
9177 }
9178 if (prevlen == 0)
9179 s = vim_strnsave(start, (int)len);
9180 else
9181 {
9182 /* Change "prev" buffer to be the right size. This way
9183 * the bytes are only copied once, and very long lines are
9184 * allocated only once. */
9185 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9186 {
9187 mch_memmove(s + prevlen, start, len);
9188 s[prevlen + len] = NUL;
9189 prev = NULL; /* the list will own the string */
9190 prevlen = prevsize = 0;
9191 }
9192 }
9193 if (s == NULL)
9194 {
9195 do_outofmem_msg((long_u) prevlen + len + 1);
9196 failed = TRUE;
9197 break;
9198 }
9199
9200 if ((li = listitem_alloc()) == NULL)
9201 {
9202 vim_free(s);
9203 failed = TRUE;
9204 break;
9205 }
9206 li->li_tv.v_type = VAR_STRING;
9207 li->li_tv.v_lock = 0;
9208 li->li_tv.vval.v_string = s;
9209 list_append(rettv->vval.v_list, li);
9210
9211 start = p + 1; /* step over newline */
9212 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9213 break;
9214 }
9215 else if (*p == NUL)
9216 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009217 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9218 * when finding the BF and check the previous two bytes. */
9219 else if (*p == 0xbf && enc_utf8 && !binary)
9220 {
9221 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9222 * + 1, these may be in the "prev" string. */
9223 char_u back1 = p >= buf + 1 ? p[-1]
9224 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9225 char_u back2 = p >= buf + 2 ? p[-2]
9226 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9227 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9228
9229 if (back2 == 0xef && back1 == 0xbb)
9230 {
9231 char_u *dest = p - 2;
9232
9233 /* Usually a BOM is at the beginning of a file, and so at
9234 * the beginning of a line; then we can just step over it.
9235 */
9236 if (start == dest)
9237 start = p + 1;
9238 else
9239 {
9240 /* have to shuffle buf to close gap */
9241 int adjust_prevlen = 0;
9242
9243 if (dest < buf)
9244 {
9245 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9246 dest = buf;
9247 }
9248 if (readlen > p - buf + 1)
9249 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9250 readlen -= 3 - adjust_prevlen;
9251 prevlen -= adjust_prevlen;
9252 p = dest - 1;
9253 }
9254 }
9255 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009256 } /* for */
9257
9258 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9259 break;
9260 if (start < p)
9261 {
9262 /* There's part of a line in buf, store it in "prev". */
9263 if (p - start + prevlen >= prevsize)
9264 {
9265 /* need bigger "prev" buffer */
9266 char_u *newprev;
9267
9268 /* A common use case is ordinary text files and "prev" gets a
9269 * fragment of a line, so the first allocation is made
9270 * small, to avoid repeatedly 'allocing' large and
9271 * 'reallocing' small. */
9272 if (prevsize == 0)
9273 prevsize = (long)(p - start);
9274 else
9275 {
9276 long grow50pc = (prevsize * 3) / 2;
9277 long growmin = (long)((p - start) * 2 + prevlen);
9278 prevsize = grow50pc > growmin ? grow50pc : growmin;
9279 }
9280 newprev = prev == NULL ? alloc(prevsize)
9281 : vim_realloc(prev, prevsize);
9282 if (newprev == NULL)
9283 {
9284 do_outofmem_msg((long_u)prevsize);
9285 failed = TRUE;
9286 break;
9287 }
9288 prev = newprev;
9289 }
9290 /* Add the line part to end of "prev". */
9291 mch_memmove(prev + prevlen, start, p - start);
9292 prevlen += (long)(p - start);
9293 }
9294 } /* while */
9295
9296 /*
9297 * For a negative line count use only the lines at the end of the file,
9298 * free the rest.
9299 */
9300 if (!failed && maxline < 0)
9301 while (cnt > -maxline)
9302 {
9303 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9304 --cnt;
9305 }
9306
9307 if (failed)
9308 {
9309 list_free(rettv->vval.v_list);
9310 /* readfile doc says an empty list is returned on error */
9311 rettv->vval.v_list = list_alloc();
9312 }
9313
9314 vim_free(prev);
9315 fclose(fd);
9316}
9317
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009318 static void
9319return_register(int regname, typval_T *rettv)
9320{
9321 char_u buf[2] = {0, 0};
9322
9323 buf[0] = (char_u)regname;
9324 rettv->v_type = VAR_STRING;
9325 rettv->vval.v_string = vim_strsave(buf);
9326}
9327
9328/*
9329 * "reg_executing()" function
9330 */
9331 static void
9332f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9333{
9334 return_register(reg_executing, rettv);
9335}
9336
9337/*
9338 * "reg_recording()" function
9339 */
9340 static void
9341f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9342{
9343 return_register(reg_recording, rettv);
9344}
9345
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009346#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009347/*
9348 * Convert a List to proftime_T.
9349 * Return FAIL when there is something wrong.
9350 */
9351 static int
9352list2proftime(typval_T *arg, proftime_T *tm)
9353{
9354 long n1, n2;
9355 int error = FALSE;
9356
9357 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9358 || arg->vval.v_list->lv_len != 2)
9359 return FAIL;
9360 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9361 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009362# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009363 tm->HighPart = n1;
9364 tm->LowPart = n2;
9365# else
9366 tm->tv_sec = n1;
9367 tm->tv_usec = n2;
9368# endif
9369 return error ? FAIL : OK;
9370}
9371#endif /* FEAT_RELTIME */
9372
9373/*
9374 * "reltime()" function
9375 */
9376 static void
9377f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9378{
9379#ifdef FEAT_RELTIME
9380 proftime_T res;
9381 proftime_T start;
9382
9383 if (argvars[0].v_type == VAR_UNKNOWN)
9384 {
9385 /* No arguments: get current time. */
9386 profile_start(&res);
9387 }
9388 else if (argvars[1].v_type == VAR_UNKNOWN)
9389 {
9390 if (list2proftime(&argvars[0], &res) == FAIL)
9391 return;
9392 profile_end(&res);
9393 }
9394 else
9395 {
9396 /* Two arguments: compute the difference. */
9397 if (list2proftime(&argvars[0], &start) == FAIL
9398 || list2proftime(&argvars[1], &res) == FAIL)
9399 return;
9400 profile_sub(&res, &start);
9401 }
9402
9403 if (rettv_list_alloc(rettv) == OK)
9404 {
9405 long n1, n2;
9406
Bram Moolenaar4f974752019-02-17 17:44:42 +01009407# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009408 n1 = res.HighPart;
9409 n2 = res.LowPart;
9410# else
9411 n1 = res.tv_sec;
9412 n2 = res.tv_usec;
9413# endif
9414 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9415 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9416 }
9417#endif
9418}
9419
9420#ifdef FEAT_FLOAT
9421/*
9422 * "reltimefloat()" function
9423 */
9424 static void
9425f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9426{
9427# ifdef FEAT_RELTIME
9428 proftime_T tm;
9429# endif
9430
9431 rettv->v_type = VAR_FLOAT;
9432 rettv->vval.v_float = 0;
9433# ifdef FEAT_RELTIME
9434 if (list2proftime(&argvars[0], &tm) == OK)
9435 rettv->vval.v_float = profile_float(&tm);
9436# endif
9437}
9438#endif
9439
9440/*
9441 * "reltimestr()" function
9442 */
9443 static void
9444f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9445{
9446#ifdef FEAT_RELTIME
9447 proftime_T tm;
9448#endif
9449
9450 rettv->v_type = VAR_STRING;
9451 rettv->vval.v_string = NULL;
9452#ifdef FEAT_RELTIME
9453 if (list2proftime(&argvars[0], &tm) == OK)
9454 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9455#endif
9456}
9457
9458#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009459 static void
9460make_connection(void)
9461{
9462 if (X_DISPLAY == NULL
9463# ifdef FEAT_GUI
9464 && !gui.in_use
9465# endif
9466 )
9467 {
9468 x_force_connect = TRUE;
9469 setup_term_clip();
9470 x_force_connect = FALSE;
9471 }
9472}
9473
9474 static int
9475check_connection(void)
9476{
9477 make_connection();
9478 if (X_DISPLAY == NULL)
9479 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009480 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009481 return FAIL;
9482 }
9483 return OK;
9484}
9485#endif
9486
9487#ifdef FEAT_CLIENTSERVER
9488 static void
9489remote_common(typval_T *argvars, typval_T *rettv, int expr)
9490{
9491 char_u *server_name;
9492 char_u *keys;
9493 char_u *r = NULL;
9494 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009495 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009496# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009497 HWND w;
9498# else
9499 Window w;
9500# endif
9501
9502 if (check_restricted() || check_secure())
9503 return;
9504
9505# ifdef FEAT_X11
9506 if (check_connection() == FAIL)
9507 return;
9508# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009509 if (argvars[2].v_type != VAR_UNKNOWN
9510 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009511 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009512
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009513 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009514 if (server_name == NULL)
9515 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009516 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009517# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009518 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009519# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009520 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9521 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009522# endif
9523 {
9524 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009525 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009526 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009527 vim_free(r);
9528 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009529 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009530 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009531 return;
9532 }
9533
9534 rettv->vval.v_string = r;
9535
9536 if (argvars[2].v_type != VAR_UNKNOWN)
9537 {
9538 dictitem_T v;
9539 char_u str[30];
9540 char_u *idvar;
9541
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009542 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009543 if (idvar != NULL && *idvar != NUL)
9544 {
9545 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9546 v.di_tv.v_type = VAR_STRING;
9547 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009548 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009549 vim_free(v.di_tv.vval.v_string);
9550 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009551 }
9552}
9553#endif
9554
9555/*
9556 * "remote_expr()" function
9557 */
9558 static void
9559f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9560{
9561 rettv->v_type = VAR_STRING;
9562 rettv->vval.v_string = NULL;
9563#ifdef FEAT_CLIENTSERVER
9564 remote_common(argvars, rettv, TRUE);
9565#endif
9566}
9567
9568/*
9569 * "remote_foreground()" function
9570 */
9571 static void
9572f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9573{
9574#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009575# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009576 /* On Win32 it's done in this application. */
9577 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009578 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009579
9580 if (server_name != NULL)
9581 serverForeground(server_name);
9582 }
9583# else
9584 /* Send a foreground() expression to the server. */
9585 argvars[1].v_type = VAR_STRING;
9586 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9587 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009588 rettv->v_type = VAR_STRING;
9589 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009590 remote_common(argvars, rettv, TRUE);
9591 vim_free(argvars[1].vval.v_string);
9592# endif
9593#endif
9594}
9595
9596 static void
9597f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9598{
9599#ifdef FEAT_CLIENTSERVER
9600 dictitem_T v;
9601 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009602# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009603 long_u n = 0;
9604# endif
9605 char_u *serverid;
9606
9607 if (check_restricted() || check_secure())
9608 {
9609 rettv->vval.v_number = -1;
9610 return;
9611 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009612 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009613 if (serverid == NULL)
9614 {
9615 rettv->vval.v_number = -1;
9616 return; /* type error; errmsg already given */
9617 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009618# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009619 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9620 if (n == 0)
9621 rettv->vval.v_number = -1;
9622 else
9623 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009624 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009625 rettv->vval.v_number = (s != NULL);
9626 }
9627# else
9628 if (check_connection() == FAIL)
9629 return;
9630
9631 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9632 serverStrToWin(serverid), &s);
9633# endif
9634
9635 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9636 {
9637 char_u *retvar;
9638
9639 v.di_tv.v_type = VAR_STRING;
9640 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009641 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009642 if (retvar != NULL)
9643 set_var(retvar, &v.di_tv, FALSE);
9644 vim_free(v.di_tv.vval.v_string);
9645 }
9646#else
9647 rettv->vval.v_number = -1;
9648#endif
9649}
9650
9651 static void
9652f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9653{
9654 char_u *r = NULL;
9655
9656#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009657 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009658
9659 if (serverid != NULL && !check_restricted() && !check_secure())
9660 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009661 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009662# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009663 /* The server's HWND is encoded in the 'id' parameter */
9664 long_u n = 0;
9665# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009666
9667 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009668 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009669
Bram Moolenaar4f974752019-02-17 17:44:42 +01009670# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9672 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009673 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009674 if (r == NULL)
9675# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009676 if (check_connection() == FAIL
9677 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9678 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009679# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009680 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009681 }
9682#endif
9683 rettv->v_type = VAR_STRING;
9684 rettv->vval.v_string = r;
9685}
9686
9687/*
9688 * "remote_send()" function
9689 */
9690 static void
9691f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9692{
9693 rettv->v_type = VAR_STRING;
9694 rettv->vval.v_string = NULL;
9695#ifdef FEAT_CLIENTSERVER
9696 remote_common(argvars, rettv, FALSE);
9697#endif
9698}
9699
9700/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009701 * "remote_startserver()" function
9702 */
9703 static void
9704f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9705{
9706#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009707 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009708
9709 if (server == NULL)
9710 return; /* type error; errmsg already given */
9711 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009712 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009713 else
9714 {
9715# ifdef FEAT_X11
9716 if (check_connection() == OK)
9717 serverRegisterName(X_DISPLAY, server);
9718# else
9719 serverSetName(server);
9720# endif
9721 }
9722#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009723 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009724#endif
9725}
9726
9727/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009728 * "remove()" function
9729 */
9730 static void
9731f_remove(typval_T *argvars, typval_T *rettv)
9732{
9733 list_T *l;
9734 listitem_T *item, *item2;
9735 listitem_T *li;
9736 long idx;
9737 long end;
9738 char_u *key;
9739 dict_T *d;
9740 dictitem_T *di;
9741 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009742 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009743
9744 if (argvars[0].v_type == VAR_DICT)
9745 {
9746 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009747 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009748 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009749 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009750 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009751 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009752 if (key != NULL)
9753 {
9754 di = dict_find(d, key, -1);
9755 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009756 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009757 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9758 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9759 {
9760 *rettv = di->di_tv;
9761 init_tv(&di->di_tv);
9762 dictitem_remove(d, di);
9763 }
9764 }
9765 }
9766 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009767 else if (argvars[0].v_type == VAR_BLOB)
9768 {
9769 idx = (long)tv_get_number_chk(&argvars[1], &error);
9770 if (!error)
9771 {
9772 blob_T *b = argvars[0].vval.v_blob;
9773 int len = blob_len(b);
9774 char_u *p;
9775
9776 if (idx < 0)
9777 // count from the end
9778 idx = len + idx;
9779 if (idx < 0 || idx >= len)
9780 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009781 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009782 return;
9783 }
9784 if (argvars[2].v_type == VAR_UNKNOWN)
9785 {
9786 // Remove one item, return its value.
9787 p = (char_u *)b->bv_ga.ga_data;
9788 rettv->vval.v_number = (varnumber_T) *(p + idx);
9789 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9790 --b->bv_ga.ga_len;
9791 }
9792 else
9793 {
9794 blob_T *blob;
9795
9796 // Remove range of items, return list with values.
9797 end = (long)tv_get_number_chk(&argvars[2], &error);
9798 if (error)
9799 return;
9800 if (end < 0)
9801 // count from the end
9802 end = len + end;
9803 if (end >= len || idx > end)
9804 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009805 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009806 return;
9807 }
9808 blob = blob_alloc();
9809 if (blob == NULL)
9810 return;
9811 blob->bv_ga.ga_len = end - idx + 1;
9812 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9813 {
9814 vim_free(blob);
9815 return;
9816 }
9817 p = (char_u *)b->bv_ga.ga_data;
9818 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9819 (size_t)(end - idx + 1));
9820 ++blob->bv_refcount;
9821 rettv->v_type = VAR_BLOB;
9822 rettv->vval.v_blob = blob;
9823
9824 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9825 b->bv_ga.ga_len -= end - idx + 1;
9826 }
9827 }
9828 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009829 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009830 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009831 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009832 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009833 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009834 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009835 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009836 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009837 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009838 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009839 else
9840 {
9841 if (argvars[2].v_type == VAR_UNKNOWN)
9842 {
9843 /* Remove one item, return its value. */
9844 vimlist_remove(l, item, item);
9845 *rettv = item->li_tv;
9846 vim_free(item);
9847 }
9848 else
9849 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009850 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009851 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009852 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009853 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009854 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009855 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009856 else
9857 {
9858 int cnt = 0;
9859
9860 for (li = item; li != NULL; li = li->li_next)
9861 {
9862 ++cnt;
9863 if (li == item2)
9864 break;
9865 }
9866 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009867 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009868 else
9869 {
9870 vimlist_remove(l, item, item2);
9871 if (rettv_list_alloc(rettv) == OK)
9872 {
9873 l = rettv->vval.v_list;
9874 l->lv_first = item;
9875 l->lv_last = item2;
9876 item->li_prev = NULL;
9877 item2->li_next = NULL;
9878 l->lv_len = cnt;
9879 }
9880 }
9881 }
9882 }
9883 }
9884 }
9885}
9886
9887/*
9888 * "rename({from}, {to})" function
9889 */
9890 static void
9891f_rename(typval_T *argvars, typval_T *rettv)
9892{
9893 char_u buf[NUMBUFLEN];
9894
9895 if (check_restricted() || check_secure())
9896 rettv->vval.v_number = -1;
9897 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009898 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9899 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009900}
9901
9902/*
9903 * "repeat()" function
9904 */
9905 static void
9906f_repeat(typval_T *argvars, typval_T *rettv)
9907{
9908 char_u *p;
9909 int n;
9910 int slen;
9911 int len;
9912 char_u *r;
9913 int i;
9914
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009915 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009916 if (argvars[0].v_type == VAR_LIST)
9917 {
9918 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9919 while (n-- > 0)
9920 if (list_extend(rettv->vval.v_list,
9921 argvars[0].vval.v_list, NULL) == FAIL)
9922 break;
9923 }
9924 else
9925 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009926 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009927 rettv->v_type = VAR_STRING;
9928 rettv->vval.v_string = NULL;
9929
9930 slen = (int)STRLEN(p);
9931 len = slen * n;
9932 if (len <= 0)
9933 return;
9934
9935 r = alloc(len + 1);
9936 if (r != NULL)
9937 {
9938 for (i = 0; i < n; i++)
9939 mch_memmove(r + i * slen, p, (size_t)slen);
9940 r[len] = NUL;
9941 }
9942
9943 rettv->vval.v_string = r;
9944 }
9945}
9946
9947/*
9948 * "resolve()" function
9949 */
9950 static void
9951f_resolve(typval_T *argvars, typval_T *rettv)
9952{
9953 char_u *p;
9954#ifdef HAVE_READLINK
9955 char_u *buf = NULL;
9956#endif
9957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009958 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009959#ifdef FEAT_SHORTCUT
9960 {
9961 char_u *v = NULL;
9962
Bram Moolenaardce1e892019-02-10 23:18:53 +01009963 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009964 if (v != NULL)
9965 rettv->vval.v_string = v;
9966 else
9967 rettv->vval.v_string = vim_strsave(p);
9968 }
9969#else
9970# ifdef HAVE_READLINK
9971 {
9972 char_u *cpy;
9973 int len;
9974 char_u *remain = NULL;
9975 char_u *q;
9976 int is_relative_to_current = FALSE;
9977 int has_trailing_pathsep = FALSE;
9978 int limit = 100;
9979
9980 p = vim_strsave(p);
9981
9982 if (p[0] == '.' && (vim_ispathsep(p[1])
9983 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9984 is_relative_to_current = TRUE;
9985
9986 len = STRLEN(p);
9987 if (len > 0 && after_pathsep(p, p + len))
9988 {
9989 has_trailing_pathsep = TRUE;
9990 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9991 }
9992
9993 q = getnextcomp(p);
9994 if (*q != NUL)
9995 {
9996 /* Separate the first path component in "p", and keep the
9997 * remainder (beginning with the path separator). */
9998 remain = vim_strsave(q - 1);
9999 q[-1] = NUL;
10000 }
10001
10002 buf = alloc(MAXPATHL + 1);
10003 if (buf == NULL)
10004 goto fail;
10005
10006 for (;;)
10007 {
10008 for (;;)
10009 {
10010 len = readlink((char *)p, (char *)buf, MAXPATHL);
10011 if (len <= 0)
10012 break;
10013 buf[len] = NUL;
10014
10015 if (limit-- == 0)
10016 {
10017 vim_free(p);
10018 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010019 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010020 rettv->vval.v_string = NULL;
10021 goto fail;
10022 }
10023
10024 /* Ensure that the result will have a trailing path separator
10025 * if the argument has one. */
10026 if (remain == NULL && has_trailing_pathsep)
10027 add_pathsep(buf);
10028
10029 /* Separate the first path component in the link value and
10030 * concatenate the remainders. */
10031 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10032 if (*q != NUL)
10033 {
10034 if (remain == NULL)
10035 remain = vim_strsave(q - 1);
10036 else
10037 {
10038 cpy = concat_str(q - 1, remain);
10039 if (cpy != NULL)
10040 {
10041 vim_free(remain);
10042 remain = cpy;
10043 }
10044 }
10045 q[-1] = NUL;
10046 }
10047
10048 q = gettail(p);
10049 if (q > p && *q == NUL)
10050 {
10051 /* Ignore trailing path separator. */
10052 q[-1] = NUL;
10053 q = gettail(p);
10054 }
10055 if (q > p && !mch_isFullName(buf))
10056 {
10057 /* symlink is relative to directory of argument */
10058 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10059 if (cpy != NULL)
10060 {
10061 STRCPY(cpy, p);
10062 STRCPY(gettail(cpy), buf);
10063 vim_free(p);
10064 p = cpy;
10065 }
10066 }
10067 else
10068 {
10069 vim_free(p);
10070 p = vim_strsave(buf);
10071 }
10072 }
10073
10074 if (remain == NULL)
10075 break;
10076
10077 /* Append the first path component of "remain" to "p". */
10078 q = getnextcomp(remain + 1);
10079 len = q - remain - (*q != NUL);
10080 cpy = vim_strnsave(p, STRLEN(p) + len);
10081 if (cpy != NULL)
10082 {
10083 STRNCAT(cpy, remain, len);
10084 vim_free(p);
10085 p = cpy;
10086 }
10087 /* Shorten "remain". */
10088 if (*q != NUL)
10089 STRMOVE(remain, q - 1);
10090 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010091 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010092 }
10093
10094 /* If the result is a relative path name, make it explicitly relative to
10095 * the current directory if and only if the argument had this form. */
10096 if (!vim_ispathsep(*p))
10097 {
10098 if (is_relative_to_current
10099 && *p != NUL
10100 && !(p[0] == '.'
10101 && (p[1] == NUL
10102 || vim_ispathsep(p[1])
10103 || (p[1] == '.'
10104 && (p[2] == NUL
10105 || vim_ispathsep(p[2]))))))
10106 {
10107 /* Prepend "./". */
10108 cpy = concat_str((char_u *)"./", p);
10109 if (cpy != NULL)
10110 {
10111 vim_free(p);
10112 p = cpy;
10113 }
10114 }
10115 else if (!is_relative_to_current)
10116 {
10117 /* Strip leading "./". */
10118 q = p;
10119 while (q[0] == '.' && vim_ispathsep(q[1]))
10120 q += 2;
10121 if (q > p)
10122 STRMOVE(p, p + 2);
10123 }
10124 }
10125
10126 /* Ensure that the result will have no trailing path separator
10127 * if the argument had none. But keep "/" or "//". */
10128 if (!has_trailing_pathsep)
10129 {
10130 q = p + STRLEN(p);
10131 if (after_pathsep(p, q))
10132 *gettail_sep(p) = NUL;
10133 }
10134
10135 rettv->vval.v_string = p;
10136 }
10137# else
10138 rettv->vval.v_string = vim_strsave(p);
10139# endif
10140#endif
10141
10142 simplify_filename(rettv->vval.v_string);
10143
10144#ifdef HAVE_READLINK
10145fail:
10146 vim_free(buf);
10147#endif
10148 rettv->v_type = VAR_STRING;
10149}
10150
10151/*
10152 * "reverse({list})" function
10153 */
10154 static void
10155f_reverse(typval_T *argvars, typval_T *rettv)
10156{
10157 list_T *l;
10158 listitem_T *li, *ni;
10159
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010160 if (argvars[0].v_type == VAR_BLOB)
10161 {
10162 blob_T *b = argvars[0].vval.v_blob;
10163 int i, len = blob_len(b);
10164
10165 for (i = 0; i < len / 2; i++)
10166 {
10167 int tmp = blob_get(b, i);
10168
10169 blob_set(b, i, blob_get(b, len - i - 1));
10170 blob_set(b, len - i - 1, tmp);
10171 }
10172 rettv_blob_set(rettv, b);
10173 return;
10174 }
10175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010176 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010177 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010178 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010179 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010180 (char_u *)N_("reverse() argument"), TRUE))
10181 {
10182 li = l->lv_last;
10183 l->lv_first = l->lv_last = NULL;
10184 l->lv_len = 0;
10185 while (li != NULL)
10186 {
10187 ni = li->li_prev;
10188 list_append(l, li);
10189 li = ni;
10190 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010191 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010192 l->lv_idx = l->lv_len - l->lv_idx - 1;
10193 }
10194}
10195
10196#define SP_NOMOVE 0x01 /* don't move cursor */
10197#define SP_REPEAT 0x02 /* repeat to find outer pair */
10198#define SP_RETCOUNT 0x04 /* return matchcount */
10199#define SP_SETPCMARK 0x08 /* set previous context mark */
10200#define SP_START 0x10 /* accept match at start position */
10201#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10202#define SP_END 0x40 /* leave cursor at end of match */
10203#define SP_COLUMN 0x80 /* start at cursor column */
10204
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010205/*
10206 * Get flags for a search function.
10207 * Possibly sets "p_ws".
10208 * Returns BACKWARD, FORWARD or zero (for an error).
10209 */
10210 static int
10211get_search_arg(typval_T *varp, int *flagsp)
10212{
10213 int dir = FORWARD;
10214 char_u *flags;
10215 char_u nbuf[NUMBUFLEN];
10216 int mask;
10217
10218 if (varp->v_type != VAR_UNKNOWN)
10219 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010220 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010221 if (flags == NULL)
10222 return 0; /* type error; errmsg already given */
10223 while (*flags != NUL)
10224 {
10225 switch (*flags)
10226 {
10227 case 'b': dir = BACKWARD; break;
10228 case 'w': p_ws = TRUE; break;
10229 case 'W': p_ws = FALSE; break;
10230 default: mask = 0;
10231 if (flagsp != NULL)
10232 switch (*flags)
10233 {
10234 case 'c': mask = SP_START; break;
10235 case 'e': mask = SP_END; break;
10236 case 'm': mask = SP_RETCOUNT; break;
10237 case 'n': mask = SP_NOMOVE; break;
10238 case 'p': mask = SP_SUBPAT; break;
10239 case 'r': mask = SP_REPEAT; break;
10240 case 's': mask = SP_SETPCMARK; break;
10241 case 'z': mask = SP_COLUMN; break;
10242 }
10243 if (mask == 0)
10244 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010245 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010246 dir = 0;
10247 }
10248 else
10249 *flagsp |= mask;
10250 }
10251 if (dir == 0)
10252 break;
10253 ++flags;
10254 }
10255 }
10256 return dir;
10257}
10258
10259/*
10260 * Shared by search() and searchpos() functions.
10261 */
10262 static int
10263search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10264{
10265 int flags;
10266 char_u *pat;
10267 pos_T pos;
10268 pos_T save_cursor;
10269 int save_p_ws = p_ws;
10270 int dir;
10271 int retval = 0; /* default: FAIL */
10272 long lnum_stop = 0;
10273 proftime_T tm;
10274#ifdef FEAT_RELTIME
10275 long time_limit = 0;
10276#endif
10277 int options = SEARCH_KEEP;
10278 int subpatnum;
10279
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010280 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010281 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10282 if (dir == 0)
10283 goto theend;
10284 flags = *flagsp;
10285 if (flags & SP_START)
10286 options |= SEARCH_START;
10287 if (flags & SP_END)
10288 options |= SEARCH_END;
10289 if (flags & SP_COLUMN)
10290 options |= SEARCH_COL;
10291
10292 /* Optional arguments: line number to stop searching and timeout. */
10293 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10294 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010295 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 if (lnum_stop < 0)
10297 goto theend;
10298#ifdef FEAT_RELTIME
10299 if (argvars[3].v_type != VAR_UNKNOWN)
10300 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010301 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010302 if (time_limit < 0)
10303 goto theend;
10304 }
10305#endif
10306 }
10307
10308#ifdef FEAT_RELTIME
10309 /* Set the time limit, if there is one. */
10310 profile_setlimit(time_limit, &tm);
10311#endif
10312
10313 /*
10314 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10315 * Check to make sure only those flags are set.
10316 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10317 * flags cannot be set. Check for that condition also.
10318 */
10319 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10320 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10321 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010322 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010323 goto theend;
10324 }
10325
10326 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010327 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010328 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010329 if (subpatnum != FAIL)
10330 {
10331 if (flags & SP_SUBPAT)
10332 retval = subpatnum;
10333 else
10334 retval = pos.lnum;
10335 if (flags & SP_SETPCMARK)
10336 setpcmark();
10337 curwin->w_cursor = pos;
10338 if (match_pos != NULL)
10339 {
10340 /* Store the match cursor position */
10341 match_pos->lnum = pos.lnum;
10342 match_pos->col = pos.col + 1;
10343 }
10344 /* "/$" will put the cursor after the end of the line, may need to
10345 * correct that here */
10346 check_cursor();
10347 }
10348
10349 /* If 'n' flag is used: restore cursor position. */
10350 if (flags & SP_NOMOVE)
10351 curwin->w_cursor = save_cursor;
10352 else
10353 curwin->w_set_curswant = TRUE;
10354theend:
10355 p_ws = save_p_ws;
10356
10357 return retval;
10358}
10359
10360#ifdef FEAT_FLOAT
10361
10362/*
10363 * round() is not in C90, use ceil() or floor() instead.
10364 */
10365 float_T
10366vim_round(float_T f)
10367{
10368 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10369}
10370
10371/*
10372 * "round({float})" function
10373 */
10374 static void
10375f_round(typval_T *argvars, typval_T *rettv)
10376{
10377 float_T f = 0.0;
10378
10379 rettv->v_type = VAR_FLOAT;
10380 if (get_float_arg(argvars, &f) == OK)
10381 rettv->vval.v_float = vim_round(f);
10382 else
10383 rettv->vval.v_float = 0.0;
10384}
10385#endif
10386
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010387#ifdef FEAT_RUBY
10388/*
10389 * "rubyeval()" function
10390 */
10391 static void
10392f_rubyeval(typval_T *argvars, typval_T *rettv)
10393{
10394 char_u *str;
10395 char_u buf[NUMBUFLEN];
10396
10397 str = tv_get_string_buf(&argvars[0], buf);
10398 do_rubyeval(str, rettv);
10399}
10400#endif
10401
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010402/*
10403 * "screenattr()" function
10404 */
10405 static void
10406f_screenattr(typval_T *argvars, typval_T *rettv)
10407{
10408 int row;
10409 int col;
10410 int c;
10411
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010412 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10413 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010414 if (row < 0 || row >= screen_Rows
10415 || col < 0 || col >= screen_Columns)
10416 c = -1;
10417 else
10418 c = ScreenAttrs[LineOffset[row] + col];
10419 rettv->vval.v_number = c;
10420}
10421
10422/*
10423 * "screenchar()" function
10424 */
10425 static void
10426f_screenchar(typval_T *argvars, typval_T *rettv)
10427{
10428 int row;
10429 int col;
10430 int off;
10431 int c;
10432
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010433 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10434 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010435 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010436 c = -1;
10437 else
10438 {
10439 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010440 if (enc_utf8 && ScreenLinesUC[off] != 0)
10441 c = ScreenLinesUC[off];
10442 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010443 c = ScreenLines[off];
10444 }
10445 rettv->vval.v_number = c;
10446}
10447
10448/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010449 * "screenchars()" function
10450 */
10451 static void
10452f_screenchars(typval_T *argvars, typval_T *rettv)
10453{
10454 int row;
10455 int col;
10456 int off;
10457 int c;
10458 int i;
10459
10460 if (rettv_list_alloc(rettv) == FAIL)
10461 return;
10462 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10463 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10464 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10465 return;
10466
10467 off = LineOffset[row] + col;
10468 if (enc_utf8 && ScreenLinesUC[off] != 0)
10469 c = ScreenLinesUC[off];
10470 else
10471 c = ScreenLines[off];
10472 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10473
10474 if (enc_utf8)
10475
10476 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10477 list_append_number(rettv->vval.v_list,
10478 (varnumber_T)ScreenLinesC[i][off]);
10479}
10480
10481/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010482 * "screencol()" function
10483 *
10484 * First column is 1 to be consistent with virtcol().
10485 */
10486 static void
10487f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10488{
10489 rettv->vval.v_number = screen_screencol() + 1;
10490}
10491
10492/*
10493 * "screenrow()" function
10494 */
10495 static void
10496f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10497{
10498 rettv->vval.v_number = screen_screenrow() + 1;
10499}
10500
10501/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010502 * "screenstring()" function
10503 */
10504 static void
10505f_screenstring(typval_T *argvars, typval_T *rettv)
10506{
10507 int row;
10508 int col;
10509 int off;
10510 int c;
10511 int i;
10512 char_u buf[MB_MAXBYTES + 1];
10513 int buflen = 0;
10514
10515 rettv->vval.v_string = NULL;
10516 rettv->v_type = VAR_STRING;
10517
10518 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10519 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10520 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10521 return;
10522
10523 off = LineOffset[row] + col;
10524 if (enc_utf8 && ScreenLinesUC[off] != 0)
10525 c = ScreenLinesUC[off];
10526 else
10527 c = ScreenLines[off];
10528 buflen += mb_char2bytes(c, buf);
10529
10530 if (enc_utf8)
10531 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10532 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10533
10534 buf[buflen] = NUL;
10535 rettv->vval.v_string = vim_strsave(buf);
10536}
10537
10538/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010539 * "search()" function
10540 */
10541 static void
10542f_search(typval_T *argvars, typval_T *rettv)
10543{
10544 int flags = 0;
10545
10546 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10547}
10548
10549/*
10550 * "searchdecl()" function
10551 */
10552 static void
10553f_searchdecl(typval_T *argvars, typval_T *rettv)
10554{
10555 int locally = 1;
10556 int thisblock = 0;
10557 int error = FALSE;
10558 char_u *name;
10559
10560 rettv->vval.v_number = 1; /* default: FAIL */
10561
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010562 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010563 if (argvars[1].v_type != VAR_UNKNOWN)
10564 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010565 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010566 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010567 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010568 }
10569 if (!error && name != NULL)
10570 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10571 locally, thisblock, SEARCH_KEEP) == FAIL;
10572}
10573
10574/*
10575 * Used by searchpair() and searchpairpos()
10576 */
10577 static int
10578searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10579{
10580 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010581 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010582 int save_p_ws = p_ws;
10583 int dir;
10584 int flags = 0;
10585 char_u nbuf1[NUMBUFLEN];
10586 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010587 int retval = 0; /* default: FAIL */
10588 long lnum_stop = 0;
10589 long time_limit = 0;
10590
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010591 /* Get the three pattern arguments: start, middle, end. Will result in an
10592 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010593 spat = tv_get_string_chk(&argvars[0]);
10594 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10595 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010596 if (spat == NULL || mpat == NULL || epat == NULL)
10597 goto theend; /* type error */
10598
10599 /* Handle the optional fourth argument: flags */
10600 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10601 if (dir == 0)
10602 goto theend;
10603
10604 /* Don't accept SP_END or SP_SUBPAT.
10605 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10606 */
10607 if ((flags & (SP_END | SP_SUBPAT)) != 0
10608 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10609 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010610 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010611 goto theend;
10612 }
10613
10614 /* Using 'r' implies 'W', otherwise it doesn't work. */
10615 if (flags & SP_REPEAT)
10616 p_ws = FALSE;
10617
10618 /* Optional fifth argument: skip expression */
10619 if (argvars[3].v_type == VAR_UNKNOWN
10620 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010621 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010622 else
10623 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010624 skip = &argvars[4];
10625 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10626 && skip->v_type != VAR_STRING)
10627 {
10628 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010629 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010630 goto theend;
10631 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010632 if (argvars[5].v_type != VAR_UNKNOWN)
10633 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010634 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010635 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010636 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010637 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010638 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010639 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010640#ifdef FEAT_RELTIME
10641 if (argvars[6].v_type != VAR_UNKNOWN)
10642 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010643 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010645 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010646 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010647 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010648 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010649 }
10650#endif
10651 }
10652 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010653
10654 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10655 match_pos, lnum_stop, time_limit);
10656
10657theend:
10658 p_ws = save_p_ws;
10659
10660 return retval;
10661}
10662
10663/*
10664 * "searchpair()" function
10665 */
10666 static void
10667f_searchpair(typval_T *argvars, typval_T *rettv)
10668{
10669 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10670}
10671
10672/*
10673 * "searchpairpos()" function
10674 */
10675 static void
10676f_searchpairpos(typval_T *argvars, typval_T *rettv)
10677{
10678 pos_T match_pos;
10679 int lnum = 0;
10680 int col = 0;
10681
10682 if (rettv_list_alloc(rettv) == FAIL)
10683 return;
10684
10685 if (searchpair_cmn(argvars, &match_pos) > 0)
10686 {
10687 lnum = match_pos.lnum;
10688 col = match_pos.col;
10689 }
10690
10691 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10692 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10693}
10694
10695/*
10696 * Search for a start/middle/end thing.
10697 * Used by searchpair(), see its documentation for the details.
10698 * Returns 0 or -1 for no match,
10699 */
10700 long
10701do_searchpair(
10702 char_u *spat, /* start pattern */
10703 char_u *mpat, /* middle pattern */
10704 char_u *epat, /* end pattern */
10705 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010706 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010707 int flags, /* SP_SETPCMARK and other SP_ values */
10708 pos_T *match_pos,
10709 linenr_T lnum_stop, /* stop at this line if not zero */
10710 long time_limit UNUSED) /* stop after this many msec */
10711{
10712 char_u *save_cpo;
10713 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10714 long retval = 0;
10715 pos_T pos;
10716 pos_T firstpos;
10717 pos_T foundpos;
10718 pos_T save_cursor;
10719 pos_T save_pos;
10720 int n;
10721 int r;
10722 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010723 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 int err;
10725 int options = SEARCH_KEEP;
10726 proftime_T tm;
10727
10728 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10729 save_cpo = p_cpo;
10730 p_cpo = empty_option;
10731
10732#ifdef FEAT_RELTIME
10733 /* Set the time limit, if there is one. */
10734 profile_setlimit(time_limit, &tm);
10735#endif
10736
10737 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10738 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010739 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10740 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010741 if (pat2 == NULL || pat3 == NULL)
10742 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010743 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010744 if (*mpat == NUL)
10745 STRCPY(pat3, pat2);
10746 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010747 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010748 spat, epat, mpat);
10749 if (flags & SP_START)
10750 options |= SEARCH_START;
10751
Bram Moolenaar48570482017-10-30 21:48:41 +010010752 if (skip != NULL)
10753 {
10754 /* Empty string means to not use the skip expression. */
10755 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10756 use_skip = skip->vval.v_string != NULL
10757 && *skip->vval.v_string != NUL;
10758 }
10759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010760 save_cursor = curwin->w_cursor;
10761 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010762 CLEAR_POS(&firstpos);
10763 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010764 pat = pat3;
10765 for (;;)
10766 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010767 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010768 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010769 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010770 /* didn't find it or found the first match again: FAIL */
10771 break;
10772
10773 if (firstpos.lnum == 0)
10774 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010775 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010776 {
10777 /* Found the same position again. Can happen with a pattern that
10778 * has "\zs" at the end and searching backwards. Advance one
10779 * character and try again. */
10780 if (dir == BACKWARD)
10781 decl(&pos);
10782 else
10783 incl(&pos);
10784 }
10785 foundpos = pos;
10786
10787 /* clear the start flag to avoid getting stuck here */
10788 options &= ~SEARCH_START;
10789
10790 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010791 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010792 {
10793 save_pos = curwin->w_cursor;
10794 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010795 err = FALSE;
10796 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010797 curwin->w_cursor = save_pos;
10798 if (err)
10799 {
10800 /* Evaluating {skip} caused an error, break here. */
10801 curwin->w_cursor = save_cursor;
10802 retval = -1;
10803 break;
10804 }
10805 if (r)
10806 continue;
10807 }
10808
10809 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10810 {
10811 /* Found end when searching backwards or start when searching
10812 * forward: nested pair. */
10813 ++nest;
10814 pat = pat2; /* nested, don't search for middle */
10815 }
10816 else
10817 {
10818 /* Found end when searching forward or start when searching
10819 * backward: end of (nested) pair; or found middle in outer pair. */
10820 if (--nest == 1)
10821 pat = pat3; /* outer level, search for middle */
10822 }
10823
10824 if (nest == 0)
10825 {
10826 /* Found the match: return matchcount or line number. */
10827 if (flags & SP_RETCOUNT)
10828 ++retval;
10829 else
10830 retval = pos.lnum;
10831 if (flags & SP_SETPCMARK)
10832 setpcmark();
10833 curwin->w_cursor = pos;
10834 if (!(flags & SP_REPEAT))
10835 break;
10836 nest = 1; /* search for next unmatched */
10837 }
10838 }
10839
10840 if (match_pos != NULL)
10841 {
10842 /* Store the match cursor position */
10843 match_pos->lnum = curwin->w_cursor.lnum;
10844 match_pos->col = curwin->w_cursor.col + 1;
10845 }
10846
10847 /* If 'n' flag is used or search failed: restore cursor position. */
10848 if ((flags & SP_NOMOVE) || retval == 0)
10849 curwin->w_cursor = save_cursor;
10850
10851theend:
10852 vim_free(pat2);
10853 vim_free(pat3);
10854 if (p_cpo == empty_option)
10855 p_cpo = save_cpo;
10856 else
10857 /* Darn, evaluating the {skip} expression changed the value. */
10858 free_string_option(save_cpo);
10859
10860 return retval;
10861}
10862
10863/*
10864 * "searchpos()" function
10865 */
10866 static void
10867f_searchpos(typval_T *argvars, typval_T *rettv)
10868{
10869 pos_T match_pos;
10870 int lnum = 0;
10871 int col = 0;
10872 int n;
10873 int flags = 0;
10874
10875 if (rettv_list_alloc(rettv) == FAIL)
10876 return;
10877
10878 n = search_cmn(argvars, &match_pos, &flags);
10879 if (n > 0)
10880 {
10881 lnum = match_pos.lnum;
10882 col = match_pos.col;
10883 }
10884
10885 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10886 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10887 if (flags & SP_SUBPAT)
10888 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10889}
10890
10891 static void
10892f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10893{
10894#ifdef FEAT_CLIENTSERVER
10895 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010896 char_u *server = tv_get_string_chk(&argvars[0]);
10897 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010898
10899 rettv->vval.v_number = -1;
10900 if (server == NULL || reply == NULL)
10901 return;
10902 if (check_restricted() || check_secure())
10903 return;
10904# ifdef FEAT_X11
10905 if (check_connection() == FAIL)
10906 return;
10907# endif
10908
10909 if (serverSendReply(server, reply) < 0)
10910 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010911 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010912 return;
10913 }
10914 rettv->vval.v_number = 0;
10915#else
10916 rettv->vval.v_number = -1;
10917#endif
10918}
10919
10920 static void
10921f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10922{
10923 char_u *r = NULL;
10924
10925#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010926# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010927 r = serverGetVimNames();
10928# else
10929 make_connection();
10930 if (X_DISPLAY != NULL)
10931 r = serverGetVimNames(X_DISPLAY);
10932# endif
10933#endif
10934 rettv->v_type = VAR_STRING;
10935 rettv->vval.v_string = r;
10936}
10937
10938/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010939 * "setbufline()" function
10940 */
10941 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010942f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010943{
10944 linenr_T lnum;
10945 buf_T *buf;
10946
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010947 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010948 if (buf == NULL)
10949 rettv->vval.v_number = 1; /* FAIL */
10950 else
10951 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010952 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010953 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010954 }
10955}
10956
10957/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010958 * "setbufvar()" function
10959 */
10960 static void
10961f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10962{
10963 buf_T *buf;
10964 char_u *varname, *bufvarname;
10965 typval_T *varp;
10966 char_u nbuf[NUMBUFLEN];
10967
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010968 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010969 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010970 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10971 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010972 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010973 varp = &argvars[2];
10974
10975 if (buf != NULL && varname != NULL && varp != NULL)
10976 {
10977 if (*varname == '&')
10978 {
10979 long numval;
10980 char_u *strval;
10981 int error = FALSE;
10982 aco_save_T aco;
10983
10984 /* set curbuf to be our buf, temporarily */
10985 aucmd_prepbuf(&aco, buf);
10986
10987 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010988 numval = (long)tv_get_number_chk(varp, &error);
10989 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010990 if (!error && strval != NULL)
10991 set_option_value(varname, numval, strval, OPT_LOCAL);
10992
10993 /* reset notion of buffer */
10994 aucmd_restbuf(&aco);
10995 }
10996 else
10997 {
10998 buf_T *save_curbuf = curbuf;
10999
11000 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
11001 if (bufvarname != NULL)
11002 {
11003 curbuf = buf;
11004 STRCPY(bufvarname, "b:");
11005 STRCPY(bufvarname + 2, varname);
11006 set_var(bufvarname, varp, TRUE);
11007 vim_free(bufvarname);
11008 curbuf = save_curbuf;
11009 }
11010 }
11011 }
11012}
11013
11014 static void
11015f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
11016{
11017 dict_T *d;
11018 dictitem_T *di;
11019 char_u *csearch;
11020
11021 if (argvars[0].v_type != VAR_DICT)
11022 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011023 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011024 return;
11025 }
11026
11027 if ((d = argvars[0].vval.v_dict) != NULL)
11028 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011029 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011030 if (csearch != NULL)
11031 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011032 if (enc_utf8)
11033 {
11034 int pcc[MAX_MCO];
11035 int c = utfc_ptr2char(csearch, pcc);
11036
11037 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11038 }
11039 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011040 set_last_csearch(PTR2CHAR(csearch),
11041 csearch, MB_PTR2LEN(csearch));
11042 }
11043
11044 di = dict_find(d, (char_u *)"forward", -1);
11045 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011046 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011047 ? FORWARD : BACKWARD);
11048
11049 di = dict_find(d, (char_u *)"until", -1);
11050 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011051 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011052 }
11053}
11054
11055/*
11056 * "setcmdpos()" function
11057 */
11058 static void
11059f_setcmdpos(typval_T *argvars, typval_T *rettv)
11060{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011061 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011062
11063 if (pos >= 0)
11064 rettv->vval.v_number = set_cmdline_pos(pos);
11065}
11066
11067/*
11068 * "setfperm({fname}, {mode})" function
11069 */
11070 static void
11071f_setfperm(typval_T *argvars, typval_T *rettv)
11072{
11073 char_u *fname;
11074 char_u modebuf[NUMBUFLEN];
11075 char_u *mode_str;
11076 int i;
11077 int mask;
11078 int mode = 0;
11079
11080 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011081 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011082 if (fname == NULL)
11083 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011084 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011085 if (mode_str == NULL)
11086 return;
11087 if (STRLEN(mode_str) != 9)
11088 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011089 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011090 return;
11091 }
11092
11093 mask = 1;
11094 for (i = 8; i >= 0; --i)
11095 {
11096 if (mode_str[i] != '-')
11097 mode |= mask;
11098 mask = mask << 1;
11099 }
11100 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11101}
11102
11103/*
11104 * "setline()" function
11105 */
11106 static void
11107f_setline(typval_T *argvars, typval_T *rettv)
11108{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011109 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011110
Bram Moolenaarca851592018-06-06 21:04:07 +020011111 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011112}
11113
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011114/*
11115 * Used by "setqflist()" and "setloclist()" functions
11116 */
11117 static void
11118set_qf_ll_list(
11119 win_T *wp UNUSED,
11120 typval_T *list_arg UNUSED,
11121 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011122 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011123 typval_T *rettv)
11124{
11125#ifdef FEAT_QUICKFIX
11126 static char *e_invact = N_("E927: Invalid action: '%s'");
11127 char_u *act;
11128 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011129 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011130#endif
11131
11132 rettv->vval.v_number = -1;
11133
11134#ifdef FEAT_QUICKFIX
11135 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011136 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011137 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011138 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011139 else
11140 {
11141 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011142 dict_T *d = NULL;
11143 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011144
11145 if (action_arg->v_type == VAR_STRING)
11146 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011147 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011148 if (act == NULL)
11149 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011150 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11151 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152 action = *act;
11153 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011154 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011155 }
11156 else if (action_arg->v_type == VAR_UNKNOWN)
11157 action = ' ';
11158 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011159 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011160
Bram Moolenaard823fa92016-08-12 16:29:27 +020011161 if (action_arg->v_type != VAR_UNKNOWN
11162 && what_arg->v_type != VAR_UNKNOWN)
11163 {
11164 if (what_arg->v_type == VAR_DICT)
11165 d = what_arg->vval.v_dict;
11166 else
11167 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011168 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011169 valid_dict = FALSE;
11170 }
11171 }
11172
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011173 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011174 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011175 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11176 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011177 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011178 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011179 }
11180#endif
11181}
11182
11183/*
11184 * "setloclist()" function
11185 */
11186 static void
11187f_setloclist(typval_T *argvars, typval_T *rettv)
11188{
11189 win_T *win;
11190
11191 rettv->vval.v_number = -1;
11192
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011193 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011194 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011195 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011196}
11197
11198/*
11199 * "setmatches()" function
11200 */
11201 static void
11202f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11203{
11204#ifdef FEAT_SEARCH_EXTRA
11205 list_T *l;
11206 listitem_T *li;
11207 dict_T *d;
11208 list_T *s = NULL;
11209
11210 rettv->vval.v_number = -1;
11211 if (argvars[0].v_type != VAR_LIST)
11212 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011213 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011214 return;
11215 }
11216 if ((l = argvars[0].vval.v_list) != NULL)
11217 {
11218
11219 /* To some extent make sure that we are dealing with a list from
11220 * "getmatches()". */
11221 li = l->lv_first;
11222 while (li != NULL)
11223 {
11224 if (li->li_tv.v_type != VAR_DICT
11225 || (d = li->li_tv.vval.v_dict) == NULL)
11226 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011227 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011228 return;
11229 }
11230 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11231 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11232 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11233 && dict_find(d, (char_u *)"priority", -1) != NULL
11234 && dict_find(d, (char_u *)"id", -1) != NULL))
11235 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011236 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011237 return;
11238 }
11239 li = li->li_next;
11240 }
11241
11242 clear_matches(curwin);
11243 li = l->lv_first;
11244 while (li != NULL)
11245 {
11246 int i = 0;
11247 char_u buf[5];
11248 dictitem_T *di;
11249 char_u *group;
11250 int priority;
11251 int id;
11252 char_u *conceal;
11253
11254 d = li->li_tv.vval.v_dict;
11255 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11256 {
11257 if (s == NULL)
11258 {
11259 s = list_alloc();
11260 if (s == NULL)
11261 return;
11262 }
11263
11264 /* match from matchaddpos() */
11265 for (i = 1; i < 9; i++)
11266 {
11267 sprintf((char *)buf, (char *)"pos%d", i);
11268 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11269 {
11270 if (di->di_tv.v_type != VAR_LIST)
11271 return;
11272
11273 list_append_tv(s, &di->di_tv);
11274 s->lv_refcount++;
11275 }
11276 else
11277 break;
11278 }
11279 }
11280
Bram Moolenaar8f667172018-12-14 15:38:31 +010011281 group = dict_get_string(d, (char_u *)"group", TRUE);
11282 priority = (int)dict_get_number(d, (char_u *)"priority");
11283 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011284 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011285 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011286 : NULL;
11287 if (i == 0)
11288 {
11289 match_add(curwin, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011290 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011291 priority, id, NULL, conceal);
11292 }
11293 else
11294 {
11295 match_add(curwin, group, NULL, priority, id, s, conceal);
11296 list_unref(s);
11297 s = NULL;
11298 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011299 vim_free(group);
11300 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011301
11302 li = li->li_next;
11303 }
11304 rettv->vval.v_number = 0;
11305 }
11306#endif
11307}
11308
11309/*
11310 * "setpos()" function
11311 */
11312 static void
11313f_setpos(typval_T *argvars, typval_T *rettv)
11314{
11315 pos_T pos;
11316 int fnum;
11317 char_u *name;
11318 colnr_T curswant = -1;
11319
11320 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011321 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011322 if (name != NULL)
11323 {
11324 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11325 {
11326 if (--pos.col < 0)
11327 pos.col = 0;
11328 if (name[0] == '.' && name[1] == NUL)
11329 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011330 /* set cursor; "fnum" is ignored */
11331 curwin->w_cursor = pos;
11332 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011333 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011334 curwin->w_curswant = curswant - 1;
11335 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011336 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011337 check_cursor();
11338 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011339 }
11340 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11341 {
11342 /* set mark */
11343 if (setmark_pos(name[1], &pos, fnum) == OK)
11344 rettv->vval.v_number = 0;
11345 }
11346 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011347 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348 }
11349 }
11350}
11351
11352/*
11353 * "setqflist()" function
11354 */
11355 static void
11356f_setqflist(typval_T *argvars, typval_T *rettv)
11357{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011358 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011359}
11360
11361/*
11362 * "setreg()" function
11363 */
11364 static void
11365f_setreg(typval_T *argvars, typval_T *rettv)
11366{
11367 int regname;
11368 char_u *strregname;
11369 char_u *stropt;
11370 char_u *strval;
11371 int append;
11372 char_u yank_type;
11373 long block_len;
11374
11375 block_len = -1;
11376 yank_type = MAUTO;
11377 append = FALSE;
11378
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011379 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011380 rettv->vval.v_number = 1; /* FAIL is default */
11381
11382 if (strregname == NULL)
11383 return; /* type error; errmsg already given */
11384 regname = *strregname;
11385 if (regname == 0 || regname == '@')
11386 regname = '"';
11387
11388 if (argvars[2].v_type != VAR_UNKNOWN)
11389 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011390 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011391 if (stropt == NULL)
11392 return; /* type error */
11393 for (; *stropt != NUL; ++stropt)
11394 switch (*stropt)
11395 {
11396 case 'a': case 'A': /* append */
11397 append = TRUE;
11398 break;
11399 case 'v': case 'c': /* character-wise selection */
11400 yank_type = MCHAR;
11401 break;
11402 case 'V': case 'l': /* line-wise selection */
11403 yank_type = MLINE;
11404 break;
11405 case 'b': case Ctrl_V: /* block-wise selection */
11406 yank_type = MBLOCK;
11407 if (VIM_ISDIGIT(stropt[1]))
11408 {
11409 ++stropt;
11410 block_len = getdigits(&stropt) - 1;
11411 --stropt;
11412 }
11413 break;
11414 }
11415 }
11416
11417 if (argvars[1].v_type == VAR_LIST)
11418 {
11419 char_u **lstval;
11420 char_u **allocval;
11421 char_u buf[NUMBUFLEN];
11422 char_u **curval;
11423 char_u **curallocval;
11424 list_T *ll = argvars[1].vval.v_list;
11425 listitem_T *li;
11426 int len;
11427
11428 /* If the list is NULL handle like an empty list. */
11429 len = ll == NULL ? 0 : ll->lv_len;
11430
11431 /* First half: use for pointers to result lines; second half: use for
11432 * pointers to allocated copies. */
11433 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11434 if (lstval == NULL)
11435 return;
11436 curval = lstval;
11437 allocval = lstval + len + 2;
11438 curallocval = allocval;
11439
11440 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11441 li = li->li_next)
11442 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011443 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011444 if (strval == NULL)
11445 goto free_lstval;
11446 if (strval == buf)
11447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011448 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011449 * overwrite the string. */
11450 strval = vim_strsave(buf);
11451 if (strval == NULL)
11452 goto free_lstval;
11453 *curallocval++ = strval;
11454 }
11455 *curval++ = strval;
11456 }
11457 *curval++ = NULL;
11458
11459 write_reg_contents_lst(regname, lstval, -1,
11460 append, yank_type, block_len);
11461free_lstval:
11462 while (curallocval > allocval)
11463 vim_free(*--curallocval);
11464 vim_free(lstval);
11465 }
11466 else
11467 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011468 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011469 if (strval == NULL)
11470 return;
11471 write_reg_contents_ex(regname, strval, -1,
11472 append, yank_type, block_len);
11473 }
11474 rettv->vval.v_number = 0;
11475}
11476
11477/*
11478 * "settabvar()" function
11479 */
11480 static void
11481f_settabvar(typval_T *argvars, typval_T *rettv)
11482{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011483 tabpage_T *save_curtab;
11484 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011485 char_u *varname, *tabvarname;
11486 typval_T *varp;
11487
11488 rettv->vval.v_number = 0;
11489
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011490 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011491 return;
11492
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011493 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11494 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011495 varp = &argvars[2];
11496
Bram Moolenaar4033c552017-09-16 20:54:51 +020011497 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011498 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011499 save_curtab = curtab;
11500 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011501
11502 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11503 if (tabvarname != NULL)
11504 {
11505 STRCPY(tabvarname, "t:");
11506 STRCPY(tabvarname + 2, varname);
11507 set_var(tabvarname, varp, TRUE);
11508 vim_free(tabvarname);
11509 }
11510
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011511 /* Restore current tabpage */
11512 if (valid_tabpage(save_curtab))
11513 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011514 }
11515}
11516
11517/*
11518 * "settabwinvar()" function
11519 */
11520 static void
11521f_settabwinvar(typval_T *argvars, typval_T *rettv)
11522{
11523 setwinvar(argvars, rettv, 1);
11524}
11525
11526/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011527 * "settagstack()" function
11528 */
11529 static void
11530f_settagstack(typval_T *argvars, typval_T *rettv)
11531{
11532 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11533 win_T *wp;
11534 dict_T *d;
11535 int action = 'r';
11536
11537 rettv->vval.v_number = -1;
11538
11539 // first argument: window number or id
11540 wp = find_win_by_nr_or_id(&argvars[0]);
11541 if (wp == NULL)
11542 return;
11543
11544 // second argument: dict with items to set in the tag stack
11545 if (argvars[1].v_type != VAR_DICT)
11546 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011547 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011548 return;
11549 }
11550 d = argvars[1].vval.v_dict;
11551 if (d == NULL)
11552 return;
11553
11554 // third argument: action - 'a' for append and 'r' for replace.
11555 // default is to replace the stack.
11556 if (argvars[2].v_type == VAR_UNKNOWN)
11557 action = 'r';
11558 else if (argvars[2].v_type == VAR_STRING)
11559 {
11560 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011561 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011562 if (actstr == NULL)
11563 return;
11564 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11565 action = *actstr;
11566 else
11567 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011568 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011569 return;
11570 }
11571 }
11572 else
11573 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011574 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011575 return;
11576 }
11577
11578 if (set_tagstack(wp, d, action) == OK)
11579 rettv->vval.v_number = 0;
11580}
11581
11582/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011583 * "setwinvar()" function
11584 */
11585 static void
11586f_setwinvar(typval_T *argvars, typval_T *rettv)
11587{
11588 setwinvar(argvars, rettv, 0);
11589}
11590
11591#ifdef FEAT_CRYPT
11592/*
11593 * "sha256({string})" function
11594 */
11595 static void
11596f_sha256(typval_T *argvars, typval_T *rettv)
11597{
11598 char_u *p;
11599
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011600 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011601 rettv->vval.v_string = vim_strsave(
11602 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11603 rettv->v_type = VAR_STRING;
11604}
11605#endif /* FEAT_CRYPT */
11606
11607/*
11608 * "shellescape({string})" function
11609 */
11610 static void
11611f_shellescape(typval_T *argvars, typval_T *rettv)
11612{
Bram Moolenaar20615522017-06-05 18:46:26 +020011613 int do_special = non_zero_arg(&argvars[1]);
11614
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011615 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011616 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011617 rettv->v_type = VAR_STRING;
11618}
11619
11620/*
11621 * shiftwidth() function
11622 */
11623 static void
11624f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11625{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011626 rettv->vval.v_number = 0;
11627
11628 if (argvars[0].v_type != VAR_UNKNOWN)
11629 {
11630 long col;
11631
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011632 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011633 if (col < 0)
11634 return; // type error; errmsg already given
11635#ifdef FEAT_VARTABS
11636 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11637 return;
11638#endif
11639 }
11640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011641 rettv->vval.v_number = get_sw_value(curbuf);
11642}
11643
Bram Moolenaar162b7142018-12-21 15:17:36 +010011644#ifdef FEAT_SIGNS
11645/*
11646 * "sign_define()" function
11647 */
11648 static void
11649f_sign_define(typval_T *argvars, typval_T *rettv)
11650{
11651 char_u *name;
11652 dict_T *dict;
11653 char_u *icon = NULL;
11654 char_u *linehl = NULL;
11655 char_u *text = NULL;
11656 char_u *texthl = NULL;
11657
11658 rettv->vval.v_number = -1;
11659
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011660 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011661 if (name == NULL)
11662 return;
11663
11664 if (argvars[1].v_type != VAR_UNKNOWN)
11665 {
11666 if (argvars[1].v_type != VAR_DICT)
11667 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011668 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011669 return;
11670 }
11671
11672 // sign attributes
11673 dict = argvars[1].vval.v_dict;
11674 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11675 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11676 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11677 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11678 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11679 text = dict_get_string(dict, (char_u *)"text", TRUE);
11680 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11681 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11682 }
11683
11684 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11685 rettv->vval.v_number = 0;
11686
11687 vim_free(icon);
11688 vim_free(linehl);
11689 vim_free(text);
11690 vim_free(texthl);
11691}
11692
11693/*
11694 * "sign_getdefined()" function
11695 */
11696 static void
11697f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11698{
11699 char_u *name = NULL;
11700
11701 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11702 return;
11703
11704 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011705 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011706
11707 sign_getlist(name, rettv->vval.v_list);
11708}
11709
11710/*
11711 * "sign_getplaced()" function
11712 */
11713 static void
11714f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11715{
11716 buf_T *buf = NULL;
11717 dict_T *dict;
11718 dictitem_T *di;
11719 linenr_T lnum = 0;
11720 int sign_id = 0;
11721 char_u *group = NULL;
11722 int notanum = FALSE;
11723
11724 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11725 return;
11726
11727 if (argvars[0].v_type != VAR_UNKNOWN)
11728 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011729 // get signs placed in the specified buffer
11730 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011731 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011732 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011733
11734 if (argvars[1].v_type != VAR_UNKNOWN)
11735 {
11736 if (argvars[1].v_type != VAR_DICT ||
11737 ((dict = argvars[1].vval.v_dict) == NULL))
11738 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011739 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011740 return;
11741 }
11742 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11743 {
11744 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011745 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011746 if (notanum)
11747 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011748 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011749 }
11750 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11751 {
11752 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011753 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011754 if (notanum)
11755 return;
11756 }
11757 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11758 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011759 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011760 if (group == NULL)
11761 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011762 if (*group == '\0') // empty string means global group
11763 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011764 }
11765 }
11766 }
11767
11768 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11769}
11770
11771/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011772 * "sign_jump()" function
11773 */
11774 static void
11775f_sign_jump(typval_T *argvars, typval_T *rettv)
11776{
11777 int sign_id;
11778 char_u *sign_group = NULL;
11779 buf_T *buf;
11780 int notanum = FALSE;
11781
11782 rettv->vval.v_number = -1;
11783
Bram Moolenaarbdace832019-03-02 10:13:42 +010011784 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011785 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11786 if (notanum)
11787 return;
11788 if (sign_id <= 0)
11789 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011790 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011791 return;
11792 }
11793
11794 // Sign group
11795 sign_group = tv_get_string_chk(&argvars[1]);
11796 if (sign_group == NULL)
11797 return;
11798 if (sign_group[0] == '\0')
11799 sign_group = NULL; // global sign group
11800 else
11801 {
11802 sign_group = vim_strsave(sign_group);
11803 if (sign_group == NULL)
11804 return;
11805 }
11806
11807 // Buffer to place the sign
11808 buf = get_buf_arg(&argvars[2]);
11809 if (buf == NULL)
11810 goto cleanup;
11811
11812 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11813
11814cleanup:
11815 vim_free(sign_group);
11816}
11817
11818/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011819 * "sign_place()" function
11820 */
11821 static void
11822f_sign_place(typval_T *argvars, typval_T *rettv)
11823{
11824 int sign_id;
11825 char_u *group = NULL;
11826 char_u *sign_name;
11827 buf_T *buf;
11828 dict_T *dict;
11829 dictitem_T *di;
11830 linenr_T lnum = 0;
11831 int prio = SIGN_DEF_PRIO;
11832 int notanum = FALSE;
11833
11834 rettv->vval.v_number = -1;
11835
Bram Moolenaarbdace832019-03-02 10:13:42 +010011836 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011837 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011838 if (notanum)
11839 return;
11840 if (sign_id < 0)
11841 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011842 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011843 return;
11844 }
11845
11846 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011847 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011848 if (group == NULL)
11849 return;
11850 if (group[0] == '\0')
11851 group = NULL; // global sign group
11852 else
11853 {
11854 group = vim_strsave(group);
11855 if (group == NULL)
11856 return;
11857 }
11858
11859 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011860 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011861 if (sign_name == NULL)
11862 goto cleanup;
11863
11864 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011865 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011866 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011867 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011868
11869 if (argvars[4].v_type != VAR_UNKNOWN)
11870 {
11871 if (argvars[4].v_type != VAR_DICT ||
11872 ((dict = argvars[4].vval.v_dict) == NULL))
11873 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011874 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011875 goto cleanup;
11876 }
11877
11878 // Line number where the sign is to be placed
11879 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011881 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011882 if (notanum)
11883 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011884 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011885 }
11886 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11887 {
11888 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011889 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011890 if (notanum)
11891 goto cleanup;
11892 }
11893 }
11894
11895 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11896 rettv->vval.v_number = sign_id;
11897
11898cleanup:
11899 vim_free(group);
11900}
11901
11902/*
11903 * "sign_undefine()" function
11904 */
11905 static void
11906f_sign_undefine(typval_T *argvars, typval_T *rettv)
11907{
11908 char_u *name;
11909
11910 rettv->vval.v_number = -1;
11911
11912 if (argvars[0].v_type == VAR_UNKNOWN)
11913 {
11914 // Free all the signs
11915 free_signs();
11916 rettv->vval.v_number = 0;
11917 }
11918 else
11919 {
11920 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011921 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011922 if (name == NULL)
11923 return;
11924
11925 if (sign_undefine_by_name(name) == OK)
11926 rettv->vval.v_number = 0;
11927 }
11928}
11929
11930/*
11931 * "sign_unplace()" function
11932 */
11933 static void
11934f_sign_unplace(typval_T *argvars, typval_T *rettv)
11935{
11936 dict_T *dict;
11937 dictitem_T *di;
11938 int sign_id = 0;
11939 buf_T *buf = NULL;
11940 char_u *group = NULL;
11941
11942 rettv->vval.v_number = -1;
11943
11944 if (argvars[0].v_type != VAR_STRING)
11945 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011946 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011947 return;
11948 }
11949
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011950 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011951 if (group[0] == '\0')
11952 group = NULL; // global sign group
11953 else
11954 {
11955 group = vim_strsave(group);
11956 if (group == NULL)
11957 return;
11958 }
11959
11960 if (argvars[1].v_type != VAR_UNKNOWN)
11961 {
11962 if (argvars[1].v_type != VAR_DICT)
11963 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011964 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011965 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011966 }
11967 dict = argvars[1].vval.v_dict;
11968
11969 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11970 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011971 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011972 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011973 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011974 }
11975 if (dict_find(dict, (char_u *)"id", -1) != NULL)
11976 sign_id = dict_get_number(dict, (char_u *)"id");
11977 }
11978
11979 if (buf == NULL)
11980 {
11981 // Delete the sign in all the buffers
11982 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011983 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011984 rettv->vval.v_number = 0;
11985 }
11986 else
11987 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010011988 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011989 rettv->vval.v_number = 0;
11990 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011991
11992cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010011993 vim_free(group);
11994}
11995#endif
11996
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011997/*
11998 * "simplify()" function
11999 */
12000 static void
12001f_simplify(typval_T *argvars, typval_T *rettv)
12002{
12003 char_u *p;
12004
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012005 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012006 rettv->vval.v_string = vim_strsave(p);
12007 simplify_filename(rettv->vval.v_string); /* simplify in place */
12008 rettv->v_type = VAR_STRING;
12009}
12010
12011#ifdef FEAT_FLOAT
12012/*
12013 * "sin()" function
12014 */
12015 static void
12016f_sin(typval_T *argvars, typval_T *rettv)
12017{
12018 float_T f = 0.0;
12019
12020 rettv->v_type = VAR_FLOAT;
12021 if (get_float_arg(argvars, &f) == OK)
12022 rettv->vval.v_float = sin(f);
12023 else
12024 rettv->vval.v_float = 0.0;
12025}
12026
12027/*
12028 * "sinh()" function
12029 */
12030 static void
12031f_sinh(typval_T *argvars, typval_T *rettv)
12032{
12033 float_T f = 0.0;
12034
12035 rettv->v_type = VAR_FLOAT;
12036 if (get_float_arg(argvars, &f) == OK)
12037 rettv->vval.v_float = sinh(f);
12038 else
12039 rettv->vval.v_float = 0.0;
12040}
12041#endif
12042
12043static int
12044#ifdef __BORLANDC__
12045 _RTLENTRYF
12046#endif
12047 item_compare(const void *s1, const void *s2);
12048static int
12049#ifdef __BORLANDC__
12050 _RTLENTRYF
12051#endif
12052 item_compare2(const void *s1, const void *s2);
12053
12054/* struct used in the array that's given to qsort() */
12055typedef struct
12056{
12057 listitem_T *item;
12058 int idx;
12059} sortItem_T;
12060
12061/* struct storing information about current sort */
12062typedef struct
12063{
12064 int item_compare_ic;
12065 int item_compare_numeric;
12066 int item_compare_numbers;
12067#ifdef FEAT_FLOAT
12068 int item_compare_float;
12069#endif
12070 char_u *item_compare_func;
12071 partial_T *item_compare_partial;
12072 dict_T *item_compare_selfdict;
12073 int item_compare_func_err;
12074 int item_compare_keep_zero;
12075} sortinfo_T;
12076static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012077#define ITEM_COMPARE_FAIL 999
12078
12079/*
12080 * Compare functions for f_sort() and f_uniq() below.
12081 */
12082 static int
12083#ifdef __BORLANDC__
12084_RTLENTRYF
12085#endif
12086item_compare(const void *s1, const void *s2)
12087{
12088 sortItem_T *si1, *si2;
12089 typval_T *tv1, *tv2;
12090 char_u *p1, *p2;
12091 char_u *tofree1 = NULL, *tofree2 = NULL;
12092 int res;
12093 char_u numbuf1[NUMBUFLEN];
12094 char_u numbuf2[NUMBUFLEN];
12095
12096 si1 = (sortItem_T *)s1;
12097 si2 = (sortItem_T *)s2;
12098 tv1 = &si1->item->li_tv;
12099 tv2 = &si2->item->li_tv;
12100
12101 if (sortinfo->item_compare_numbers)
12102 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012103 varnumber_T v1 = tv_get_number(tv1);
12104 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012105
12106 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12107 }
12108
12109#ifdef FEAT_FLOAT
12110 if (sortinfo->item_compare_float)
12111 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012112 float_T v1 = tv_get_float(tv1);
12113 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012114
12115 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12116 }
12117#endif
12118
12119 /* tv2string() puts quotes around a string and allocates memory. Don't do
12120 * that for string variables. Use a single quote when comparing with a
12121 * non-string to do what the docs promise. */
12122 if (tv1->v_type == VAR_STRING)
12123 {
12124 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12125 p1 = (char_u *)"'";
12126 else
12127 p1 = tv1->vval.v_string;
12128 }
12129 else
12130 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12131 if (tv2->v_type == VAR_STRING)
12132 {
12133 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12134 p2 = (char_u *)"'";
12135 else
12136 p2 = tv2->vval.v_string;
12137 }
12138 else
12139 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12140 if (p1 == NULL)
12141 p1 = (char_u *)"";
12142 if (p2 == NULL)
12143 p2 = (char_u *)"";
12144 if (!sortinfo->item_compare_numeric)
12145 {
12146 if (sortinfo->item_compare_ic)
12147 res = STRICMP(p1, p2);
12148 else
12149 res = STRCMP(p1, p2);
12150 }
12151 else
12152 {
12153 double n1, n2;
12154 n1 = strtod((char *)p1, (char **)&p1);
12155 n2 = strtod((char *)p2, (char **)&p2);
12156 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12157 }
12158
12159 /* When the result would be zero, compare the item indexes. Makes the
12160 * sort stable. */
12161 if (res == 0 && !sortinfo->item_compare_keep_zero)
12162 res = si1->idx > si2->idx ? 1 : -1;
12163
12164 vim_free(tofree1);
12165 vim_free(tofree2);
12166 return res;
12167}
12168
12169 static int
12170#ifdef __BORLANDC__
12171_RTLENTRYF
12172#endif
12173item_compare2(const void *s1, const void *s2)
12174{
12175 sortItem_T *si1, *si2;
12176 int res;
12177 typval_T rettv;
12178 typval_T argv[3];
12179 int dummy;
12180 char_u *func_name;
12181 partial_T *partial = sortinfo->item_compare_partial;
12182
12183 /* shortcut after failure in previous call; compare all items equal */
12184 if (sortinfo->item_compare_func_err)
12185 return 0;
12186
12187 si1 = (sortItem_T *)s1;
12188 si2 = (sortItem_T *)s2;
12189
12190 if (partial == NULL)
12191 func_name = sortinfo->item_compare_func;
12192 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012193 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012194
12195 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12196 * in the copy without changing the original list items. */
12197 copy_tv(&si1->item->li_tv, &argv[0]);
12198 copy_tv(&si2->item->li_tv, &argv[1]);
12199
12200 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12201 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012202 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012203 partial, sortinfo->item_compare_selfdict);
12204 clear_tv(&argv[0]);
12205 clear_tv(&argv[1]);
12206
12207 if (res == FAIL)
12208 res = ITEM_COMPARE_FAIL;
12209 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012210 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012211 if (sortinfo->item_compare_func_err)
12212 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12213 clear_tv(&rettv);
12214
12215 /* When the result would be zero, compare the pointers themselves. Makes
12216 * the sort stable. */
12217 if (res == 0 && !sortinfo->item_compare_keep_zero)
12218 res = si1->idx > si2->idx ? 1 : -1;
12219
12220 return res;
12221}
12222
12223/*
12224 * "sort({list})" function
12225 */
12226 static void
12227do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12228{
12229 list_T *l;
12230 listitem_T *li;
12231 sortItem_T *ptrs;
12232 sortinfo_T *old_sortinfo;
12233 sortinfo_T info;
12234 long len;
12235 long i;
12236
12237 /* Pointer to current info struct used in compare function. Save and
12238 * restore the current one for nested calls. */
12239 old_sortinfo = sortinfo;
12240 sortinfo = &info;
12241
12242 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012243 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012244 else
12245 {
12246 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012247 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012248 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12249 TRUE))
12250 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012251 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012252
12253 len = list_len(l);
12254 if (len <= 1)
12255 goto theend; /* short list sorts pretty quickly */
12256
12257 info.item_compare_ic = FALSE;
12258 info.item_compare_numeric = FALSE;
12259 info.item_compare_numbers = FALSE;
12260#ifdef FEAT_FLOAT
12261 info.item_compare_float = FALSE;
12262#endif
12263 info.item_compare_func = NULL;
12264 info.item_compare_partial = NULL;
12265 info.item_compare_selfdict = NULL;
12266 if (argvars[1].v_type != VAR_UNKNOWN)
12267 {
12268 /* optional second argument: {func} */
12269 if (argvars[1].v_type == VAR_FUNC)
12270 info.item_compare_func = argvars[1].vval.v_string;
12271 else if (argvars[1].v_type == VAR_PARTIAL)
12272 info.item_compare_partial = argvars[1].vval.v_partial;
12273 else
12274 {
12275 int error = FALSE;
12276
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012277 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012278 if (error)
12279 goto theend; /* type error; errmsg already given */
12280 if (i == 1)
12281 info.item_compare_ic = TRUE;
12282 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012283 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012284 else if (i != 0)
12285 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012286 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012287 goto theend;
12288 }
12289 if (info.item_compare_func != NULL)
12290 {
12291 if (*info.item_compare_func == NUL)
12292 {
12293 /* empty string means default sort */
12294 info.item_compare_func = NULL;
12295 }
12296 else if (STRCMP(info.item_compare_func, "n") == 0)
12297 {
12298 info.item_compare_func = NULL;
12299 info.item_compare_numeric = TRUE;
12300 }
12301 else if (STRCMP(info.item_compare_func, "N") == 0)
12302 {
12303 info.item_compare_func = NULL;
12304 info.item_compare_numbers = TRUE;
12305 }
12306#ifdef FEAT_FLOAT
12307 else if (STRCMP(info.item_compare_func, "f") == 0)
12308 {
12309 info.item_compare_func = NULL;
12310 info.item_compare_float = TRUE;
12311 }
12312#endif
12313 else if (STRCMP(info.item_compare_func, "i") == 0)
12314 {
12315 info.item_compare_func = NULL;
12316 info.item_compare_ic = TRUE;
12317 }
12318 }
12319 }
12320
12321 if (argvars[2].v_type != VAR_UNKNOWN)
12322 {
12323 /* optional third argument: {dict} */
12324 if (argvars[2].v_type != VAR_DICT)
12325 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012326 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012327 goto theend;
12328 }
12329 info.item_compare_selfdict = argvars[2].vval.v_dict;
12330 }
12331 }
12332
12333 /* Make an array with each entry pointing to an item in the List. */
12334 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12335 if (ptrs == NULL)
12336 goto theend;
12337
12338 i = 0;
12339 if (sort)
12340 {
12341 /* sort(): ptrs will be the list to sort */
12342 for (li = l->lv_first; li != NULL; li = li->li_next)
12343 {
12344 ptrs[i].item = li;
12345 ptrs[i].idx = i;
12346 ++i;
12347 }
12348
12349 info.item_compare_func_err = FALSE;
12350 info.item_compare_keep_zero = FALSE;
12351 /* test the compare function */
12352 if ((info.item_compare_func != NULL
12353 || info.item_compare_partial != NULL)
12354 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12355 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012356 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 else
12358 {
12359 /* Sort the array with item pointers. */
12360 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12361 info.item_compare_func == NULL
12362 && info.item_compare_partial == NULL
12363 ? item_compare : item_compare2);
12364
12365 if (!info.item_compare_func_err)
12366 {
12367 /* Clear the List and append the items in sorted order. */
12368 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12369 l->lv_len = 0;
12370 for (i = 0; i < len; ++i)
12371 list_append(l, ptrs[i].item);
12372 }
12373 }
12374 }
12375 else
12376 {
12377 int (*item_compare_func_ptr)(const void *, const void *);
12378
12379 /* f_uniq(): ptrs will be a stack of items to remove */
12380 info.item_compare_func_err = FALSE;
12381 info.item_compare_keep_zero = TRUE;
12382 item_compare_func_ptr = info.item_compare_func != NULL
12383 || info.item_compare_partial != NULL
12384 ? item_compare2 : item_compare;
12385
12386 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12387 li = li->li_next)
12388 {
12389 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12390 == 0)
12391 ptrs[i++].item = li;
12392 if (info.item_compare_func_err)
12393 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012394 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012395 break;
12396 }
12397 }
12398
12399 if (!info.item_compare_func_err)
12400 {
12401 while (--i >= 0)
12402 {
12403 li = ptrs[i].item->li_next;
12404 ptrs[i].item->li_next = li->li_next;
12405 if (li->li_next != NULL)
12406 li->li_next->li_prev = ptrs[i].item;
12407 else
12408 l->lv_last = ptrs[i].item;
12409 list_fix_watch(l, li);
12410 listitem_free(li);
12411 l->lv_len--;
12412 }
12413 }
12414 }
12415
12416 vim_free(ptrs);
12417 }
12418theend:
12419 sortinfo = old_sortinfo;
12420}
12421
12422/*
12423 * "sort({list})" function
12424 */
12425 static void
12426f_sort(typval_T *argvars, typval_T *rettv)
12427{
12428 do_sort_uniq(argvars, rettv, TRUE);
12429}
12430
12431/*
12432 * "uniq({list})" function
12433 */
12434 static void
12435f_uniq(typval_T *argvars, typval_T *rettv)
12436{
12437 do_sort_uniq(argvars, rettv, FALSE);
12438}
12439
12440/*
12441 * "soundfold({word})" function
12442 */
12443 static void
12444f_soundfold(typval_T *argvars, typval_T *rettv)
12445{
12446 char_u *s;
12447
12448 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012449 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012450#ifdef FEAT_SPELL
12451 rettv->vval.v_string = eval_soundfold(s);
12452#else
12453 rettv->vval.v_string = vim_strsave(s);
12454#endif
12455}
12456
12457/*
12458 * "spellbadword()" function
12459 */
12460 static void
12461f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12462{
12463 char_u *word = (char_u *)"";
12464 hlf_T attr = HLF_COUNT;
12465 int len = 0;
12466
12467 if (rettv_list_alloc(rettv) == FAIL)
12468 return;
12469
12470#ifdef FEAT_SPELL
12471 if (argvars[0].v_type == VAR_UNKNOWN)
12472 {
12473 /* Find the start and length of the badly spelled word. */
12474 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12475 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012476 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012477 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012478 curwin->w_set_curswant = TRUE;
12479 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012480 }
12481 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12482 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012483 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012484 int capcol = -1;
12485
12486 if (str != NULL)
12487 {
12488 /* Check the argument for spelling. */
12489 while (*str != NUL)
12490 {
12491 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12492 if (attr != HLF_COUNT)
12493 {
12494 word = str;
12495 break;
12496 }
12497 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012498 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012499 }
12500 }
12501 }
12502#endif
12503
12504 list_append_string(rettv->vval.v_list, word, len);
12505 list_append_string(rettv->vval.v_list, (char_u *)(
12506 attr == HLF_SPB ? "bad" :
12507 attr == HLF_SPR ? "rare" :
12508 attr == HLF_SPL ? "local" :
12509 attr == HLF_SPC ? "caps" :
12510 ""), -1);
12511}
12512
12513/*
12514 * "spellsuggest()" function
12515 */
12516 static void
12517f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12518{
12519#ifdef FEAT_SPELL
12520 char_u *str;
12521 int typeerr = FALSE;
12522 int maxcount;
12523 garray_T ga;
12524 int i;
12525 listitem_T *li;
12526 int need_capital = FALSE;
12527#endif
12528
12529 if (rettv_list_alloc(rettv) == FAIL)
12530 return;
12531
12532#ifdef FEAT_SPELL
12533 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12534 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012535 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012536 if (argvars[1].v_type != VAR_UNKNOWN)
12537 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012538 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012539 if (maxcount <= 0)
12540 return;
12541 if (argvars[2].v_type != VAR_UNKNOWN)
12542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012543 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012544 if (typeerr)
12545 return;
12546 }
12547 }
12548 else
12549 maxcount = 25;
12550
12551 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12552
12553 for (i = 0; i < ga.ga_len; ++i)
12554 {
12555 str = ((char_u **)ga.ga_data)[i];
12556
12557 li = listitem_alloc();
12558 if (li == NULL)
12559 vim_free(str);
12560 else
12561 {
12562 li->li_tv.v_type = VAR_STRING;
12563 li->li_tv.v_lock = 0;
12564 li->li_tv.vval.v_string = str;
12565 list_append(rettv->vval.v_list, li);
12566 }
12567 }
12568 ga_clear(&ga);
12569 }
12570#endif
12571}
12572
12573 static void
12574f_split(typval_T *argvars, typval_T *rettv)
12575{
12576 char_u *str;
12577 char_u *end;
12578 char_u *pat = NULL;
12579 regmatch_T regmatch;
12580 char_u patbuf[NUMBUFLEN];
12581 char_u *save_cpo;
12582 int match;
12583 colnr_T col = 0;
12584 int keepempty = FALSE;
12585 int typeerr = FALSE;
12586
12587 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12588 save_cpo = p_cpo;
12589 p_cpo = (char_u *)"";
12590
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012591 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012592 if (argvars[1].v_type != VAR_UNKNOWN)
12593 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012594 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012595 if (pat == NULL)
12596 typeerr = TRUE;
12597 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012598 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012599 }
12600 if (pat == NULL || *pat == NUL)
12601 pat = (char_u *)"[\\x01- ]\\+";
12602
12603 if (rettv_list_alloc(rettv) == FAIL)
12604 return;
12605 if (typeerr)
12606 return;
12607
12608 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12609 if (regmatch.regprog != NULL)
12610 {
12611 regmatch.rm_ic = FALSE;
12612 while (*str != NUL || keepempty)
12613 {
12614 if (*str == NUL)
12615 match = FALSE; /* empty item at the end */
12616 else
12617 match = vim_regexec_nl(&regmatch, str, col);
12618 if (match)
12619 end = regmatch.startp[0];
12620 else
12621 end = str + STRLEN(str);
12622 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12623 && *str != NUL && match && end < regmatch.endp[0]))
12624 {
12625 if (list_append_string(rettv->vval.v_list, str,
12626 (int)(end - str)) == FAIL)
12627 break;
12628 }
12629 if (!match)
12630 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012631 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012632 if (regmatch.endp[0] > str)
12633 col = 0;
12634 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012635 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012636 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012637 str = regmatch.endp[0];
12638 }
12639
12640 vim_regfree(regmatch.regprog);
12641 }
12642
12643 p_cpo = save_cpo;
12644}
12645
12646#ifdef FEAT_FLOAT
12647/*
12648 * "sqrt()" function
12649 */
12650 static void
12651f_sqrt(typval_T *argvars, typval_T *rettv)
12652{
12653 float_T f = 0.0;
12654
12655 rettv->v_type = VAR_FLOAT;
12656 if (get_float_arg(argvars, &f) == OK)
12657 rettv->vval.v_float = sqrt(f);
12658 else
12659 rettv->vval.v_float = 0.0;
12660}
12661
12662/*
12663 * "str2float()" function
12664 */
12665 static void
12666f_str2float(typval_T *argvars, typval_T *rettv)
12667{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012668 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012669 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012670
Bram Moolenaar08243d22017-01-10 16:12:29 +010012671 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672 p = skipwhite(p + 1);
12673 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012674 if (isneg)
12675 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012676 rettv->v_type = VAR_FLOAT;
12677}
12678#endif
12679
12680/*
12681 * "str2nr()" function
12682 */
12683 static void
12684f_str2nr(typval_T *argvars, typval_T *rettv)
12685{
12686 int base = 10;
12687 char_u *p;
12688 varnumber_T n;
12689 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012690 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012691
12692 if (argvars[1].v_type != VAR_UNKNOWN)
12693 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012694 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012695 if (base != 2 && base != 8 && base != 10 && base != 16)
12696 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012697 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012698 return;
12699 }
12700 }
12701
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012702 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012703 isneg = (*p == '-');
12704 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012705 p = skipwhite(p + 1);
12706 switch (base)
12707 {
12708 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12709 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12710 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12711 default: what = 0;
12712 }
12713 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012714 if (isneg)
12715 rettv->vval.v_number = -n;
12716 else
12717 rettv->vval.v_number = n;
12718
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012719}
12720
12721#ifdef HAVE_STRFTIME
12722/*
12723 * "strftime({format}[, {time}])" function
12724 */
12725 static void
12726f_strftime(typval_T *argvars, typval_T *rettv)
12727{
12728 char_u result_buf[256];
12729 struct tm *curtime;
12730 time_t seconds;
12731 char_u *p;
12732
12733 rettv->v_type = VAR_STRING;
12734
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012735 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012736 if (argvars[1].v_type == VAR_UNKNOWN)
12737 seconds = time(NULL);
12738 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012739 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012740 curtime = localtime(&seconds);
12741 /* MSVC returns NULL for an invalid value of seconds. */
12742 if (curtime == NULL)
12743 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12744 else
12745 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012746 vimconv_T conv;
12747 char_u *enc;
12748
12749 conv.vc_type = CONV_NONE;
12750 enc = enc_locale();
12751 convert_setup(&conv, p_enc, enc);
12752 if (conv.vc_type != CONV_NONE)
12753 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012754 if (p != NULL)
12755 (void)strftime((char *)result_buf, sizeof(result_buf),
12756 (char *)p, curtime);
12757 else
12758 result_buf[0] = NUL;
12759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012760 if (conv.vc_type != CONV_NONE)
12761 vim_free(p);
12762 convert_setup(&conv, enc, p_enc);
12763 if (conv.vc_type != CONV_NONE)
12764 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12765 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012766 rettv->vval.v_string = vim_strsave(result_buf);
12767
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012768 /* Release conversion descriptors */
12769 convert_setup(&conv, NULL, NULL);
12770 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 }
12772}
12773#endif
12774
12775/*
12776 * "strgetchar()" function
12777 */
12778 static void
12779f_strgetchar(typval_T *argvars, typval_T *rettv)
12780{
12781 char_u *str;
12782 int len;
12783 int error = FALSE;
12784 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012785 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012786
12787 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012788 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012789 if (str == NULL)
12790 return;
12791 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012792 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012793 if (error)
12794 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012795
Bram Moolenaar13505972019-01-24 15:04:48 +010012796 while (charidx >= 0 && byteidx < len)
12797 {
12798 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012799 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012800 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12801 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012802 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012803 --charidx;
12804 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012805 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012806}
12807
12808/*
12809 * "stridx()" function
12810 */
12811 static void
12812f_stridx(typval_T *argvars, typval_T *rettv)
12813{
12814 char_u buf[NUMBUFLEN];
12815 char_u *needle;
12816 char_u *haystack;
12817 char_u *save_haystack;
12818 char_u *pos;
12819 int start_idx;
12820
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012821 needle = tv_get_string_chk(&argvars[1]);
12822 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012823 rettv->vval.v_number = -1;
12824 if (needle == NULL || haystack == NULL)
12825 return; /* type error; errmsg already given */
12826
12827 if (argvars[2].v_type != VAR_UNKNOWN)
12828 {
12829 int error = FALSE;
12830
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012831 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012832 if (error || start_idx >= (int)STRLEN(haystack))
12833 return;
12834 if (start_idx >= 0)
12835 haystack += start_idx;
12836 }
12837
12838 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12839 if (pos != NULL)
12840 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12841}
12842
12843/*
12844 * "string()" function
12845 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012846 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012847f_string(typval_T *argvars, typval_T *rettv)
12848{
12849 char_u *tofree;
12850 char_u numbuf[NUMBUFLEN];
12851
12852 rettv->v_type = VAR_STRING;
12853 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12854 get_copyID());
12855 /* Make a copy if we have a value but it's not in allocated memory. */
12856 if (rettv->vval.v_string != NULL && tofree == NULL)
12857 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12858}
12859
12860/*
12861 * "strlen()" function
12862 */
12863 static void
12864f_strlen(typval_T *argvars, typval_T *rettv)
12865{
12866 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012867 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012868}
12869
12870/*
12871 * "strchars()" function
12872 */
12873 static void
12874f_strchars(typval_T *argvars, typval_T *rettv)
12875{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012876 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012877 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012878 varnumber_T len = 0;
12879 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012880
12881 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012882 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012883 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012884 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012885 else
12886 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012887 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12888 while (*s != NUL)
12889 {
12890 func_mb_ptr2char_adv(&s);
12891 ++len;
12892 }
12893 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012894 }
12895}
12896
12897/*
12898 * "strdisplaywidth()" function
12899 */
12900 static void
12901f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12902{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012903 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012904 int col = 0;
12905
12906 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012907 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012908
12909 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12910}
12911
12912/*
12913 * "strwidth()" function
12914 */
12915 static void
12916f_strwidth(typval_T *argvars, typval_T *rettv)
12917{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012918 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012919
Bram Moolenaar13505972019-01-24 15:04:48 +010012920 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012921}
12922
12923/*
12924 * "strcharpart()" function
12925 */
12926 static void
12927f_strcharpart(typval_T *argvars, typval_T *rettv)
12928{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012929 char_u *p;
12930 int nchar;
12931 int nbyte = 0;
12932 int charlen;
12933 int len = 0;
12934 int slen;
12935 int error = FALSE;
12936
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012937 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012938 slen = (int)STRLEN(p);
12939
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012940 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012941 if (!error)
12942 {
12943 if (nchar > 0)
12944 while (nchar > 0 && nbyte < slen)
12945 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012946 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012947 --nchar;
12948 }
12949 else
12950 nbyte = nchar;
12951 if (argvars[2].v_type != VAR_UNKNOWN)
12952 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012953 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012954 while (charlen > 0 && nbyte + len < slen)
12955 {
12956 int off = nbyte + len;
12957
12958 if (off < 0)
12959 len += 1;
12960 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012961 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012962 --charlen;
12963 }
12964 }
12965 else
12966 len = slen - nbyte; /* default: all bytes that are available. */
12967 }
12968
12969 /*
12970 * Only return the overlap between the specified part and the actual
12971 * string.
12972 */
12973 if (nbyte < 0)
12974 {
12975 len += nbyte;
12976 nbyte = 0;
12977 }
12978 else if (nbyte > slen)
12979 nbyte = slen;
12980 if (len < 0)
12981 len = 0;
12982 else if (nbyte + len > slen)
12983 len = slen - nbyte;
12984
12985 rettv->v_type = VAR_STRING;
12986 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012987}
12988
12989/*
12990 * "strpart()" function
12991 */
12992 static void
12993f_strpart(typval_T *argvars, typval_T *rettv)
12994{
12995 char_u *p;
12996 int n;
12997 int len;
12998 int slen;
12999 int error = FALSE;
13000
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013001 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013002 slen = (int)STRLEN(p);
13003
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013004 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013005 if (error)
13006 len = 0;
13007 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013008 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013009 else
13010 len = slen - n; /* default len: all bytes that are available. */
13011
13012 /*
13013 * Only return the overlap between the specified part and the actual
13014 * string.
13015 */
13016 if (n < 0)
13017 {
13018 len += n;
13019 n = 0;
13020 }
13021 else if (n > slen)
13022 n = slen;
13023 if (len < 0)
13024 len = 0;
13025 else if (n + len > slen)
13026 len = slen - n;
13027
13028 rettv->v_type = VAR_STRING;
13029 rettv->vval.v_string = vim_strnsave(p + n, len);
13030}
13031
13032/*
13033 * "strridx()" function
13034 */
13035 static void
13036f_strridx(typval_T *argvars, typval_T *rettv)
13037{
13038 char_u buf[NUMBUFLEN];
13039 char_u *needle;
13040 char_u *haystack;
13041 char_u *rest;
13042 char_u *lastmatch = NULL;
13043 int haystack_len, end_idx;
13044
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013045 needle = tv_get_string_chk(&argvars[1]);
13046 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013047
13048 rettv->vval.v_number = -1;
13049 if (needle == NULL || haystack == NULL)
13050 return; /* type error; errmsg already given */
13051
13052 haystack_len = (int)STRLEN(haystack);
13053 if (argvars[2].v_type != VAR_UNKNOWN)
13054 {
13055 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013056 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013057 if (end_idx < 0)
13058 return; /* can never find a match */
13059 }
13060 else
13061 end_idx = haystack_len;
13062
13063 if (*needle == NUL)
13064 {
13065 /* Empty string matches past the end. */
13066 lastmatch = haystack + end_idx;
13067 }
13068 else
13069 {
13070 for (rest = haystack; *rest != '\0'; ++rest)
13071 {
13072 rest = (char_u *)strstr((char *)rest, (char *)needle);
13073 if (rest == NULL || rest > haystack + end_idx)
13074 break;
13075 lastmatch = rest;
13076 }
13077 }
13078
13079 if (lastmatch == NULL)
13080 rettv->vval.v_number = -1;
13081 else
13082 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13083}
13084
13085/*
13086 * "strtrans()" function
13087 */
13088 static void
13089f_strtrans(typval_T *argvars, typval_T *rettv)
13090{
13091 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013092 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013093}
13094
13095/*
13096 * "submatch()" function
13097 */
13098 static void
13099f_submatch(typval_T *argvars, typval_T *rettv)
13100{
13101 int error = FALSE;
13102 int no;
13103 int retList = 0;
13104
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013105 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013106 if (error)
13107 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013108 if (no < 0 || no >= NSUBEXP)
13109 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013110 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013111 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013112 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013113 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013114 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013115 if (error)
13116 return;
13117
13118 if (retList == 0)
13119 {
13120 rettv->v_type = VAR_STRING;
13121 rettv->vval.v_string = reg_submatch(no);
13122 }
13123 else
13124 {
13125 rettv->v_type = VAR_LIST;
13126 rettv->vval.v_list = reg_submatch_list(no);
13127 }
13128}
13129
13130/*
13131 * "substitute()" function
13132 */
13133 static void
13134f_substitute(typval_T *argvars, typval_T *rettv)
13135{
13136 char_u patbuf[NUMBUFLEN];
13137 char_u subbuf[NUMBUFLEN];
13138 char_u flagsbuf[NUMBUFLEN];
13139
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013140 char_u *str = tv_get_string_chk(&argvars[0]);
13141 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013142 char_u *sub = NULL;
13143 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013144 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013145
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013146 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13147 expr = &argvars[2];
13148 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013149 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013150
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013151 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013152 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13153 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013154 rettv->vval.v_string = NULL;
13155 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013156 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013157}
13158
13159/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013160 * "swapinfo(swap_filename)" function
13161 */
13162 static void
13163f_swapinfo(typval_T *argvars, typval_T *rettv)
13164{
13165 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013166 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013167}
13168
13169/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013170 * "swapname(expr)" function
13171 */
13172 static void
13173f_swapname(typval_T *argvars, typval_T *rettv)
13174{
13175 buf_T *buf;
13176
13177 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013178 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013179 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13180 || buf->b_ml.ml_mfp->mf_fname == NULL)
13181 rettv->vval.v_string = NULL;
13182 else
13183 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13184}
13185
13186/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013187 * "synID(lnum, col, trans)" function
13188 */
13189 static void
13190f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13191{
13192 int id = 0;
13193#ifdef FEAT_SYN_HL
13194 linenr_T lnum;
13195 colnr_T col;
13196 int trans;
13197 int transerr = FALSE;
13198
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013199 lnum = tv_get_lnum(argvars); /* -1 on type error */
13200 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13201 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013202
13203 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13204 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13205 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13206#endif
13207
13208 rettv->vval.v_number = id;
13209}
13210
13211/*
13212 * "synIDattr(id, what [, mode])" function
13213 */
13214 static void
13215f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13216{
13217 char_u *p = NULL;
13218#ifdef FEAT_SYN_HL
13219 int id;
13220 char_u *what;
13221 char_u *mode;
13222 char_u modebuf[NUMBUFLEN];
13223 int modec;
13224
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013225 id = (int)tv_get_number(&argvars[0]);
13226 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013227 if (argvars[2].v_type != VAR_UNKNOWN)
13228 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013229 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013230 modec = TOLOWER_ASC(mode[0]);
13231 if (modec != 't' && modec != 'c' && modec != 'g')
13232 modec = 0; /* replace invalid with current */
13233 }
13234 else
13235 {
13236#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13237 if (USE_24BIT)
13238 modec = 'g';
13239 else
13240#endif
13241 if (t_colors > 1)
13242 modec = 'c';
13243 else
13244 modec = 't';
13245 }
13246
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013247 switch (TOLOWER_ASC(what[0]))
13248 {
13249 case 'b':
13250 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13251 p = highlight_color(id, what, modec);
13252 else /* bold */
13253 p = highlight_has_attr(id, HL_BOLD, modec);
13254 break;
13255
13256 case 'f': /* fg[#] or font */
13257 p = highlight_color(id, what, modec);
13258 break;
13259
13260 case 'i':
13261 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13262 p = highlight_has_attr(id, HL_INVERSE, modec);
13263 else /* italic */
13264 p = highlight_has_attr(id, HL_ITALIC, modec);
13265 break;
13266
13267 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013268 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013269 break;
13270
13271 case 'r': /* reverse */
13272 p = highlight_has_attr(id, HL_INVERSE, modec);
13273 break;
13274
13275 case 's':
13276 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13277 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013278 /* strikeout */
13279 else if (TOLOWER_ASC(what[1]) == 't' &&
13280 TOLOWER_ASC(what[2]) == 'r')
13281 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013282 else /* standout */
13283 p = highlight_has_attr(id, HL_STANDOUT, modec);
13284 break;
13285
13286 case 'u':
13287 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13288 /* underline */
13289 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13290 else
13291 /* undercurl */
13292 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13293 break;
13294 }
13295
13296 if (p != NULL)
13297 p = vim_strsave(p);
13298#endif
13299 rettv->v_type = VAR_STRING;
13300 rettv->vval.v_string = p;
13301}
13302
13303/*
13304 * "synIDtrans(id)" function
13305 */
13306 static void
13307f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13308{
13309 int id;
13310
13311#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013312 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013313
13314 if (id > 0)
13315 id = syn_get_final_id(id);
13316 else
13317#endif
13318 id = 0;
13319
13320 rettv->vval.v_number = id;
13321}
13322
13323/*
13324 * "synconcealed(lnum, col)" function
13325 */
13326 static void
13327f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13328{
13329#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13330 linenr_T lnum;
13331 colnr_T col;
13332 int syntax_flags = 0;
13333 int cchar;
13334 int matchid = 0;
13335 char_u str[NUMBUFLEN];
13336#endif
13337
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013338 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013339
13340#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013341 lnum = tv_get_lnum(argvars); /* -1 on type error */
13342 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013343
13344 vim_memset(str, NUL, sizeof(str));
13345
13346 if (rettv_list_alloc(rettv) != FAIL)
13347 {
13348 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13349 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13350 && curwin->w_p_cole > 0)
13351 {
13352 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13353 syntax_flags = get_syntax_info(&matchid);
13354
13355 /* get the conceal character */
13356 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13357 {
13358 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013359 if (cchar == NUL && curwin->w_p_cole == 1)
13360 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013361 if (cchar != NUL)
13362 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013363 if (has_mbyte)
13364 (*mb_char2bytes)(cchar, str);
13365 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013366 str[0] = cchar;
13367 }
13368 }
13369 }
13370
13371 list_append_number(rettv->vval.v_list,
13372 (syntax_flags & HL_CONCEAL) != 0);
13373 /* -1 to auto-determine strlen */
13374 list_append_string(rettv->vval.v_list, str, -1);
13375 list_append_number(rettv->vval.v_list, matchid);
13376 }
13377#endif
13378}
13379
13380/*
13381 * "synstack(lnum, col)" function
13382 */
13383 static void
13384f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13385{
13386#ifdef FEAT_SYN_HL
13387 linenr_T lnum;
13388 colnr_T col;
13389 int i;
13390 int id;
13391#endif
13392
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013393 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013394
13395#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013396 lnum = tv_get_lnum(argvars); /* -1 on type error */
13397 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013398
13399 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13400 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13401 && rettv_list_alloc(rettv) != FAIL)
13402 {
13403 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13404 for (i = 0; ; ++i)
13405 {
13406 id = syn_get_stack_item(i);
13407 if (id < 0)
13408 break;
13409 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13410 break;
13411 }
13412 }
13413#endif
13414}
13415
13416 static void
13417get_cmd_output_as_rettv(
13418 typval_T *argvars,
13419 typval_T *rettv,
13420 int retlist)
13421{
13422 char_u *res = NULL;
13423 char_u *p;
13424 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013425 int err = FALSE;
13426 FILE *fd;
13427 list_T *list = NULL;
13428 int flags = SHELL_SILENT;
13429
13430 rettv->v_type = VAR_STRING;
13431 rettv->vval.v_string = NULL;
13432 if (check_restricted() || check_secure())
13433 goto errret;
13434
13435 if (argvars[1].v_type != VAR_UNKNOWN)
13436 {
13437 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013438 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439 * command.
13440 */
13441 if ((infile = vim_tempname('i', TRUE)) == NULL)
13442 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013443 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013444 goto errret;
13445 }
13446
13447 fd = mch_fopen((char *)infile, WRITEBIN);
13448 if (fd == NULL)
13449 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013450 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013451 goto errret;
13452 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013453 if (argvars[1].v_type == VAR_NUMBER)
13454 {
13455 linenr_T lnum;
13456 buf_T *buf;
13457
13458 buf = buflist_findnr(argvars[1].vval.v_number);
13459 if (buf == NULL)
13460 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013461 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013462 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013463 goto errret;
13464 }
13465
13466 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13467 {
13468 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13469 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13470 {
13471 err = TRUE;
13472 break;
13473 }
13474 if (putc(NL, fd) == EOF)
13475 {
13476 err = TRUE;
13477 break;
13478 }
13479 }
13480 }
13481 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013482 {
13483 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13484 err = TRUE;
13485 }
13486 else
13487 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013488 size_t len;
13489 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013490
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013491 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013492 if (p == NULL)
13493 {
13494 fclose(fd);
13495 goto errret; /* type error; errmsg already given */
13496 }
13497 len = STRLEN(p);
13498 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13499 err = TRUE;
13500 }
13501 if (fclose(fd) != 0)
13502 err = TRUE;
13503 if (err)
13504 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013505 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013506 goto errret;
13507 }
13508 }
13509
13510 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13511 * echoes typeahead, that messes up the display. */
13512 if (!msg_silent)
13513 flags += SHELL_COOKED;
13514
13515 if (retlist)
13516 {
13517 int len;
13518 listitem_T *li;
13519 char_u *s = NULL;
13520 char_u *start;
13521 char_u *end;
13522 int i;
13523
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013524 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013525 if (res == NULL)
13526 goto errret;
13527
13528 list = list_alloc();
13529 if (list == NULL)
13530 goto errret;
13531
13532 for (i = 0; i < len; ++i)
13533 {
13534 start = res + i;
13535 while (i < len && res[i] != NL)
13536 ++i;
13537 end = res + i;
13538
13539 s = alloc((unsigned)(end - start + 1));
13540 if (s == NULL)
13541 goto errret;
13542
13543 for (p = s; start < end; ++p, ++start)
13544 *p = *start == NUL ? NL : *start;
13545 *p = NUL;
13546
13547 li = listitem_alloc();
13548 if (li == NULL)
13549 {
13550 vim_free(s);
13551 goto errret;
13552 }
13553 li->li_tv.v_type = VAR_STRING;
13554 li->li_tv.v_lock = 0;
13555 li->li_tv.vval.v_string = s;
13556 list_append(list, li);
13557 }
13558
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013559 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013560 list = NULL;
13561 }
13562 else
13563 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013564 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013565#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013566 /* translate <CR><NL> into <NL> */
13567 if (res != NULL)
13568 {
13569 char_u *s, *d;
13570
13571 d = res;
13572 for (s = res; *s; ++s)
13573 {
13574 if (s[0] == CAR && s[1] == NL)
13575 ++s;
13576 *d++ = *s;
13577 }
13578 *d = NUL;
13579 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013580#endif
13581 rettv->vval.v_string = res;
13582 res = NULL;
13583 }
13584
13585errret:
13586 if (infile != NULL)
13587 {
13588 mch_remove(infile);
13589 vim_free(infile);
13590 }
13591 if (res != NULL)
13592 vim_free(res);
13593 if (list != NULL)
13594 list_free(list);
13595}
13596
13597/*
13598 * "system()" function
13599 */
13600 static void
13601f_system(typval_T *argvars, typval_T *rettv)
13602{
13603 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13604}
13605
13606/*
13607 * "systemlist()" function
13608 */
13609 static void
13610f_systemlist(typval_T *argvars, typval_T *rettv)
13611{
13612 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13613}
13614
13615/*
13616 * "tabpagebuflist()" function
13617 */
13618 static void
13619f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13620{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013621 tabpage_T *tp;
13622 win_T *wp = NULL;
13623
13624 if (argvars[0].v_type == VAR_UNKNOWN)
13625 wp = firstwin;
13626 else
13627 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013628 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013629 if (tp != NULL)
13630 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13631 }
13632 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13633 {
13634 for (; wp != NULL; wp = wp->w_next)
13635 if (list_append_number(rettv->vval.v_list,
13636 wp->w_buffer->b_fnum) == FAIL)
13637 break;
13638 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013639}
13640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013641/*
13642 * "tabpagenr()" function
13643 */
13644 static void
13645f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13646{
13647 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013648 char_u *arg;
13649
13650 if (argvars[0].v_type != VAR_UNKNOWN)
13651 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013652 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013653 nr = 0;
13654 if (arg != NULL)
13655 {
13656 if (STRCMP(arg, "$") == 0)
13657 nr = tabpage_index(NULL) - 1;
13658 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013659 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013660 }
13661 }
13662 else
13663 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013664 rettv->vval.v_number = nr;
13665}
13666
13667
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013668/*
13669 * Common code for tabpagewinnr() and winnr().
13670 */
13671 static int
13672get_winnr(tabpage_T *tp, typval_T *argvar)
13673{
13674 win_T *twin;
13675 int nr = 1;
13676 win_T *wp;
13677 char_u *arg;
13678
13679 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13680 if (argvar->v_type != VAR_UNKNOWN)
13681 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013682 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013683 if (arg == NULL)
13684 nr = 0; /* type error; errmsg already given */
13685 else if (STRCMP(arg, "$") == 0)
13686 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13687 else if (STRCMP(arg, "#") == 0)
13688 {
13689 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13690 if (twin == NULL)
13691 nr = 0;
13692 }
13693 else
13694 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013695 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013696 nr = 0;
13697 }
13698 }
13699
13700 if (nr > 0)
13701 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13702 wp != twin; wp = wp->w_next)
13703 {
13704 if (wp == NULL)
13705 {
13706 /* didn't find it in this tabpage */
13707 nr = 0;
13708 break;
13709 }
13710 ++nr;
13711 }
13712 return nr;
13713}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013714
13715/*
13716 * "tabpagewinnr()" function
13717 */
13718 static void
13719f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13720{
13721 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013722 tabpage_T *tp;
13723
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013724 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013725 if (tp == NULL)
13726 nr = 0;
13727 else
13728 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013729 rettv->vval.v_number = nr;
13730}
13731
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013732/*
13733 * "tagfiles()" function
13734 */
13735 static void
13736f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13737{
13738 char_u *fname;
13739 tagname_T tn;
13740 int first;
13741
13742 if (rettv_list_alloc(rettv) == FAIL)
13743 return;
13744 fname = alloc(MAXPATHL);
13745 if (fname == NULL)
13746 return;
13747
13748 for (first = TRUE; ; first = FALSE)
13749 if (get_tagfname(&tn, first, fname) == FAIL
13750 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13751 break;
13752 tagname_free(&tn);
13753 vim_free(fname);
13754}
13755
13756/*
13757 * "taglist()" function
13758 */
13759 static void
13760f_taglist(typval_T *argvars, typval_T *rettv)
13761{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013762 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013763 char_u *tag_pattern;
13764
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013765 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013766
13767 rettv->vval.v_number = FALSE;
13768 if (*tag_pattern == NUL)
13769 return;
13770
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013771 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013772 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013773 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013774 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013775}
13776
13777/*
13778 * "tempname()" function
13779 */
13780 static void
13781f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13782{
13783 static int x = 'A';
13784
13785 rettv->v_type = VAR_STRING;
13786 rettv->vval.v_string = vim_tempname(x, FALSE);
13787
13788 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13789 * names. Skip 'I' and 'O', they are used for shell redirection. */
13790 do
13791 {
13792 if (x == 'Z')
13793 x = '0';
13794 else if (x == '9')
13795 x = 'A';
13796 else
13797 {
13798#ifdef EBCDIC
13799 if (x == 'I')
13800 x = 'J';
13801 else if (x == 'R')
13802 x = 'S';
13803 else
13804#endif
13805 ++x;
13806 }
13807 } while (x == 'I' || x == 'O');
13808}
13809
13810#ifdef FEAT_FLOAT
13811/*
13812 * "tan()" function
13813 */
13814 static void
13815f_tan(typval_T *argvars, typval_T *rettv)
13816{
13817 float_T f = 0.0;
13818
13819 rettv->v_type = VAR_FLOAT;
13820 if (get_float_arg(argvars, &f) == OK)
13821 rettv->vval.v_float = tan(f);
13822 else
13823 rettv->vval.v_float = 0.0;
13824}
13825
13826/*
13827 * "tanh()" function
13828 */
13829 static void
13830f_tanh(typval_T *argvars, typval_T *rettv)
13831{
13832 float_T f = 0.0;
13833
13834 rettv->v_type = VAR_FLOAT;
13835 if (get_float_arg(argvars, &f) == OK)
13836 rettv->vval.v_float = tanh(f);
13837 else
13838 rettv->vval.v_float = 0.0;
13839}
13840#endif
13841
13842/*
13843 * "test_alloc_fail(id, countdown, repeat)" function
13844 */
13845 static void
13846f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13847{
13848 if (argvars[0].v_type != VAR_NUMBER
13849 || argvars[0].vval.v_number <= 0
13850 || argvars[1].v_type != VAR_NUMBER
13851 || argvars[1].vval.v_number < 0
13852 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013853 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013854 else
13855 {
13856 alloc_fail_id = argvars[0].vval.v_number;
13857 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013858 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013859 alloc_fail_countdown = argvars[1].vval.v_number;
13860 alloc_fail_repeat = argvars[2].vval.v_number;
13861 did_outofmem_msg = FALSE;
13862 }
13863}
13864
13865/*
13866 * "test_autochdir()"
13867 */
13868 static void
13869f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13870{
13871#if defined(FEAT_AUTOCHDIR)
13872 test_autochdir = TRUE;
13873#endif
13874}
13875
13876/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013877 * "test_feedinput()"
13878 */
13879 static void
13880f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13881{
13882#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013883 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013884
13885 if (val != NULL)
13886 {
13887 trash_input_buf();
13888 add_to_input_buf_csi(val, (int)STRLEN(val));
13889 }
13890#endif
13891}
13892
13893/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013894 * "test_option_not_set({name})" function
13895 */
13896 static void
13897f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13898{
13899 char_u *name = (char_u *)"";
13900
13901 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013902 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013903 else
13904 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013905 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013906 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013907 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013908 }
13909}
13910
13911/*
13912 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013913 */
13914 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013915f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013916{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013917 char_u *name = (char_u *)"";
13918 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013919 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013920
13921 if (argvars[0].v_type != VAR_STRING
13922 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013923 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013924 else
13925 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013926 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013927 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013928
13929 if (STRCMP(name, (char_u *)"redraw") == 0)
13930 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013931 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13932 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013933 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13934 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013935 else if (STRCMP(name, (char_u *)"starting") == 0)
13936 {
13937 if (val)
13938 {
13939 if (save_starting < 0)
13940 save_starting = starting;
13941 starting = 0;
13942 }
13943 else
13944 {
13945 starting = save_starting;
13946 save_starting = -1;
13947 }
13948 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013949 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13950 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013951 else if (STRCMP(name, (char_u *)"ALL") == 0)
13952 {
13953 disable_char_avail_for_testing = FALSE;
13954 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013955 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013956 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013957 if (save_starting >= 0)
13958 {
13959 starting = save_starting;
13960 save_starting = -1;
13961 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013962 }
13963 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013964 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013965 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013966}
13967
13968/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010013969 * "test_refcount({expr})" function
13970 */
13971 static void
13972f_test_refcount(typval_T *argvars, typval_T *rettv)
13973{
13974 int retval = -1;
13975
13976 switch (argvars[0].v_type)
13977 {
13978 case VAR_UNKNOWN:
13979 case VAR_NUMBER:
13980 case VAR_FLOAT:
13981 case VAR_SPECIAL:
13982 case VAR_STRING:
13983 break;
13984 case VAR_JOB:
13985#ifdef FEAT_JOB_CHANNEL
13986 if (argvars[0].vval.v_job != NULL)
13987 retval = argvars[0].vval.v_job->jv_refcount - 1;
13988#endif
13989 break;
13990 case VAR_CHANNEL:
13991#ifdef FEAT_JOB_CHANNEL
13992 if (argvars[0].vval.v_channel != NULL)
13993 retval = argvars[0].vval.v_channel->ch_refcount - 1;
13994#endif
13995 break;
13996 case VAR_FUNC:
13997 if (argvars[0].vval.v_string != NULL)
13998 {
13999 ufunc_T *fp;
14000
14001 fp = find_func(argvars[0].vval.v_string);
14002 if (fp != NULL)
14003 retval = fp->uf_refcount;
14004 }
14005 break;
14006 case VAR_PARTIAL:
14007 if (argvars[0].vval.v_partial != NULL)
14008 retval = argvars[0].vval.v_partial->pt_refcount - 1;
14009 break;
14010 case VAR_BLOB:
14011 if (argvars[0].vval.v_blob != NULL)
14012 retval = argvars[0].vval.v_blob->bv_refcount - 1;
14013 break;
14014 case VAR_LIST:
14015 if (argvars[0].vval.v_list != NULL)
14016 retval = argvars[0].vval.v_list->lv_refcount - 1;
14017 break;
14018 case VAR_DICT:
14019 if (argvars[0].vval.v_dict != NULL)
14020 retval = argvars[0].vval.v_dict->dv_refcount - 1;
14021 break;
14022 }
14023
14024 rettv->v_type = VAR_NUMBER;
14025 rettv->vval.v_number = retval;
14026
14027}
14028
14029/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014030 * "test_garbagecollect_now()" function
14031 */
14032 static void
14033f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14034{
14035 /* This is dangerous, any Lists and Dicts used internally may be freed
14036 * while still in use. */
14037 garbage_collect(TRUE);
14038}
14039
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014040/*
14041 * "test_ignore_error()" function
14042 */
14043 static void
14044f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
14045{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014046 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014047}
14048
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010014049 static void
14050f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
14051{
14052 rettv->v_type = VAR_BLOB;
14053 rettv->vval.v_blob = NULL;
14054}
14055
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014056#ifdef FEAT_JOB_CHANNEL
14057 static void
14058f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
14059{
14060 rettv->v_type = VAR_CHANNEL;
14061 rettv->vval.v_channel = NULL;
14062}
14063#endif
14064
14065 static void
14066f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
14067{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014068 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014069}
14070
14071#ifdef FEAT_JOB_CHANNEL
14072 static void
14073f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14074{
14075 rettv->v_type = VAR_JOB;
14076 rettv->vval.v_job = NULL;
14077}
14078#endif
14079
14080 static void
14081f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14082{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014083 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014084}
14085
14086 static void
14087f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14088{
14089 rettv->v_type = VAR_PARTIAL;
14090 rettv->vval.v_partial = NULL;
14091}
14092
14093 static void
14094f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14095{
14096 rettv->v_type = VAR_STRING;
14097 rettv->vval.v_string = NULL;
14098}
14099
Bram Moolenaarab186732018-09-14 21:27:06 +020014100#ifdef FEAT_GUI
14101 static void
14102f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14103{
14104 char_u *which;
14105 long value;
14106 int dragging;
14107 scrollbar_T *sb = NULL;
14108
14109 if (argvars[0].v_type != VAR_STRING
14110 || (argvars[1].v_type) != VAR_NUMBER
14111 || (argvars[2].v_type) != VAR_NUMBER)
14112 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014113 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014114 return;
14115 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014116 which = tv_get_string(&argvars[0]);
14117 value = tv_get_number(&argvars[1]);
14118 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014119
14120 if (STRCMP(which, "left") == 0)
14121 sb = &curwin->w_scrollbars[SBAR_LEFT];
14122 else if (STRCMP(which, "right") == 0)
14123 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14124 else if (STRCMP(which, "hor") == 0)
14125 sb = &gui.bottom_sbar;
14126 if (sb == NULL)
14127 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014128 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014129 return;
14130 }
14131 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014132# ifndef USE_ON_FLY_SCROLL
14133 // need to loop through normal_cmd() to handle the scroll events
14134 exec_normal(FALSE, TRUE, FALSE);
14135# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014136}
14137#endif
14138
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014139 static void
14140f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14141{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014142 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014143}
14144
14145#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14146/*
14147 * Get a callback from "arg". It can be a Funcref or a function name.
14148 * When "arg" is zero return an empty string.
14149 * Return NULL for an invalid argument.
14150 */
14151 char_u *
14152get_callback(typval_T *arg, partial_T **pp)
14153{
14154 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14155 {
14156 *pp = arg->vval.v_partial;
14157 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014158 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014159 }
14160 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014161 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014162 {
14163 func_ref(arg->vval.v_string);
14164 return arg->vval.v_string;
14165 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014166 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14167 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014168 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014169 return NULL;
14170}
14171
14172/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014173 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014174 */
14175 void
14176free_callback(char_u *callback, partial_T *partial)
14177{
14178 if (partial != NULL)
14179 partial_unref(partial);
14180 else if (callback != NULL)
14181 {
14182 func_unref(callback);
14183 vim_free(callback);
14184 }
14185}
14186#endif
14187
14188#ifdef FEAT_TIMERS
14189/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014190 * "timer_info([timer])" function
14191 */
14192 static void
14193f_timer_info(typval_T *argvars, typval_T *rettv)
14194{
14195 timer_T *timer = NULL;
14196
14197 if (rettv_list_alloc(rettv) != OK)
14198 return;
14199 if (argvars[0].v_type != VAR_UNKNOWN)
14200 {
14201 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014202 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014203 else
14204 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014205 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014206 if (timer != NULL)
14207 add_timer_info(rettv, timer);
14208 }
14209 }
14210 else
14211 add_timer_info_all(rettv);
14212}
14213
14214/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014215 * "timer_pause(timer, paused)" function
14216 */
14217 static void
14218f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14219{
14220 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014221 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014222
14223 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014224 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014225 else
14226 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014227 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014228 if (timer != NULL)
14229 timer->tr_paused = paused;
14230 }
14231}
14232
14233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014234 * "timer_start(time, callback [, options])" function
14235 */
14236 static void
14237f_timer_start(typval_T *argvars, typval_T *rettv)
14238{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014239 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014240 timer_T *timer;
14241 int repeat = 0;
14242 char_u *callback;
14243 dict_T *dict;
14244 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014245
Bram Moolenaar75537a92016-09-05 22:45:28 +020014246 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014247 if (check_secure())
14248 return;
14249 if (argvars[2].v_type != VAR_UNKNOWN)
14250 {
14251 if (argvars[2].v_type != VAR_DICT
14252 || (dict = argvars[2].vval.v_dict) == NULL)
14253 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014254 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014255 return;
14256 }
14257 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014258 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014259 }
14260
Bram Moolenaar75537a92016-09-05 22:45:28 +020014261 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014262 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014263 return;
14264
14265 timer = create_timer(msec, repeat);
14266 if (timer == NULL)
14267 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014268 else
14269 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014270 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014271 timer->tr_callback = vim_strsave(callback);
14272 else
14273 /* pointer into the partial */
14274 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014275 timer->tr_partial = partial;
14276 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014277 }
14278}
14279
14280/*
14281 * "timer_stop(timer)" function
14282 */
14283 static void
14284f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14285{
14286 timer_T *timer;
14287
14288 if (argvars[0].v_type != VAR_NUMBER)
14289 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014290 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014291 return;
14292 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014293 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014294 if (timer != NULL)
14295 stop_timer(timer);
14296}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014297
14298/*
14299 * "timer_stopall()" function
14300 */
14301 static void
14302f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14303{
14304 stop_all_timers();
14305}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014306#endif
14307
14308/*
14309 * "tolower(string)" function
14310 */
14311 static void
14312f_tolower(typval_T *argvars, typval_T *rettv)
14313{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014314 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014315 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014316}
14317
14318/*
14319 * "toupper(string)" function
14320 */
14321 static void
14322f_toupper(typval_T *argvars, typval_T *rettv)
14323{
14324 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014325 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014326}
14327
14328/*
14329 * "tr(string, fromstr, tostr)" function
14330 */
14331 static void
14332f_tr(typval_T *argvars, typval_T *rettv)
14333{
14334 char_u *in_str;
14335 char_u *fromstr;
14336 char_u *tostr;
14337 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014338 int inlen;
14339 int fromlen;
14340 int tolen;
14341 int idx;
14342 char_u *cpstr;
14343 int cplen;
14344 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014345 char_u buf[NUMBUFLEN];
14346 char_u buf2[NUMBUFLEN];
14347 garray_T ga;
14348
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014349 in_str = tv_get_string(&argvars[0]);
14350 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14351 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014352
14353 /* Default return value: empty string. */
14354 rettv->v_type = VAR_STRING;
14355 rettv->vval.v_string = NULL;
14356 if (fromstr == NULL || tostr == NULL)
14357 return; /* type error; errmsg already given */
14358 ga_init2(&ga, (int)sizeof(char), 80);
14359
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014360 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014361 /* not multi-byte: fromstr and tostr must be the same length */
14362 if (STRLEN(fromstr) != STRLEN(tostr))
14363 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014364error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014365 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014366 ga_clear(&ga);
14367 return;
14368 }
14369
14370 /* fromstr and tostr have to contain the same number of chars */
14371 while (*in_str != NUL)
14372 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014373 if (has_mbyte)
14374 {
14375 inlen = (*mb_ptr2len)(in_str);
14376 cpstr = in_str;
14377 cplen = inlen;
14378 idx = 0;
14379 for (p = fromstr; *p != NUL; p += fromlen)
14380 {
14381 fromlen = (*mb_ptr2len)(p);
14382 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14383 {
14384 for (p = tostr; *p != NUL; p += tolen)
14385 {
14386 tolen = (*mb_ptr2len)(p);
14387 if (idx-- == 0)
14388 {
14389 cplen = tolen;
14390 cpstr = p;
14391 break;
14392 }
14393 }
14394 if (*p == NUL) /* tostr is shorter than fromstr */
14395 goto error;
14396 break;
14397 }
14398 ++idx;
14399 }
14400
14401 if (first && cpstr == in_str)
14402 {
14403 /* Check that fromstr and tostr have the same number of
14404 * (multi-byte) characters. Done only once when a character
14405 * of in_str doesn't appear in fromstr. */
14406 first = FALSE;
14407 for (p = tostr; *p != NUL; p += tolen)
14408 {
14409 tolen = (*mb_ptr2len)(p);
14410 --idx;
14411 }
14412 if (idx != 0)
14413 goto error;
14414 }
14415
14416 (void)ga_grow(&ga, cplen);
14417 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14418 ga.ga_len += cplen;
14419
14420 in_str += inlen;
14421 }
14422 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014423 {
14424 /* When not using multi-byte chars we can do it faster. */
14425 p = vim_strchr(fromstr, *in_str);
14426 if (p != NULL)
14427 ga_append(&ga, tostr[p - fromstr]);
14428 else
14429 ga_append(&ga, *in_str);
14430 ++in_str;
14431 }
14432 }
14433
14434 /* add a terminating NUL */
14435 (void)ga_grow(&ga, 1);
14436 ga_append(&ga, NUL);
14437
14438 rettv->vval.v_string = ga.ga_data;
14439}
14440
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014441/*
14442 * "trim({expr})" function
14443 */
14444 static void
14445f_trim(typval_T *argvars, typval_T *rettv)
14446{
14447 char_u buf1[NUMBUFLEN];
14448 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014449 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014450 char_u *mask = NULL;
14451 char_u *tail;
14452 char_u *prev;
14453 char_u *p;
14454 int c1;
14455
14456 rettv->v_type = VAR_STRING;
14457 if (head == NULL)
14458 {
14459 rettv->vval.v_string = NULL;
14460 return;
14461 }
14462
14463 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014464 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014465
14466 while (*head != NUL)
14467 {
14468 c1 = PTR2CHAR(head);
14469 if (mask == NULL)
14470 {
14471 if (c1 > ' ' && c1 != 0xa0)
14472 break;
14473 }
14474 else
14475 {
14476 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14477 if (c1 == PTR2CHAR(p))
14478 break;
14479 if (*p == NUL)
14480 break;
14481 }
14482 MB_PTR_ADV(head);
14483 }
14484
14485 for (tail = head + STRLEN(head); tail > head; tail = prev)
14486 {
14487 prev = tail;
14488 MB_PTR_BACK(head, prev);
14489 c1 = PTR2CHAR(prev);
14490 if (mask == NULL)
14491 {
14492 if (c1 > ' ' && c1 != 0xa0)
14493 break;
14494 }
14495 else
14496 {
14497 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14498 if (c1 == PTR2CHAR(p))
14499 break;
14500 if (*p == NUL)
14501 break;
14502 }
14503 }
14504 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14505}
14506
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014507#ifdef FEAT_FLOAT
14508/*
14509 * "trunc({float})" function
14510 */
14511 static void
14512f_trunc(typval_T *argvars, typval_T *rettv)
14513{
14514 float_T f = 0.0;
14515
14516 rettv->v_type = VAR_FLOAT;
14517 if (get_float_arg(argvars, &f) == OK)
14518 /* trunc() is not in C90, use floor() or ceil() instead. */
14519 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14520 else
14521 rettv->vval.v_float = 0.0;
14522}
14523#endif
14524
14525/*
14526 * "type(expr)" function
14527 */
14528 static void
14529f_type(typval_T *argvars, typval_T *rettv)
14530{
14531 int n = -1;
14532
14533 switch (argvars[0].v_type)
14534 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014535 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14536 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014537 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014538 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14539 case VAR_LIST: n = VAR_TYPE_LIST; break;
14540 case VAR_DICT: n = VAR_TYPE_DICT; break;
14541 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014542 case VAR_SPECIAL:
14543 if (argvars[0].vval.v_number == VVAL_FALSE
14544 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014545 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014546 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014547 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014548 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014549 case VAR_JOB: n = VAR_TYPE_JOB; break;
14550 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014551 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014552 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014553 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014554 n = -1;
14555 break;
14556 }
14557 rettv->vval.v_number = n;
14558}
14559
14560/*
14561 * "undofile(name)" function
14562 */
14563 static void
14564f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14565{
14566 rettv->v_type = VAR_STRING;
14567#ifdef FEAT_PERSISTENT_UNDO
14568 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014569 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014570
14571 if (*fname == NUL)
14572 {
14573 /* If there is no file name there will be no undo file. */
14574 rettv->vval.v_string = NULL;
14575 }
14576 else
14577 {
14578 char_u *ffname = FullName_save(fname, FALSE);
14579
14580 if (ffname != NULL)
14581 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14582 vim_free(ffname);
14583 }
14584 }
14585#else
14586 rettv->vval.v_string = NULL;
14587#endif
14588}
14589
14590/*
14591 * "undotree()" function
14592 */
14593 static void
14594f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14595{
14596 if (rettv_dict_alloc(rettv) == OK)
14597 {
14598 dict_T *dict = rettv->vval.v_dict;
14599 list_T *list;
14600
Bram Moolenaare0be1672018-07-08 16:50:37 +020014601 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14602 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14603 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14604 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14605 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14606 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014607
14608 list = list_alloc();
14609 if (list != NULL)
14610 {
14611 u_eval_tree(curbuf->b_u_oldhead, list);
14612 dict_add_list(dict, "entries", list);
14613 }
14614 }
14615}
14616
14617/*
14618 * "values(dict)" function
14619 */
14620 static void
14621f_values(typval_T *argvars, typval_T *rettv)
14622{
14623 dict_list(argvars, rettv, 1);
14624}
14625
14626/*
14627 * "virtcol(string)" function
14628 */
14629 static void
14630f_virtcol(typval_T *argvars, typval_T *rettv)
14631{
14632 colnr_T vcol = 0;
14633 pos_T *fp;
14634 int fnum = curbuf->b_fnum;
14635
14636 fp = var2fpos(&argvars[0], FALSE, &fnum);
14637 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14638 && fnum == curbuf->b_fnum)
14639 {
14640 getvvcol(curwin, fp, NULL, NULL, &vcol);
14641 ++vcol;
14642 }
14643
14644 rettv->vval.v_number = vcol;
14645}
14646
14647/*
14648 * "visualmode()" function
14649 */
14650 static void
14651f_visualmode(typval_T *argvars, typval_T *rettv)
14652{
14653 char_u str[2];
14654
14655 rettv->v_type = VAR_STRING;
14656 str[0] = curbuf->b_visual_mode_eval;
14657 str[1] = NUL;
14658 rettv->vval.v_string = vim_strsave(str);
14659
14660 /* A non-zero number or non-empty string argument: reset mode. */
14661 if (non_zero_arg(&argvars[0]))
14662 curbuf->b_visual_mode_eval = NUL;
14663}
14664
14665/*
14666 * "wildmenumode()" function
14667 */
14668 static void
14669f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14670{
14671#ifdef FEAT_WILDMENU
14672 if (wild_menu_showing)
14673 rettv->vval.v_number = 1;
14674#endif
14675}
14676
14677/*
14678 * "winbufnr(nr)" function
14679 */
14680 static void
14681f_winbufnr(typval_T *argvars, typval_T *rettv)
14682{
14683 win_T *wp;
14684
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014685 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014686 if (wp == NULL)
14687 rettv->vval.v_number = -1;
14688 else
14689 rettv->vval.v_number = wp->w_buffer->b_fnum;
14690}
14691
14692/*
14693 * "wincol()" function
14694 */
14695 static void
14696f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14697{
14698 validate_cursor();
14699 rettv->vval.v_number = curwin->w_wcol + 1;
14700}
14701
14702/*
14703 * "winheight(nr)" function
14704 */
14705 static void
14706f_winheight(typval_T *argvars, typval_T *rettv)
14707{
14708 win_T *wp;
14709
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014710 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014711 if (wp == NULL)
14712 rettv->vval.v_number = -1;
14713 else
14714 rettv->vval.v_number = wp->w_height;
14715}
14716
14717/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014718 * "winlayout()" function
14719 */
14720 static void
14721f_winlayout(typval_T *argvars, typval_T *rettv)
14722{
14723 tabpage_T *tp;
14724
14725 if (rettv_list_alloc(rettv) != OK)
14726 return;
14727
14728 if (argvars[0].v_type == VAR_UNKNOWN)
14729 tp = curtab;
14730 else
14731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014732 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014733 if (tp == NULL)
14734 return;
14735 }
14736
14737 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14738}
14739
14740/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014741 * "winline()" function
14742 */
14743 static void
14744f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14745{
14746 validate_cursor();
14747 rettv->vval.v_number = curwin->w_wrow + 1;
14748}
14749
14750/*
14751 * "winnr()" function
14752 */
14753 static void
14754f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14755{
14756 int nr = 1;
14757
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014758 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014759 rettv->vval.v_number = nr;
14760}
14761
14762/*
14763 * "winrestcmd()" function
14764 */
14765 static void
14766f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14767{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014768 win_T *wp;
14769 int winnr = 1;
14770 garray_T ga;
14771 char_u buf[50];
14772
14773 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014774 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014775 {
14776 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14777 ga_concat(&ga, buf);
14778 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14779 ga_concat(&ga, buf);
14780 ++winnr;
14781 }
14782 ga_append(&ga, NUL);
14783
14784 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014785 rettv->v_type = VAR_STRING;
14786}
14787
14788/*
14789 * "winrestview()" function
14790 */
14791 static void
14792f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14793{
14794 dict_T *dict;
14795
14796 if (argvars[0].v_type != VAR_DICT
14797 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014798 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014799 else
14800 {
14801 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014802 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014803 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014804 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014805 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014806 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014807 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14808 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014809 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014810 curwin->w_set_curswant = FALSE;
14811 }
14812
14813 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014814 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014815#ifdef FEAT_DIFF
14816 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014817 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014818#endif
14819 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014820 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014821 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014822 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014823
14824 check_cursor();
14825 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014826 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014827 changed_window_setting();
14828
14829 if (curwin->w_topline <= 0)
14830 curwin->w_topline = 1;
14831 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14832 curwin->w_topline = curbuf->b_ml.ml_line_count;
14833#ifdef FEAT_DIFF
14834 check_topfill(curwin, TRUE);
14835#endif
14836 }
14837}
14838
14839/*
14840 * "winsaveview()" function
14841 */
14842 static void
14843f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14844{
14845 dict_T *dict;
14846
14847 if (rettv_dict_alloc(rettv) == FAIL)
14848 return;
14849 dict = rettv->vval.v_dict;
14850
Bram Moolenaare0be1672018-07-08 16:50:37 +020014851 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14852 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014853 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014854 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014855 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014856
Bram Moolenaare0be1672018-07-08 16:50:37 +020014857 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014858#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014859 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014860#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014861 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14862 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014863}
14864
14865/*
14866 * "winwidth(nr)" function
14867 */
14868 static void
14869f_winwidth(typval_T *argvars, typval_T *rettv)
14870{
14871 win_T *wp;
14872
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014873 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014874 if (wp == NULL)
14875 rettv->vval.v_number = -1;
14876 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014877 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014878}
14879
14880/*
14881 * "wordcount()" function
14882 */
14883 static void
14884f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14885{
14886 if (rettv_dict_alloc(rettv) == FAIL)
14887 return;
14888 cursor_pos_info(rettv->vval.v_dict);
14889}
14890
14891/*
14892 * "writefile()" function
14893 */
14894 static void
14895f_writefile(typval_T *argvars, typval_T *rettv)
14896{
14897 int binary = FALSE;
14898 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014899#ifdef HAVE_FSYNC
14900 int do_fsync = p_fs;
14901#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014902 char_u *fname;
14903 FILE *fd;
14904 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014905 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014906 list_T *list = NULL;
14907 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014908
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014909 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014910 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014911 return;
14912
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014913 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014914 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014915 list = argvars[0].vval.v_list;
14916 if (list == NULL)
14917 return;
14918 for (li = list->lv_first; li != NULL; li = li->li_next)
14919 if (tv_get_string_chk(&li->li_tv) == NULL)
14920 return;
14921 }
14922 else if (argvars[0].v_type == VAR_BLOB)
14923 {
14924 blob = argvars[0].vval.v_blob;
14925 if (blob == NULL)
14926 return;
14927 }
14928 else
14929 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014930 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014931 return;
14932 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014933
14934 if (argvars[2].v_type != VAR_UNKNOWN)
14935 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014936 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014937
14938 if (arg2 == NULL)
14939 return;
14940 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014941 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014942 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014943 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014944#ifdef HAVE_FSYNC
14945 if (vim_strchr(arg2, 's') != NULL)
14946 do_fsync = TRUE;
14947 else if (vim_strchr(arg2, 'S') != NULL)
14948 do_fsync = FALSE;
14949#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014950 }
14951
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014952 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014953 if (fname == NULL)
14954 return;
14955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014956 /* Always open the file in binary mode, library functions have a mind of
14957 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014958 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14959 append ? APPENDBIN : WRITEBIN)) == NULL)
14960 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014961 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014962 ret = -1;
14963 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014964 else if (blob)
14965 {
14966 if (write_blob(fd, blob) == FAIL)
14967 ret = -1;
14968#ifdef HAVE_FSYNC
14969 else if (do_fsync)
14970 // Ignore the error, the user wouldn't know what to do about it.
14971 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010014972 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014973#endif
14974 fclose(fd);
14975 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014976 else
14977 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014978 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014979 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014980#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014981 else if (do_fsync)
14982 /* Ignore the error, the user wouldn't know what to do about it.
14983 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010014984 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014985#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014986 fclose(fd);
14987 }
14988
14989 rettv->vval.v_number = ret;
14990}
14991
14992/*
14993 * "xor(expr, expr)" function
14994 */
14995 static void
14996f_xor(typval_T *argvars, typval_T *rettv)
14997{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014998 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14999 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015000}
15001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015002#endif /* FEAT_EVAL */