blob: 02ca1ae8289d8f17497ab853a7f2e1b7f8a70a97 [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 Moolenaaraff74912019-03-30 18:11:49 +010034static char *e_invalwindow = N_("E957: Invalid window number");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020035
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020043static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_argc(typval_T *argvars, typval_T *rettv);
45static void f_argidx(typval_T *argvars, typval_T *rettv);
46static void f_arglistid(typval_T *argvars, typval_T *rettv);
47static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010048static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010050static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_assert_exception(typval_T *argvars, typval_T *rettv);
52static void f_assert_fails(typval_T *argvars, typval_T *rettv);
53static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020054static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_assert_match(typval_T *argvars, typval_T *rettv);
56static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
57static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010058static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_assert_true(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_asin(typval_T *argvars, typval_T *rettv);
62static void f_atan(typval_T *argvars, typval_T *rettv);
63static void f_atan2(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020066static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010067static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010068# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010069static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010070# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010071#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_browse(typval_T *argvars, typval_T *rettv);
73static void f_browsedir(typval_T *argvars, typval_T *rettv);
74static void f_bufexists(typval_T *argvars, typval_T *rettv);
75static void f_buflisted(typval_T *argvars, typval_T *rettv);
76static void f_bufloaded(typval_T *argvars, typval_T *rettv);
77static void f_bufname(typval_T *argvars, typval_T *rettv);
78static void f_bufnr(typval_T *argvars, typval_T *rettv);
79static void f_bufwinid(typval_T *argvars, typval_T *rettv);
80static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
81static void f_byte2line(typval_T *argvars, typval_T *rettv);
82static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
83static void f_byteidx(typval_T *argvars, typval_T *rettv);
84static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
85static void f_call(typval_T *argvars, typval_T *rettv);
86#ifdef FEAT_FLOAT
87static void f_ceil(typval_T *argvars, typval_T *rettv);
88#endif
89#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010090static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020092static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
94static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
95static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
96static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
97static void f_ch_info(typval_T *argvars, typval_T *rettv);
98static void f_ch_log(typval_T *argvars, typval_T *rettv);
99static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
100static void f_ch_open(typval_T *argvars, typval_T *rettv);
101static void f_ch_read(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100102static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
104static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
105static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
106static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
107static void f_ch_status(typval_T *argvars, typval_T *rettv);
108#endif
109static void f_changenr(typval_T *argvars, typval_T *rettv);
110static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200111static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200112static void f_cindent(typval_T *argvars, typval_T *rettv);
113static void f_clearmatches(typval_T *argvars, typval_T *rettv);
114static void f_col(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_INS_EXPAND)
116static void f_complete(typval_T *argvars, typval_T *rettv);
117static void f_complete_add(typval_T *argvars, typval_T *rettv);
118static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +0100119static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200120#endif
121static void f_confirm(typval_T *argvars, typval_T *rettv);
122static void f_copy(typval_T *argvars, typval_T *rettv);
123#ifdef FEAT_FLOAT
124static void f_cos(typval_T *argvars, typval_T *rettv);
125static void f_cosh(typval_T *argvars, typval_T *rettv);
126#endif
127static void f_count(typval_T *argvars, typval_T *rettv);
128static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
129static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100130#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200131static void f_debugbreak(typval_T *argvars, typval_T *rettv);
132#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200133static void f_deepcopy(typval_T *argvars, typval_T *rettv);
134static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200135static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200136static void f_did_filetype(typval_T *argvars, typval_T *rettv);
137static void f_diff_filler(typval_T *argvars, typval_T *rettv);
138static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
139static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200140static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_escape(typval_T *argvars, typval_T *rettv);
142static void f_eval(typval_T *argvars, typval_T *rettv);
143static void f_eventhandler(typval_T *argvars, typval_T *rettv);
144static void f_executable(typval_T *argvars, typval_T *rettv);
145static void f_execute(typval_T *argvars, typval_T *rettv);
146static void f_exepath(typval_T *argvars, typval_T *rettv);
147static void f_exists(typval_T *argvars, typval_T *rettv);
148#ifdef FEAT_FLOAT
149static void f_exp(typval_T *argvars, typval_T *rettv);
150#endif
151static void f_expand(typval_T *argvars, typval_T *rettv);
152static void f_extend(typval_T *argvars, typval_T *rettv);
153static void f_feedkeys(typval_T *argvars, typval_T *rettv);
154static void f_filereadable(typval_T *argvars, typval_T *rettv);
155static void f_filewritable(typval_T *argvars, typval_T *rettv);
156static void f_filter(typval_T *argvars, typval_T *rettv);
157static void f_finddir(typval_T *argvars, typval_T *rettv);
158static void f_findfile(typval_T *argvars, typval_T *rettv);
159#ifdef FEAT_FLOAT
160static void f_float2nr(typval_T *argvars, typval_T *rettv);
161static void f_floor(typval_T *argvars, typval_T *rettv);
162static void f_fmod(typval_T *argvars, typval_T *rettv);
163#endif
164static void f_fnameescape(typval_T *argvars, typval_T *rettv);
165static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
166static void f_foldclosed(typval_T *argvars, typval_T *rettv);
167static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
168static void f_foldlevel(typval_T *argvars, typval_T *rettv);
169static void f_foldtext(typval_T *argvars, typval_T *rettv);
170static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
171static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200172static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_function(typval_T *argvars, typval_T *rettv);
174static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
175static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200176static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_getbufline(typval_T *argvars, typval_T *rettv);
178static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100179static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200180static void f_getchar(typval_T *argvars, typval_T *rettv);
181static void f_getcharmod(typval_T *argvars, typval_T *rettv);
182static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
183static void f_getcmdline(typval_T *argvars, typval_T *rettv);
184#if defined(FEAT_CMDL_COMPL)
185static void f_getcompletion(typval_T *argvars, typval_T *rettv);
186#endif
187static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
188static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
189static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
190static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200191static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_getfontname(typval_T *argvars, typval_T *rettv);
193static void f_getfperm(typval_T *argvars, typval_T *rettv);
194static void f_getfsize(typval_T *argvars, typval_T *rettv);
195static void f_getftime(typval_T *argvars, typval_T *rettv);
196static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100197static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200199static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_getmatches(typval_T *argvars, typval_T *rettv);
201static void f_getpid(typval_T *argvars, typval_T *rettv);
202static void f_getcurpos(typval_T *argvars, typval_T *rettv);
203static void f_getpos(typval_T *argvars, typval_T *rettv);
204static void f_getqflist(typval_T *argvars, typval_T *rettv);
205static void f_getreg(typval_T *argvars, typval_T *rettv);
206static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200207static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200208static void f_gettabvar(typval_T *argvars, typval_T *rettv);
209static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100210static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200211static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100212static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_getwinposx(typval_T *argvars, typval_T *rettv);
214static void f_getwinposy(typval_T *argvars, typval_T *rettv);
215static void f_getwinvar(typval_T *argvars, typval_T *rettv);
216static void f_glob(typval_T *argvars, typval_T *rettv);
217static void f_globpath(typval_T *argvars, typval_T *rettv);
218static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
219static void f_has(typval_T *argvars, typval_T *rettv);
220static void f_has_key(typval_T *argvars, typval_T *rettv);
221static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
222static void f_hasmapto(typval_T *argvars, typval_T *rettv);
223static void f_histadd(typval_T *argvars, typval_T *rettv);
224static void f_histdel(typval_T *argvars, typval_T *rettv);
225static void f_histget(typval_T *argvars, typval_T *rettv);
226static void f_histnr(typval_T *argvars, typval_T *rettv);
227static void f_hlID(typval_T *argvars, typval_T *rettv);
228static void f_hlexists(typval_T *argvars, typval_T *rettv);
229static void f_hostname(typval_T *argvars, typval_T *rettv);
230static void f_iconv(typval_T *argvars, typval_T *rettv);
231static void f_indent(typval_T *argvars, typval_T *rettv);
232static void f_index(typval_T *argvars, typval_T *rettv);
233static void f_input(typval_T *argvars, typval_T *rettv);
234static void f_inputdialog(typval_T *argvars, typval_T *rettv);
235static void f_inputlist(typval_T *argvars, typval_T *rettv);
236static void f_inputrestore(typval_T *argvars, typval_T *rettv);
237static void f_inputsave(typval_T *argvars, typval_T *rettv);
238static void f_inputsecret(typval_T *argvars, typval_T *rettv);
239static void f_insert(typval_T *argvars, typval_T *rettv);
240static void f_invert(typval_T *argvars, typval_T *rettv);
241static void f_isdirectory(typval_T *argvars, typval_T *rettv);
242static void f_islocked(typval_T *argvars, typval_T *rettv);
243#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200244static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_isnan(typval_T *argvars, typval_T *rettv);
246#endif
247static void f_items(typval_T *argvars, typval_T *rettv);
248#ifdef FEAT_JOB_CHANNEL
249static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
250static void f_job_info(typval_T *argvars, typval_T *rettv);
251static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
252static void f_job_start(typval_T *argvars, typval_T *rettv);
253static void f_job_stop(typval_T *argvars, typval_T *rettv);
254static void f_job_status(typval_T *argvars, typval_T *rettv);
255#endif
256static void f_join(typval_T *argvars, typval_T *rettv);
257static void f_js_decode(typval_T *argvars, typval_T *rettv);
258static void f_js_encode(typval_T *argvars, typval_T *rettv);
259static void f_json_decode(typval_T *argvars, typval_T *rettv);
260static void f_json_encode(typval_T *argvars, typval_T *rettv);
261static void f_keys(typval_T *argvars, typval_T *rettv);
262static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
263static void f_len(typval_T *argvars, typval_T *rettv);
264static void f_libcall(typval_T *argvars, typval_T *rettv);
265static void f_libcallnr(typval_T *argvars, typval_T *rettv);
266static void f_line(typval_T *argvars, typval_T *rettv);
267static void f_line2byte(typval_T *argvars, typval_T *rettv);
268static void f_lispindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar9d401282019-04-06 13:18:12 +0200269static void f_list2str(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200270static void f_localtime(typval_T *argvars, typval_T *rettv);
271#ifdef FEAT_FLOAT
272static void f_log(typval_T *argvars, typval_T *rettv);
273static void f_log10(typval_T *argvars, typval_T *rettv);
274#endif
275#ifdef FEAT_LUA
276static void f_luaeval(typval_T *argvars, typval_T *rettv);
277#endif
278static void f_map(typval_T *argvars, typval_T *rettv);
279static void f_maparg(typval_T *argvars, typval_T *rettv);
280static void f_mapcheck(typval_T *argvars, typval_T *rettv);
281static void f_match(typval_T *argvars, typval_T *rettv);
282static void f_matchadd(typval_T *argvars, typval_T *rettv);
283static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
284static void f_matcharg(typval_T *argvars, typval_T *rettv);
285static void f_matchdelete(typval_T *argvars, typval_T *rettv);
286static void f_matchend(typval_T *argvars, typval_T *rettv);
287static void f_matchlist(typval_T *argvars, typval_T *rettv);
288static void f_matchstr(typval_T *argvars, typval_T *rettv);
289static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
290static void f_max(typval_T *argvars, typval_T *rettv);
291static void f_min(typval_T *argvars, typval_T *rettv);
292#ifdef vim_mkdir
293static void f_mkdir(typval_T *argvars, typval_T *rettv);
294#endif
295static void f_mode(typval_T *argvars, typval_T *rettv);
296#ifdef FEAT_MZSCHEME
297static void f_mzeval(typval_T *argvars, typval_T *rettv);
298#endif
299static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
300static void f_nr2char(typval_T *argvars, typval_T *rettv);
301static void f_or(typval_T *argvars, typval_T *rettv);
302static void f_pathshorten(typval_T *argvars, typval_T *rettv);
303#ifdef FEAT_PERL
304static void f_perleval(typval_T *argvars, typval_T *rettv);
305#endif
306#ifdef FEAT_FLOAT
307static void f_pow(typval_T *argvars, typval_T *rettv);
308#endif
309static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
310static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200311#ifdef FEAT_JOB_CHANNEL
312static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200313static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200314static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
315#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200316static void f_pumvisible(typval_T *argvars, typval_T *rettv);
317#ifdef FEAT_PYTHON3
318static void f_py3eval(typval_T *argvars, typval_T *rettv);
319#endif
320#ifdef FEAT_PYTHON
321static void f_pyeval(typval_T *argvars, typval_T *rettv);
322#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100323#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
324static void f_pyxeval(typval_T *argvars, typval_T *rettv);
325#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200327static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200328static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200329static void f_reg_executing(typval_T *argvars, typval_T *rettv);
330static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200331static void f_reltime(typval_T *argvars, typval_T *rettv);
332#ifdef FEAT_FLOAT
333static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
334#endif
335static void f_reltimestr(typval_T *argvars, typval_T *rettv);
336static void f_remote_expr(typval_T *argvars, typval_T *rettv);
337static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
338static void f_remote_peek(typval_T *argvars, typval_T *rettv);
339static void f_remote_read(typval_T *argvars, typval_T *rettv);
340static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100341static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342static void f_remove(typval_T *argvars, typval_T *rettv);
343static void f_rename(typval_T *argvars, typval_T *rettv);
344static void f_repeat(typval_T *argvars, typval_T *rettv);
345static void f_resolve(typval_T *argvars, typval_T *rettv);
346static void f_reverse(typval_T *argvars, typval_T *rettv);
347#ifdef FEAT_FLOAT
348static void f_round(typval_T *argvars, typval_T *rettv);
349#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100350#ifdef FEAT_RUBY
351static void f_rubyeval(typval_T *argvars, typval_T *rettv);
352#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353static void f_screenattr(typval_T *argvars, typval_T *rettv);
354static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100355static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200356static void f_screencol(typval_T *argvars, typval_T *rettv);
357static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100358static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359static void f_search(typval_T *argvars, typval_T *rettv);
360static void f_searchdecl(typval_T *argvars, typval_T *rettv);
361static void f_searchpair(typval_T *argvars, typval_T *rettv);
362static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
363static void f_searchpos(typval_T *argvars, typval_T *rettv);
364static void f_server2client(typval_T *argvars, typval_T *rettv);
365static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200366static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200367static void f_setbufvar(typval_T *argvars, typval_T *rettv);
368static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
369static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200370static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200371static void f_setfperm(typval_T *argvars, typval_T *rettv);
372static void f_setline(typval_T *argvars, typval_T *rettv);
373static void f_setloclist(typval_T *argvars, typval_T *rettv);
374static void f_setmatches(typval_T *argvars, typval_T *rettv);
375static void f_setpos(typval_T *argvars, typval_T *rettv);
376static void f_setqflist(typval_T *argvars, typval_T *rettv);
377static void f_setreg(typval_T *argvars, typval_T *rettv);
378static void f_settabvar(typval_T *argvars, typval_T *rettv);
379static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100380static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381static void f_setwinvar(typval_T *argvars, typval_T *rettv);
382#ifdef FEAT_CRYPT
383static void f_sha256(typval_T *argvars, typval_T *rettv);
384#endif /* FEAT_CRYPT */
385static void f_shellescape(typval_T *argvars, typval_T *rettv);
386static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100387#ifdef FEAT_SIGNS
388static void f_sign_define(typval_T *argvars, typval_T *rettv);
389static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
390static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100391static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100392static void f_sign_place(typval_T *argvars, typval_T *rettv);
393static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
394static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
395#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200396static void f_simplify(typval_T *argvars, typval_T *rettv);
397#ifdef FEAT_FLOAT
398static void f_sin(typval_T *argvars, typval_T *rettv);
399static void f_sinh(typval_T *argvars, typval_T *rettv);
400#endif
401static void f_sort(typval_T *argvars, typval_T *rettv);
402static void f_soundfold(typval_T *argvars, typval_T *rettv);
403static void f_spellbadword(typval_T *argvars, typval_T *rettv);
404static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
405static void f_split(typval_T *argvars, typval_T *rettv);
406#ifdef FEAT_FLOAT
407static void f_sqrt(typval_T *argvars, typval_T *rettv);
408static void f_str2float(typval_T *argvars, typval_T *rettv);
409#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200410static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200411static void f_str2nr(typval_T *argvars, typval_T *rettv);
412static void f_strchars(typval_T *argvars, typval_T *rettv);
413#ifdef HAVE_STRFTIME
414static void f_strftime(typval_T *argvars, typval_T *rettv);
415#endif
416static void f_strgetchar(typval_T *argvars, typval_T *rettv);
417static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200418static void f_strlen(typval_T *argvars, typval_T *rettv);
419static void f_strcharpart(typval_T *argvars, typval_T *rettv);
420static void f_strpart(typval_T *argvars, typval_T *rettv);
421static void f_strridx(typval_T *argvars, typval_T *rettv);
422static void f_strtrans(typval_T *argvars, typval_T *rettv);
423static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
424static void f_strwidth(typval_T *argvars, typval_T *rettv);
425static void f_submatch(typval_T *argvars, typval_T *rettv);
426static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200427static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200428static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429static void f_synID(typval_T *argvars, typval_T *rettv);
430static void f_synIDattr(typval_T *argvars, typval_T *rettv);
431static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
432static void f_synstack(typval_T *argvars, typval_T *rettv);
433static void f_synconcealed(typval_T *argvars, typval_T *rettv);
434static void f_system(typval_T *argvars, typval_T *rettv);
435static void f_systemlist(typval_T *argvars, typval_T *rettv);
436static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
437static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
438static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
439static void f_taglist(typval_T *argvars, typval_T *rettv);
440static void f_tagfiles(typval_T *argvars, typval_T *rettv);
441static void f_tempname(typval_T *argvars, typval_T *rettv);
442static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
443static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200444static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200445static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100446static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100447static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200448static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100449static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100450static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200451#ifdef FEAT_JOB_CHANNEL
452static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
453#endif
454static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
455#ifdef FEAT_JOB_CHANNEL
456static void f_test_null_job(typval_T *argvars, typval_T *rettv);
457#endif
458static void f_test_null_list(typval_T *argvars, typval_T *rettv);
459static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
460static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200461#ifdef FEAT_GUI
462static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
463#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200464#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +0200465static void f_test_setmouse(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200466#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467static void f_test_settime(typval_T *argvars, typval_T *rettv);
468#ifdef FEAT_FLOAT
469static void f_tan(typval_T *argvars, typval_T *rettv);
470static void f_tanh(typval_T *argvars, typval_T *rettv);
471#endif
472#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200473static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200474static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200475static void f_timer_start(typval_T *argvars, typval_T *rettv);
476static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200477static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200478#endif
479static void f_tolower(typval_T *argvars, typval_T *rettv);
480static void f_toupper(typval_T *argvars, typval_T *rettv);
481static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100482static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200483#ifdef FEAT_FLOAT
484static void f_trunc(typval_T *argvars, typval_T *rettv);
485#endif
486static void f_type(typval_T *argvars, typval_T *rettv);
487static void f_undofile(typval_T *argvars, typval_T *rettv);
488static void f_undotree(typval_T *argvars, typval_T *rettv);
489static void f_uniq(typval_T *argvars, typval_T *rettv);
490static void f_values(typval_T *argvars, typval_T *rettv);
491static void f_virtcol(typval_T *argvars, typval_T *rettv);
492static void f_visualmode(typval_T *argvars, typval_T *rettv);
493static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
494static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
495static void f_win_getid(typval_T *argvars, typval_T *rettv);
496static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
497static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
498static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100499static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200500static void f_winbufnr(typval_T *argvars, typval_T *rettv);
501static void f_wincol(typval_T *argvars, typval_T *rettv);
502static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200503static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200504static void f_winline(typval_T *argvars, typval_T *rettv);
505static void f_winnr(typval_T *argvars, typval_T *rettv);
506static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
507static void f_winrestview(typval_T *argvars, typval_T *rettv);
508static void f_winsaveview(typval_T *argvars, typval_T *rettv);
509static void f_winwidth(typval_T *argvars, typval_T *rettv);
510static void f_writefile(typval_T *argvars, typval_T *rettv);
511static void f_wordcount(typval_T *argvars, typval_T *rettv);
512static void f_xor(typval_T *argvars, typval_T *rettv);
513
514/*
515 * Array with names and number of arguments of all internal functions
516 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
517 */
518static struct fst
519{
520 char *f_name; /* function name */
521 char f_min_argc; /* minimal number of arguments */
522 char f_max_argc; /* maximal number of arguments */
523 void (*f_func)(typval_T *args, typval_T *rvar);
524 /* implementation of function */
525} functions[] =
526{
527#ifdef FEAT_FLOAT
528 {"abs", 1, 1, f_abs},
529 {"acos", 1, 1, f_acos}, /* WJMc */
530#endif
531 {"add", 2, 2, f_add},
532 {"and", 2, 2, f_and},
533 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200534 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200535 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536 {"argidx", 0, 0, f_argidx},
537 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200538 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200539#ifdef FEAT_FLOAT
540 {"asin", 1, 1, f_asin}, /* WJMc */
541#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100542 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200543 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100544 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200545 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200546 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100548 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200549 {"assert_match", 2, 3, f_assert_match},
550 {"assert_notequal", 2, 3, f_assert_notequal},
551 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100552 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200553 {"assert_true", 1, 2, f_assert_true},
554#ifdef FEAT_FLOAT
555 {"atan", 1, 1, f_atan},
556 {"atan2", 2, 2, f_atan2},
557#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100558#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +0200559 {"balloon_gettext", 0, 0, f_balloon_gettext},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100560 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100561# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100562 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100563# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100564#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200565 {"browse", 4, 4, f_browse},
566 {"browsedir", 2, 2, f_browsedir},
567 {"bufexists", 1, 1, f_bufexists},
568 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
569 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
570 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
571 {"buflisted", 1, 1, f_buflisted},
572 {"bufloaded", 1, 1, f_bufloaded},
573 {"bufname", 1, 1, f_bufname},
574 {"bufnr", 1, 2, f_bufnr},
575 {"bufwinid", 1, 1, f_bufwinid},
576 {"bufwinnr", 1, 1, f_bufwinnr},
577 {"byte2line", 1, 1, f_byte2line},
578 {"byteidx", 2, 2, f_byteidx},
579 {"byteidxcomp", 2, 2, f_byteidxcomp},
580 {"call", 2, 3, f_call},
581#ifdef FEAT_FLOAT
582 {"ceil", 1, 1, f_ceil},
583#endif
584#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100585 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200587 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
589 {"ch_evalraw", 2, 3, f_ch_evalraw},
590 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
591 {"ch_getjob", 1, 1, f_ch_getjob},
592 {"ch_info", 1, 1, f_ch_info},
593 {"ch_log", 1, 2, f_ch_log},
594 {"ch_logfile", 1, 2, f_ch_logfile},
595 {"ch_open", 1, 2, f_ch_open},
596 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100597 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200598 {"ch_readraw", 1, 2, f_ch_readraw},
599 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
600 {"ch_sendraw", 2, 3, f_ch_sendraw},
601 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200602 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#endif
604 {"changenr", 0, 0, f_changenr},
605 {"char2nr", 1, 2, f_char2nr},
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200606 {"chdir", 1, 1, f_chdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200607 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100608 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609 {"col", 1, 1, f_col},
610#if defined(FEAT_INS_EXPAND)
611 {"complete", 2, 2, f_complete},
612 {"complete_add", 1, 1, f_complete_add},
613 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100614 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200615#endif
616 {"confirm", 1, 4, f_confirm},
617 {"copy", 1, 1, f_copy},
618#ifdef FEAT_FLOAT
619 {"cos", 1, 1, f_cos},
620 {"cosh", 1, 1, f_cosh},
621#endif
622 {"count", 2, 4, f_count},
623 {"cscope_connection",0,3, f_cscope_connection},
624 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100625#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200626 {"debugbreak", 1, 1, f_debugbreak},
627#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628 {"deepcopy", 1, 2, f_deepcopy},
629 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200630 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200631 {"did_filetype", 0, 0, f_did_filetype},
632 {"diff_filler", 1, 1, f_diff_filler},
633 {"diff_hlID", 2, 2, f_diff_hlID},
634 {"empty", 1, 1, f_empty},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200635 {"environ", 0, 0, f_environ},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"escape", 2, 2, f_escape},
637 {"eval", 1, 1, f_eval},
638 {"eventhandler", 0, 0, f_eventhandler},
639 {"executable", 1, 1, f_executable},
640 {"execute", 1, 2, f_execute},
641 {"exepath", 1, 1, f_exepath},
642 {"exists", 1, 1, f_exists},
643#ifdef FEAT_FLOAT
644 {"exp", 1, 1, f_exp},
645#endif
646 {"expand", 1, 3, f_expand},
647 {"extend", 2, 3, f_extend},
648 {"feedkeys", 1, 2, f_feedkeys},
649 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
650 {"filereadable", 1, 1, f_filereadable},
651 {"filewritable", 1, 1, f_filewritable},
652 {"filter", 2, 2, f_filter},
653 {"finddir", 1, 3, f_finddir},
654 {"findfile", 1, 3, f_findfile},
655#ifdef FEAT_FLOAT
656 {"float2nr", 1, 1, f_float2nr},
657 {"floor", 1, 1, f_floor},
658 {"fmod", 2, 2, f_fmod},
659#endif
660 {"fnameescape", 1, 1, f_fnameescape},
661 {"fnamemodify", 2, 2, f_fnamemodify},
662 {"foldclosed", 1, 1, f_foldclosed},
663 {"foldclosedend", 1, 1, f_foldclosedend},
664 {"foldlevel", 1, 1, f_foldlevel},
665 {"foldtext", 0, 0, f_foldtext},
666 {"foldtextresult", 1, 1, f_foldtextresult},
667 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200668 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200669 {"function", 1, 3, f_function},
670 {"garbagecollect", 0, 1, f_garbagecollect},
671 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200672 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200673 {"getbufline", 2, 3, f_getbufline},
674 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100675 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200676 {"getchar", 0, 1, f_getchar},
677 {"getcharmod", 0, 0, f_getcharmod},
678 {"getcharsearch", 0, 0, f_getcharsearch},
679 {"getcmdline", 0, 0, f_getcmdline},
680 {"getcmdpos", 0, 0, f_getcmdpos},
681 {"getcmdtype", 0, 0, f_getcmdtype},
682 {"getcmdwintype", 0, 0, f_getcmdwintype},
683#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200684 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685#endif
686 {"getcurpos", 0, 0, f_getcurpos},
687 {"getcwd", 0, 2, f_getcwd},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200688 {"getenv", 1, 1, f_getenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689 {"getfontname", 0, 1, f_getfontname},
690 {"getfperm", 1, 1, f_getfperm},
691 {"getfsize", 1, 1, f_getfsize},
692 {"getftime", 1, 1, f_getftime},
693 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100694 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200696 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100697 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200698 {"getpid", 0, 0, f_getpid},
699 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200700 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200701 {"getreg", 0, 3, f_getreg},
702 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200703 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200704 {"gettabvar", 2, 3, f_gettabvar},
705 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100706 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200707 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100708 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709 {"getwinposx", 0, 0, f_getwinposx},
710 {"getwinposy", 0, 0, f_getwinposy},
711 {"getwinvar", 2, 3, f_getwinvar},
712 {"glob", 1, 4, f_glob},
713 {"glob2regpat", 1, 1, f_glob2regpat},
714 {"globpath", 2, 5, f_globpath},
715 {"has", 1, 1, f_has},
716 {"has_key", 2, 2, f_has_key},
717 {"haslocaldir", 0, 2, f_haslocaldir},
718 {"hasmapto", 1, 3, f_hasmapto},
719 {"highlightID", 1, 1, f_hlID}, /* obsolete */
720 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
721 {"histadd", 2, 2, f_histadd},
722 {"histdel", 1, 2, f_histdel},
723 {"histget", 1, 2, f_histget},
724 {"histnr", 1, 1, f_histnr},
725 {"hlID", 1, 1, f_hlID},
726 {"hlexists", 1, 1, f_hlexists},
727 {"hostname", 0, 0, f_hostname},
728 {"iconv", 3, 3, f_iconv},
729 {"indent", 1, 1, f_indent},
730 {"index", 2, 4, f_index},
731 {"input", 1, 3, f_input},
732 {"inputdialog", 1, 3, f_inputdialog},
733 {"inputlist", 1, 1, f_inputlist},
734 {"inputrestore", 0, 0, f_inputrestore},
735 {"inputsave", 0, 0, f_inputsave},
736 {"inputsecret", 1, 2, f_inputsecret},
737 {"insert", 2, 3, f_insert},
738 {"invert", 1, 1, f_invert},
739 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200740#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
741 {"isinf", 1, 1, f_isinf},
742#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200743 {"islocked", 1, 1, f_islocked},
744#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
745 {"isnan", 1, 1, f_isnan},
746#endif
747 {"items", 1, 1, f_items},
748#ifdef FEAT_JOB_CHANNEL
749 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200750 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200751 {"job_setoptions", 2, 2, f_job_setoptions},
752 {"job_start", 1, 2, f_job_start},
753 {"job_status", 1, 1, f_job_status},
754 {"job_stop", 1, 2, f_job_stop},
755#endif
756 {"join", 1, 2, f_join},
757 {"js_decode", 1, 1, f_js_decode},
758 {"js_encode", 1, 1, f_js_encode},
759 {"json_decode", 1, 1, f_json_decode},
760 {"json_encode", 1, 1, f_json_encode},
761 {"keys", 1, 1, f_keys},
762 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
763 {"len", 1, 1, f_len},
764 {"libcall", 3, 3, f_libcall},
765 {"libcallnr", 3, 3, f_libcallnr},
766 {"line", 1, 1, f_line},
767 {"line2byte", 1, 1, f_line2byte},
768 {"lispindent", 1, 1, f_lispindent},
Bram Moolenaar9d401282019-04-06 13:18:12 +0200769 {"list2str", 1, 2, f_list2str},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200770 {"listener_add", 1, 2, f_listener_add},
771 {"listener_remove", 1, 1, f_listener_remove},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772 {"localtime", 0, 0, f_localtime},
773#ifdef FEAT_FLOAT
774 {"log", 1, 1, f_log},
775 {"log10", 1, 1, f_log10},
776#endif
777#ifdef FEAT_LUA
778 {"luaeval", 1, 2, f_luaeval},
779#endif
780 {"map", 2, 2, f_map},
781 {"maparg", 1, 4, f_maparg},
782 {"mapcheck", 1, 3, f_mapcheck},
783 {"match", 2, 4, f_match},
784 {"matchadd", 2, 5, f_matchadd},
785 {"matchaddpos", 2, 5, f_matchaddpos},
786 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100787 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"matchend", 2, 4, f_matchend},
789 {"matchlist", 2, 4, f_matchlist},
790 {"matchstr", 2, 4, f_matchstr},
791 {"matchstrpos", 2, 4, f_matchstrpos},
792 {"max", 1, 1, f_max},
793 {"min", 1, 1, f_min},
794#ifdef vim_mkdir
795 {"mkdir", 1, 3, f_mkdir},
796#endif
797 {"mode", 0, 1, f_mode},
798#ifdef FEAT_MZSCHEME
799 {"mzeval", 1, 1, f_mzeval},
800#endif
801 {"nextnonblank", 1, 1, f_nextnonblank},
802 {"nr2char", 1, 2, f_nr2char},
803 {"or", 2, 2, f_or},
804 {"pathshorten", 1, 1, f_pathshorten},
805#ifdef FEAT_PERL
806 {"perleval", 1, 1, f_perleval},
807#endif
808#ifdef FEAT_FLOAT
809 {"pow", 2, 2, f_pow},
810#endif
811 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100812 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200813#ifdef FEAT_JOB_CHANNEL
814 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200815 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200816 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
817#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100818#ifdef FEAT_TEXT_PROP
819 {"prop_add", 3, 3, f_prop_add},
820 {"prop_clear", 1, 3, f_prop_clear},
821 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100822 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100823 {"prop_type_add", 2, 2, f_prop_type_add},
824 {"prop_type_change", 2, 2, f_prop_type_change},
825 {"prop_type_delete", 1, 2, f_prop_type_delete},
826 {"prop_type_get", 1, 2, f_prop_type_get},
827 {"prop_type_list", 0, 1, f_prop_type_list},
828#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200829 {"pumvisible", 0, 0, f_pumvisible},
830#ifdef FEAT_PYTHON3
831 {"py3eval", 1, 1, f_py3eval},
832#endif
833#ifdef FEAT_PYTHON
834 {"pyeval", 1, 1, f_pyeval},
835#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100836#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
837 {"pyxeval", 1, 1, f_pyxeval},
838#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200840 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200841 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200842 {"reg_executing", 0, 0, f_reg_executing},
843 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200844 {"reltime", 0, 2, f_reltime},
845#ifdef FEAT_FLOAT
846 {"reltimefloat", 1, 1, f_reltimefloat},
847#endif
848 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100849 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850 {"remote_foreground", 1, 1, f_remote_foreground},
851 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100852 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100854 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200855 {"remove", 2, 3, f_remove},
856 {"rename", 2, 2, f_rename},
857 {"repeat", 2, 2, f_repeat},
858 {"resolve", 1, 1, f_resolve},
859 {"reverse", 1, 1, f_reverse},
860#ifdef FEAT_FLOAT
861 {"round", 1, 1, f_round},
862#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100863#ifdef FEAT_RUBY
864 {"rubyeval", 1, 1, f_rubyeval},
865#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866 {"screenattr", 2, 2, f_screenattr},
867 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100868 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869 {"screencol", 0, 0, f_screencol},
870 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100871 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200872 {"search", 1, 4, f_search},
873 {"searchdecl", 1, 3, f_searchdecl},
874 {"searchpair", 3, 7, f_searchpair},
875 {"searchpairpos", 3, 7, f_searchpairpos},
876 {"searchpos", 1, 4, f_searchpos},
877 {"server2client", 2, 2, f_server2client},
878 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200879 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200880 {"setbufvar", 3, 3, f_setbufvar},
881 {"setcharsearch", 1, 1, f_setcharsearch},
882 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200883 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200884 {"setfperm", 2, 2, f_setfperm},
885 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200886 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100887 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200889 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890 {"setreg", 2, 3, f_setreg},
891 {"settabvar", 3, 3, f_settabvar},
892 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100893 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200894 {"setwinvar", 3, 3, f_setwinvar},
895#ifdef FEAT_CRYPT
896 {"sha256", 1, 1, f_sha256},
897#endif
898 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100899 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100900#ifdef FEAT_SIGNS
901 {"sign_define", 1, 2, f_sign_define},
902 {"sign_getdefined", 0, 1, f_sign_getdefined},
903 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100904 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100905 {"sign_place", 4, 5, f_sign_place},
906 {"sign_undefine", 0, 1, f_sign_undefine},
907 {"sign_unplace", 1, 2, f_sign_unplace},
908#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200909 {"simplify", 1, 1, f_simplify},
910#ifdef FEAT_FLOAT
911 {"sin", 1, 1, f_sin},
912 {"sinh", 1, 1, f_sinh},
913#endif
914 {"sort", 1, 3, f_sort},
915 {"soundfold", 1, 1, f_soundfold},
916 {"spellbadword", 0, 1, f_spellbadword},
917 {"spellsuggest", 1, 3, f_spellsuggest},
918 {"split", 1, 3, f_split},
919#ifdef FEAT_FLOAT
920 {"sqrt", 1, 1, f_sqrt},
921 {"str2float", 1, 1, f_str2float},
922#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200923 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200924 {"str2nr", 1, 2, f_str2nr},
925 {"strcharpart", 2, 3, f_strcharpart},
926 {"strchars", 1, 2, f_strchars},
927 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
928#ifdef HAVE_STRFTIME
929 {"strftime", 1, 2, f_strftime},
930#endif
931 {"strgetchar", 2, 2, f_strgetchar},
932 {"stridx", 2, 3, f_stridx},
933 {"string", 1, 1, f_string},
934 {"strlen", 1, 1, f_strlen},
935 {"strpart", 2, 3, f_strpart},
936 {"strridx", 2, 3, f_strridx},
937 {"strtrans", 1, 1, f_strtrans},
938 {"strwidth", 1, 1, f_strwidth},
939 {"submatch", 1, 2, f_submatch},
940 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200941 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200942 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943 {"synID", 3, 3, f_synID},
944 {"synIDattr", 2, 3, f_synIDattr},
945 {"synIDtrans", 1, 1, f_synIDtrans},
946 {"synconcealed", 2, 2, f_synconcealed},
947 {"synstack", 2, 2, f_synstack},
948 {"system", 1, 2, f_system},
949 {"systemlist", 1, 2, f_systemlist},
950 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
951 {"tabpagenr", 0, 1, f_tabpagenr},
952 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
953 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100954 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955#ifdef FEAT_FLOAT
956 {"tan", 1, 1, f_tan},
957 {"tanh", 1, 1, f_tanh},
958#endif
959 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200960#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100961 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
962 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100963 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200964 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200965# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
966 {"term_getansicolors", 1, 1, f_term_getansicolors},
967# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200968 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200969 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200970 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200971 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200972 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200973 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200974 {"term_getstatus", 1, 1, f_term_getstatus},
975 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200976 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200977 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200978 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200979 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200980# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
981 {"term_setansicolors", 2, 2, f_term_setansicolors},
982# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100983 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100984 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200985 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200986 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200987 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200988#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200989 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
990 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200991 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200992 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100993 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100994 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200995#ifdef FEAT_JOB_CHANNEL
996 {"test_null_channel", 0, 0, f_test_null_channel},
997#endif
998 {"test_null_dict", 0, 0, f_test_null_dict},
999#ifdef FEAT_JOB_CHANNEL
1000 {"test_null_job", 0, 0, f_test_null_job},
1001#endif
1002 {"test_null_list", 0, 0, f_test_null_list},
1003 {"test_null_partial", 0, 0, f_test_null_partial},
1004 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +02001005 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +01001006 {"test_override", 2, 2, f_test_override},
1007 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +02001008#ifdef FEAT_GUI
1009 {"test_scrollbar", 3, 3, f_test_scrollbar},
1010#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +02001011#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +02001012 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +02001013#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014 {"test_settime", 1, 1, f_test_settime},
1015#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001016 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001017 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001018 {"timer_start", 2, 3, f_timer_start},
1019 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001020 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021#endif
1022 {"tolower", 1, 1, f_tolower},
1023 {"toupper", 1, 1, f_toupper},
1024 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01001025 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001026#ifdef FEAT_FLOAT
1027 {"trunc", 1, 1, f_trunc},
1028#endif
1029 {"type", 1, 1, f_type},
1030 {"undofile", 1, 1, f_undofile},
1031 {"undotree", 0, 0, f_undotree},
1032 {"uniq", 1, 3, f_uniq},
1033 {"values", 1, 1, f_values},
1034 {"virtcol", 1, 1, f_virtcol},
1035 {"visualmode", 0, 1, f_visualmode},
1036 {"wildmenumode", 0, 0, f_wildmenumode},
1037 {"win_findbuf", 1, 1, f_win_findbuf},
1038 {"win_getid", 0, 2, f_win_getid},
1039 {"win_gotoid", 1, 1, f_win_gotoid},
1040 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1041 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001042 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001043 {"winbufnr", 1, 1, f_winbufnr},
1044 {"wincol", 0, 0, f_wincol},
1045 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001046 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001047 {"winline", 0, 0, f_winline},
1048 {"winnr", 0, 1, f_winnr},
1049 {"winrestcmd", 0, 0, f_winrestcmd},
1050 {"winrestview", 1, 1, f_winrestview},
1051 {"winsaveview", 0, 0, f_winsaveview},
1052 {"winwidth", 1, 1, f_winwidth},
1053 {"wordcount", 0, 0, f_wordcount},
1054 {"writefile", 2, 3, f_writefile},
1055 {"xor", 2, 2, f_xor},
1056};
1057
1058#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1059
1060/*
1061 * Function given to ExpandGeneric() to obtain the list of internal
1062 * or user defined function names.
1063 */
1064 char_u *
1065get_function_name(expand_T *xp, int idx)
1066{
1067 static int intidx = -1;
1068 char_u *name;
1069
1070 if (idx == 0)
1071 intidx = -1;
1072 if (intidx < 0)
1073 {
1074 name = get_user_func_name(xp, idx);
1075 if (name != NULL)
1076 return name;
1077 }
1078 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1079 {
1080 STRCPY(IObuff, functions[intidx].f_name);
1081 STRCAT(IObuff, "(");
1082 if (functions[intidx].f_max_argc == 0)
1083 STRCAT(IObuff, ")");
1084 return IObuff;
1085 }
1086
1087 return NULL;
1088}
1089
1090/*
1091 * Function given to ExpandGeneric() to obtain the list of internal or
1092 * user defined variable or function names.
1093 */
1094 char_u *
1095get_expr_name(expand_T *xp, int idx)
1096{
1097 static int intidx = -1;
1098 char_u *name;
1099
1100 if (idx == 0)
1101 intidx = -1;
1102 if (intidx < 0)
1103 {
1104 name = get_function_name(xp, idx);
1105 if (name != NULL)
1106 return name;
1107 }
1108 return get_user_var_name(xp, ++intidx);
1109}
1110
1111#endif /* FEAT_CMDL_COMPL */
1112
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001113/*
1114 * Find internal function in table above.
1115 * Return index, or -1 if not found
1116 */
1117 int
1118find_internal_func(
1119 char_u *name) /* name of the function */
1120{
1121 int first = 0;
1122 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1123 int cmp;
1124 int x;
1125
1126 /*
1127 * Find the function name in the table. Binary search.
1128 */
1129 while (first <= last)
1130 {
1131 x = first + ((unsigned)(last - first) >> 1);
1132 cmp = STRCMP(name, functions[x].f_name);
1133 if (cmp < 0)
1134 last = x - 1;
1135 else if (cmp > 0)
1136 first = x + 1;
1137 else
1138 return x;
1139 }
1140 return -1;
1141}
1142
1143 int
1144call_internal_func(
1145 char_u *name,
1146 int argcount,
1147 typval_T *argvars,
1148 typval_T *rettv)
1149{
1150 int i;
1151
1152 i = find_internal_func(name);
1153 if (i < 0)
1154 return ERROR_UNKNOWN;
1155 if (argcount < functions[i].f_min_argc)
1156 return ERROR_TOOFEW;
1157 if (argcount > functions[i].f_max_argc)
1158 return ERROR_TOOMANY;
1159 argvars[argcount].v_type = VAR_UNKNOWN;
1160 functions[i].f_func(argvars, rettv);
1161 return ERROR_NONE;
1162}
1163
1164/*
1165 * Return TRUE for a non-zero Number and a non-empty String.
1166 */
1167 static int
1168non_zero_arg(typval_T *argvars)
1169{
1170 return ((argvars[0].v_type == VAR_NUMBER
1171 && argvars[0].vval.v_number != 0)
1172 || (argvars[0].v_type == VAR_SPECIAL
1173 && argvars[0].vval.v_number == VVAL_TRUE)
1174 || (argvars[0].v_type == VAR_STRING
1175 && argvars[0].vval.v_string != NULL
1176 && *argvars[0].vval.v_string != NUL));
1177}
1178
1179/*
1180 * Get the lnum from the first argument.
1181 * Also accepts ".", "$", etc., but that only works for the current buffer.
1182 * Returns -1 on error.
1183 */
1184 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001185tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001186{
1187 typval_T rettv;
1188 linenr_T lnum;
1189
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001190 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001191 if (lnum == 0) /* no valid number, try using line() */
1192 {
1193 rettv.v_type = VAR_NUMBER;
1194 f_line(argvars, &rettv);
1195 lnum = (linenr_T)rettv.vval.v_number;
1196 clear_tv(&rettv);
1197 }
1198 return lnum;
1199}
1200
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001201/*
1202 * Get the lnum from the first argument.
1203 * Also accepts "$", then "buf" is used.
1204 * Returns 0 on error.
1205 */
1206 static linenr_T
1207tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1208{
1209 if (argvars[0].v_type == VAR_STRING
1210 && argvars[0].vval.v_string != NULL
1211 && argvars[0].vval.v_string[0] == '$'
1212 && buf != NULL)
1213 return buf->b_ml.ml_line_count;
1214 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1215}
1216
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001217#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001218/*
1219 * Get the float value of "argvars[0]" into "f".
1220 * Returns FAIL when the argument is not a Number or Float.
1221 */
1222 static int
1223get_float_arg(typval_T *argvars, float_T *f)
1224{
1225 if (argvars[0].v_type == VAR_FLOAT)
1226 {
1227 *f = argvars[0].vval.v_float;
1228 return OK;
1229 }
1230 if (argvars[0].v_type == VAR_NUMBER)
1231 {
1232 *f = (float_T)argvars[0].vval.v_number;
1233 return OK;
1234 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001235 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001236 return FAIL;
1237}
1238
1239/*
1240 * "abs(expr)" function
1241 */
1242 static void
1243f_abs(typval_T *argvars, typval_T *rettv)
1244{
1245 if (argvars[0].v_type == VAR_FLOAT)
1246 {
1247 rettv->v_type = VAR_FLOAT;
1248 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1249 }
1250 else
1251 {
1252 varnumber_T n;
1253 int error = FALSE;
1254
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001255 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001256 if (error)
1257 rettv->vval.v_number = -1;
1258 else if (n > 0)
1259 rettv->vval.v_number = n;
1260 else
1261 rettv->vval.v_number = -n;
1262 }
1263}
1264
1265/*
1266 * "acos()" function
1267 */
1268 static void
1269f_acos(typval_T *argvars, typval_T *rettv)
1270{
1271 float_T f = 0.0;
1272
1273 rettv->v_type = VAR_FLOAT;
1274 if (get_float_arg(argvars, &f) == OK)
1275 rettv->vval.v_float = acos(f);
1276 else
1277 rettv->vval.v_float = 0.0;
1278}
1279#endif
1280
1281/*
1282 * "add(list, item)" function
1283 */
1284 static void
1285f_add(typval_T *argvars, typval_T *rettv)
1286{
1287 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001288 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001289
1290 rettv->vval.v_number = 1; /* Default: Failed */
1291 if (argvars[0].v_type == VAR_LIST)
1292 {
1293 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001294 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 (char_u *)N_("add() argument"), TRUE)
1296 && list_append_tv(l, &argvars[1]) == OK)
1297 copy_tv(&argvars[0], rettv);
1298 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001299 else if (argvars[0].v_type == VAR_BLOB)
1300 {
1301 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001302 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001303 (char_u *)N_("add() argument"), TRUE))
1304 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001305 int error = FALSE;
1306 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1307
1308 if (!error)
1309 {
1310 ga_append(&b->bv_ga, (int)n);
1311 copy_tv(&argvars[0], rettv);
1312 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001313 }
1314 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001315 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001316 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001317}
1318
1319/*
1320 * "and(expr, expr)" function
1321 */
1322 static void
1323f_and(typval_T *argvars, typval_T *rettv)
1324{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001325 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1326 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001327}
1328
1329/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001330 * If there is a window for "curbuf", make it the current window.
1331 */
1332 static void
1333find_win_for_curbuf(void)
1334{
1335 wininfo_T *wip;
1336
1337 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1338 {
1339 if (wip->wi_win != NULL)
1340 {
1341 curwin = wip->wi_win;
1342 break;
1343 }
1344 }
1345}
1346
1347/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001349 */
1350 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001351set_buffer_lines(
1352 buf_T *buf,
1353 linenr_T lnum_arg,
1354 int append,
1355 typval_T *lines,
1356 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001357{
Bram Moolenaarca851592018-06-06 21:04:07 +02001358 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1359 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 list_T *l = NULL;
1361 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001363 linenr_T append_lnum;
1364 buf_T *curbuf_save = NULL;
1365 win_T *curwin_save = NULL;
1366 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367
Bram Moolenaarca851592018-06-06 21:04:07 +02001368 /* When using the current buffer ml_mfp will be set if needed. Useful when
1369 * setline() is used on startup. For other buffers the buffer must be
1370 * loaded. */
1371 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001372 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001373 rettv->vval.v_number = 1; /* FAIL */
1374 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001375 }
1376
Bram Moolenaarca851592018-06-06 21:04:07 +02001377 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001378 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001379 curbuf_save = curbuf;
1380 curwin_save = curwin;
1381 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001382 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001383 }
1384
1385 if (append)
1386 // appendbufline() uses the line number below which we insert
1387 append_lnum = lnum - 1;
1388 else
1389 // setbufline() uses the line number above which we insert, we only
1390 // append if it's below the last line
1391 append_lnum = curbuf->b_ml.ml_line_count;
1392
1393 if (lines->v_type == VAR_LIST)
1394 {
1395 l = lines->vval.v_list;
1396 li = l->lv_first;
1397 }
1398 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001399 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001400
1401 /* default result is zero == OK */
1402 for (;;)
1403 {
1404 if (l != NULL)
1405 {
1406 /* list argument, get next string */
1407 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001408 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001409 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001410 li = li->li_next;
1411 }
1412
Bram Moolenaarca851592018-06-06 21:04:07 +02001413 rettv->vval.v_number = 1; /* FAIL */
1414 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1415 break;
1416
1417 /* When coming here from Insert mode, sync undo, so that this can be
1418 * undone separately from what was previously inserted. */
1419 if (u_sync_once == 2)
1420 {
1421 u_sync_once = 1; /* notify that u_sync() was called */
1422 u_sync(TRUE);
1423 }
1424
1425 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1426 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001427 // Existing line, replace it.
1428 // Removes any existing text properties.
1429 if (u_savesub(lnum) == OK && ml_replace_len(
1430 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001431 {
1432 changed_bytes(lnum, 0);
1433 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1434 check_cursor_col();
1435 rettv->vval.v_number = 0; /* OK */
1436 }
1437 }
1438 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1439 {
1440 /* append the line */
1441 ++added;
1442 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1443 rettv->vval.v_number = 0; /* OK */
1444 }
1445
1446 if (l == NULL) /* only one string argument */
1447 break;
1448 ++lnum;
1449 }
1450
1451 if (added > 0)
1452 {
1453 win_T *wp;
1454 tabpage_T *tp;
1455
1456 appended_lines_mark(append_lnum, added);
1457 FOR_ALL_TAB_WINDOWS(tp, wp)
1458 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1459 wp->w_cursor.lnum += added;
1460 check_cursor_col();
1461
Bram Moolenaarf2732452018-06-03 14:47:35 +02001462#ifdef FEAT_JOB_CHANNEL
1463 if (bt_prompt(curbuf) && (State & INSERT))
1464 // show the line with the prompt
1465 update_topline();
1466#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001467 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001468
1469 if (!is_curbuf)
1470 {
1471 curbuf = curbuf_save;
1472 curwin = curwin_save;
1473 }
1474}
1475
1476/*
1477 * "append(lnum, string/list)" function
1478 */
1479 static void
1480f_append(typval_T *argvars, typval_T *rettv)
1481{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001482 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001483
1484 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1485}
1486
1487/*
1488 * "appendbufline(buf, lnum, string/list)" function
1489 */
1490 static void
1491f_appendbufline(typval_T *argvars, typval_T *rettv)
1492{
1493 linenr_T lnum;
1494 buf_T *buf;
1495
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001496 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001497 if (buf == NULL)
1498 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001500 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001501 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001502 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1503 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504}
1505
1506/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001507 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508 */
1509 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001510f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001511{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001512 win_T *wp;
1513
1514 if (argvars[0].v_type == VAR_UNKNOWN)
1515 // use the current window
1516 rettv->vval.v_number = ARGCOUNT;
1517 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001518 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001519 // use the global argument list
1520 rettv->vval.v_number = GARGCOUNT;
1521 else
1522 {
1523 // use the argument list of the specified window
1524 wp = find_win_by_nr_or_id(&argvars[0]);
1525 if (wp != NULL)
1526 rettv->vval.v_number = WARGCOUNT(wp);
1527 else
1528 rettv->vval.v_number = -1;
1529 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001530}
1531
1532/*
1533 * "argidx()" function
1534 */
1535 static void
1536f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1537{
1538 rettv->vval.v_number = curwin->w_arg_idx;
1539}
1540
1541/*
1542 * "arglistid()" function
1543 */
1544 static void
1545f_arglistid(typval_T *argvars, typval_T *rettv)
1546{
1547 win_T *wp;
1548
1549 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001550 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001551 if (wp != NULL)
1552 rettv->vval.v_number = wp->w_alist->id;
1553}
1554
1555/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001556 * Get the argument list for a given window
1557 */
1558 static void
1559get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1560{
1561 int idx;
1562
1563 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1564 for (idx = 0; idx < argcount; ++idx)
1565 list_append_string(rettv->vval.v_list,
1566 alist_name(&arglist[idx]), -1);
1567}
1568
1569/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 * "argv(nr)" function
1571 */
1572 static void
1573f_argv(typval_T *argvars, typval_T *rettv)
1574{
1575 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001576 aentry_T *arglist = NULL;
1577 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578
1579 if (argvars[0].v_type != VAR_UNKNOWN)
1580 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001581 if (argvars[1].v_type == VAR_UNKNOWN)
1582 {
1583 arglist = ARGLIST;
1584 argcount = ARGCOUNT;
1585 }
1586 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001587 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001588 {
1589 arglist = GARGLIST;
1590 argcount = GARGCOUNT;
1591 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001593 {
1594 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1595
1596 if (wp != NULL)
1597 {
1598 /* Use the argument list of the specified window */
1599 arglist = WARGLIST(wp);
1600 argcount = WARGCOUNT(wp);
1601 }
1602 }
1603
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001605 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001606 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001607 if (arglist != NULL && idx >= 0 && idx < argcount)
1608 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1609 else if (idx == -1)
1610 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001611 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001612 else
1613 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001614}
1615
1616/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001617 * "assert_beeps(cmd [, error])" function
1618 */
1619 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001620f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001621{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001622 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001623}
1624
1625/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001626 * "assert_equal(expected, actual[, msg])" function
1627 */
1628 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001629f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001631 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001632}
1633
1634/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001635 * "assert_equalfile(fname-one, fname-two)" function
1636 */
1637 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001638f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001639{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001640 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001641}
1642
1643/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001644 * "assert_notequal(expected, actual[, msg])" function
1645 */
1646 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001647f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001649 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650}
1651
1652/*
1653 * "assert_exception(string[, msg])" function
1654 */
1655 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001656f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001657{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001658 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659}
1660
1661/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001662 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001663 */
1664 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001665f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001666{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001667 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001668}
1669
1670/*
1671 * "assert_false(actual[, msg])" function
1672 */
1673 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001674f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001676 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001677}
1678
1679/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001680 * "assert_inrange(lower, upper[, msg])" function
1681 */
1682 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001683f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001684{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001685 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001686}
1687
1688/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001689 * "assert_match(pattern, actual[, msg])" function
1690 */
1691 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001692f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001694 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695}
1696
1697/*
1698 * "assert_notmatch(pattern, actual[, msg])" function
1699 */
1700 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001701f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001703 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001704}
1705
1706/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001707 * "assert_report(msg)" function
1708 */
1709 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001710f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001711{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001712 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001713}
1714
1715/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 * "assert_true(actual[, msg])" function
1717 */
1718 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001719f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001721 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722}
1723
1724#ifdef FEAT_FLOAT
1725/*
1726 * "asin()" function
1727 */
1728 static void
1729f_asin(typval_T *argvars, typval_T *rettv)
1730{
1731 float_T f = 0.0;
1732
1733 rettv->v_type = VAR_FLOAT;
1734 if (get_float_arg(argvars, &f) == OK)
1735 rettv->vval.v_float = asin(f);
1736 else
1737 rettv->vval.v_float = 0.0;
1738}
1739
1740/*
1741 * "atan()" function
1742 */
1743 static void
1744f_atan(typval_T *argvars, typval_T *rettv)
1745{
1746 float_T f = 0.0;
1747
1748 rettv->v_type = VAR_FLOAT;
1749 if (get_float_arg(argvars, &f) == OK)
1750 rettv->vval.v_float = atan(f);
1751 else
1752 rettv->vval.v_float = 0.0;
1753}
1754
1755/*
1756 * "atan2()" function
1757 */
1758 static void
1759f_atan2(typval_T *argvars, typval_T *rettv)
1760{
1761 float_T fx = 0.0, fy = 0.0;
1762
1763 rettv->v_type = VAR_FLOAT;
1764 if (get_float_arg(argvars, &fx) == OK
1765 && get_float_arg(&argvars[1], &fy) == OK)
1766 rettv->vval.v_float = atan2(fx, fy);
1767 else
1768 rettv->vval.v_float = 0.0;
1769}
1770#endif
1771
1772/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001773 * "balloon_show()" function
1774 */
1775#ifdef FEAT_BEVAL
1776 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001777f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1778{
1779 rettv->v_type = VAR_STRING;
1780 if (balloonEval != NULL)
1781 {
1782 if (balloonEval->msg == NULL)
1783 rettv->vval.v_string = NULL;
1784 else
1785 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1786 }
1787}
1788
1789 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001790f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1791{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001792 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001793 {
1794 if (argvars[0].v_type == VAR_LIST
1795# ifdef FEAT_GUI
1796 && !gui.in_use
1797# endif
1798 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001799 {
1800 list_T *l = argvars[0].vval.v_list;
1801
1802 // empty list removes the balloon
1803 post_balloon(balloonEval, NULL,
1804 l == NULL || l->lv_len == 0 ? NULL : l);
1805 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001806 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001807 {
1808 char_u *mesg = tv_get_string_chk(&argvars[0]);
1809
1810 if (mesg != NULL)
1811 // empty string removes the balloon
1812 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1813 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001814 }
1815}
1816
Bram Moolenaar669a8282017-11-19 20:13:05 +01001817# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001818 static void
1819f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1820{
1821 if (rettv_list_alloc(rettv) == OK)
1822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001823 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001824
1825 if (msg != NULL)
1826 {
1827 pumitem_T *array;
1828 int size = split_message(msg, &array);
1829 int i;
1830
1831 /* Skip the first and last item, they are always empty. */
1832 for (i = 1; i < size - 1; ++i)
1833 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001834 while (size > 0)
1835 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001836 vim_free(array);
1837 }
1838 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001839}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001840# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001841#endif
1842
1843/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 * "browse(save, title, initdir, default)" function
1845 */
1846 static void
1847f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1848{
1849#ifdef FEAT_BROWSE
1850 int save;
1851 char_u *title;
1852 char_u *initdir;
1853 char_u *defname;
1854 char_u buf[NUMBUFLEN];
1855 char_u buf2[NUMBUFLEN];
1856 int error = FALSE;
1857
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001858 save = (int)tv_get_number_chk(&argvars[0], &error);
1859 title = tv_get_string_chk(&argvars[1]);
1860 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1861 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001862
1863 if (error || title == NULL || initdir == NULL || defname == NULL)
1864 rettv->vval.v_string = NULL;
1865 else
1866 rettv->vval.v_string =
1867 do_browse(save ? BROWSE_SAVE : 0,
1868 title, defname, NULL, initdir, NULL, curbuf);
1869#else
1870 rettv->vval.v_string = NULL;
1871#endif
1872 rettv->v_type = VAR_STRING;
1873}
1874
1875/*
1876 * "browsedir(title, initdir)" function
1877 */
1878 static void
1879f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1880{
1881#ifdef FEAT_BROWSE
1882 char_u *title;
1883 char_u *initdir;
1884 char_u buf[NUMBUFLEN];
1885
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001886 title = tv_get_string_chk(&argvars[0]);
1887 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001888
1889 if (title == NULL || initdir == NULL)
1890 rettv->vval.v_string = NULL;
1891 else
1892 rettv->vval.v_string = do_browse(BROWSE_DIR,
1893 title, NULL, NULL, initdir, NULL, curbuf);
1894#else
1895 rettv->vval.v_string = NULL;
1896#endif
1897 rettv->v_type = VAR_STRING;
1898}
1899
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900/*
1901 * Find a buffer by number or exact name.
1902 */
1903 static buf_T *
1904find_buffer(typval_T *avar)
1905{
1906 buf_T *buf = NULL;
1907
1908 if (avar->v_type == VAR_NUMBER)
1909 buf = buflist_findnr((int)avar->vval.v_number);
1910 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1911 {
1912 buf = buflist_findname_exp(avar->vval.v_string);
1913 if (buf == NULL)
1914 {
1915 /* No full path name match, try a match with a URL or a "nofile"
1916 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001917 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001918 if (buf->b_fname != NULL
1919 && (path_with_url(buf->b_fname)
1920#ifdef FEAT_QUICKFIX
1921 || bt_nofile(buf)
1922#endif
1923 )
1924 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1925 break;
1926 }
1927 }
1928 return buf;
1929}
1930
1931/*
1932 * "bufexists(expr)" function
1933 */
1934 static void
1935f_bufexists(typval_T *argvars, typval_T *rettv)
1936{
1937 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1938}
1939
1940/*
1941 * "buflisted(expr)" function
1942 */
1943 static void
1944f_buflisted(typval_T *argvars, typval_T *rettv)
1945{
1946 buf_T *buf;
1947
1948 buf = find_buffer(&argvars[0]);
1949 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1950}
1951
1952/*
1953 * "bufloaded(expr)" function
1954 */
1955 static void
1956f_bufloaded(typval_T *argvars, typval_T *rettv)
1957{
1958 buf_T *buf;
1959
1960 buf = find_buffer(&argvars[0]);
1961 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1962}
1963
1964 buf_T *
1965buflist_find_by_name(char_u *name, int curtab_only)
1966{
1967 int save_magic;
1968 char_u *save_cpo;
1969 buf_T *buf;
1970
1971 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1972 save_magic = p_magic;
1973 p_magic = TRUE;
1974 save_cpo = p_cpo;
1975 p_cpo = (char_u *)"";
1976
1977 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1978 TRUE, FALSE, curtab_only));
1979
1980 p_magic = save_magic;
1981 p_cpo = save_cpo;
1982 return buf;
1983}
1984
1985/*
1986 * Get buffer by number or pattern.
1987 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001988 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001989tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990{
1991 char_u *name = tv->vval.v_string;
1992 buf_T *buf;
1993
1994 if (tv->v_type == VAR_NUMBER)
1995 return buflist_findnr((int)tv->vval.v_number);
1996 if (tv->v_type != VAR_STRING)
1997 return NULL;
1998 if (name == NULL || *name == NUL)
1999 return curbuf;
2000 if (name[0] == '$' && name[1] == NUL)
2001 return lastbuf;
2002
2003 buf = buflist_find_by_name(name, curtab_only);
2004
2005 /* If not found, try expanding the name, like done for bufexists(). */
2006 if (buf == NULL)
2007 buf = find_buffer(tv);
2008
2009 return buf;
2010}
2011
Bram Moolenaarec9d3002019-01-12 13:50:31 +01002012#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002014 * Get the buffer from "arg" and give an error and return NULL if it is not
2015 * valid.
2016 */
2017 static buf_T *
2018get_buf_arg(typval_T *arg)
2019{
2020 buf_T *buf;
2021
2022 ++emsg_off;
2023 buf = tv_get_buf(arg, FALSE);
2024 --emsg_off;
2025 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002026 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002027 return buf;
2028}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01002029#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002030
2031/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032 * "bufname(expr)" function
2033 */
2034 static void
2035f_bufname(typval_T *argvars, typval_T *rettv)
2036{
2037 buf_T *buf;
2038
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002039 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002041 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 rettv->v_type = VAR_STRING;
2043 if (buf != NULL && buf->b_fname != NULL)
2044 rettv->vval.v_string = vim_strsave(buf->b_fname);
2045 else
2046 rettv->vval.v_string = NULL;
2047 --emsg_off;
2048}
2049
2050/*
2051 * "bufnr(expr)" function
2052 */
2053 static void
2054f_bufnr(typval_T *argvars, typval_T *rettv)
2055{
2056 buf_T *buf;
2057 int error = FALSE;
2058 char_u *name;
2059
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002060 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002062 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 --emsg_off;
2064
2065 /* If the buffer isn't found and the second argument is not zero create a
2066 * new buffer. */
2067 if (buf == NULL
2068 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002069 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002070 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002071 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002072 && !error)
2073 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2074
2075 if (buf != NULL)
2076 rettv->vval.v_number = buf->b_fnum;
2077 else
2078 rettv->vval.v_number = -1;
2079}
2080
2081 static void
2082buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2083{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002084 win_T *wp;
2085 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086 buf_T *buf;
2087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002088 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002090 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002091 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002092 {
2093 ++winnr;
2094 if (wp->w_buffer == buf)
2095 break;
2096 }
2097 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 --emsg_off;
2099}
2100
2101/*
2102 * "bufwinid(nr)" function
2103 */
2104 static void
2105f_bufwinid(typval_T *argvars, typval_T *rettv)
2106{
2107 buf_win_common(argvars, rettv, FALSE);
2108}
2109
2110/*
2111 * "bufwinnr(nr)" function
2112 */
2113 static void
2114f_bufwinnr(typval_T *argvars, typval_T *rettv)
2115{
2116 buf_win_common(argvars, rettv, TRUE);
2117}
2118
2119/*
2120 * "byte2line(byte)" function
2121 */
2122 static void
2123f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2124{
2125#ifndef FEAT_BYTEOFF
2126 rettv->vval.v_number = -1;
2127#else
2128 long boff = 0;
2129
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002130 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002131 if (boff < 0)
2132 rettv->vval.v_number = -1;
2133 else
2134 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2135 (linenr_T)0, &boff);
2136#endif
2137}
2138
2139 static void
2140byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2141{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002142 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002143 char_u *str;
2144 varnumber_T idx;
2145
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002146 str = tv_get_string_chk(&argvars[0]);
2147 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148 rettv->vval.v_number = -1;
2149 if (str == NULL || idx < 0)
2150 return;
2151
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 t = str;
2153 for ( ; idx > 0; idx--)
2154 {
2155 if (*t == NUL) /* EOL reached */
2156 return;
2157 if (enc_utf8 && comp)
2158 t += utf_ptr2len(t);
2159 else
2160 t += (*mb_ptr2len)(t);
2161 }
2162 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002163}
2164
2165/*
2166 * "byteidx()" function
2167 */
2168 static void
2169f_byteidx(typval_T *argvars, typval_T *rettv)
2170{
2171 byteidx(argvars, rettv, FALSE);
2172}
2173
2174/*
2175 * "byteidxcomp()" function
2176 */
2177 static void
2178f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2179{
2180 byteidx(argvars, rettv, TRUE);
2181}
2182
2183/*
2184 * "call(func, arglist [, dict])" function
2185 */
2186 static void
2187f_call(typval_T *argvars, typval_T *rettv)
2188{
2189 char_u *func;
2190 partial_T *partial = NULL;
2191 dict_T *selfdict = NULL;
2192
2193 if (argvars[1].v_type != VAR_LIST)
2194 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002195 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196 return;
2197 }
2198 if (argvars[1].vval.v_list == NULL)
2199 return;
2200
2201 if (argvars[0].v_type == VAR_FUNC)
2202 func = argvars[0].vval.v_string;
2203 else if (argvars[0].v_type == VAR_PARTIAL)
2204 {
2205 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002206 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 }
2208 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002209 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210 if (*func == NUL)
2211 return; /* type error or empty name */
2212
2213 if (argvars[2].v_type != VAR_UNKNOWN)
2214 {
2215 if (argvars[2].v_type != VAR_DICT)
2216 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002217 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002218 return;
2219 }
2220 selfdict = argvars[2].vval.v_dict;
2221 }
2222
2223 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2224}
2225
2226#ifdef FEAT_FLOAT
2227/*
2228 * "ceil({float})" function
2229 */
2230 static void
2231f_ceil(typval_T *argvars, typval_T *rettv)
2232{
2233 float_T f = 0.0;
2234
2235 rettv->v_type = VAR_FLOAT;
2236 if (get_float_arg(argvars, &f) == OK)
2237 rettv->vval.v_float = ceil(f);
2238 else
2239 rettv->vval.v_float = 0.0;
2240}
2241#endif
2242
2243#ifdef FEAT_JOB_CHANNEL
2244/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002245 * "ch_canread()" function
2246 */
2247 static void
2248f_ch_canread(typval_T *argvars, typval_T *rettv)
2249{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002250 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002251
2252 rettv->vval.v_number = 0;
2253 if (channel != NULL)
2254 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2255 || channel_has_readahead(channel, PART_OUT)
2256 || channel_has_readahead(channel, PART_ERR);
2257}
2258
2259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002260 * "ch_close()" function
2261 */
2262 static void
2263f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2264{
2265 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2266
2267 if (channel != NULL)
2268 {
2269 channel_close(channel, FALSE);
2270 channel_clear(channel);
2271 }
2272}
2273
2274/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002275 * "ch_close()" function
2276 */
2277 static void
2278f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2279{
2280 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2281
2282 if (channel != NULL)
2283 channel_close_in(channel);
2284}
2285
2286/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287 * "ch_getbufnr()" function
2288 */
2289 static void
2290f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2291{
2292 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2293
2294 rettv->vval.v_number = -1;
2295 if (channel != NULL)
2296 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002297 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298 int part;
2299
2300 if (STRCMP(what, "err") == 0)
2301 part = PART_ERR;
2302 else if (STRCMP(what, "out") == 0)
2303 part = PART_OUT;
2304 else if (STRCMP(what, "in") == 0)
2305 part = PART_IN;
2306 else
2307 part = PART_SOCK;
2308 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2309 rettv->vval.v_number =
2310 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2311 }
2312}
2313
2314/*
2315 * "ch_getjob()" function
2316 */
2317 static void
2318f_ch_getjob(typval_T *argvars, typval_T *rettv)
2319{
2320 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2321
2322 if (channel != NULL)
2323 {
2324 rettv->v_type = VAR_JOB;
2325 rettv->vval.v_job = channel->ch_job;
2326 if (channel->ch_job != NULL)
2327 ++channel->ch_job->jv_refcount;
2328 }
2329}
2330
2331/*
2332 * "ch_info()" function
2333 */
2334 static void
2335f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2336{
2337 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2338
2339 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2340 channel_info(channel, rettv->vval.v_dict);
2341}
2342
2343/*
2344 * "ch_log()" function
2345 */
2346 static void
2347f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2348{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002349 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002350 channel_T *channel = NULL;
2351
2352 if (argvars[1].v_type != VAR_UNKNOWN)
2353 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2354
Bram Moolenaard5359b22018-04-05 22:44:39 +02002355 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356}
2357
2358/*
2359 * "ch_logfile()" function
2360 */
2361 static void
2362f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2363{
2364 char_u *fname;
2365 char_u *opt = (char_u *)"";
2366 char_u buf[NUMBUFLEN];
2367
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002368 /* Don't open a file in restricted mode. */
2369 if (check_restricted() || check_secure())
2370 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002371 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002372 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002373 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002374 ch_logfile(fname, opt);
2375}
2376
2377/*
2378 * "ch_open()" function
2379 */
2380 static void
2381f_ch_open(typval_T *argvars, typval_T *rettv)
2382{
2383 rettv->v_type = VAR_CHANNEL;
2384 if (check_restricted() || check_secure())
2385 return;
2386 rettv->vval.v_channel = channel_open_func(argvars);
2387}
2388
2389/*
2390 * "ch_read()" function
2391 */
2392 static void
2393f_ch_read(typval_T *argvars, typval_T *rettv)
2394{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002395 common_channel_read(argvars, rettv, FALSE, FALSE);
2396}
2397
2398/*
2399 * "ch_readblob()" function
2400 */
2401 static void
2402f_ch_readblob(typval_T *argvars, typval_T *rettv)
2403{
2404 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405}
2406
2407/*
2408 * "ch_readraw()" function
2409 */
2410 static void
2411f_ch_readraw(typval_T *argvars, typval_T *rettv)
2412{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002413 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414}
2415
2416/*
2417 * "ch_evalexpr()" function
2418 */
2419 static void
2420f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2421{
2422 ch_expr_common(argvars, rettv, TRUE);
2423}
2424
2425/*
2426 * "ch_sendexpr()" function
2427 */
2428 static void
2429f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2430{
2431 ch_expr_common(argvars, rettv, FALSE);
2432}
2433
2434/*
2435 * "ch_evalraw()" function
2436 */
2437 static void
2438f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2439{
2440 ch_raw_common(argvars, rettv, TRUE);
2441}
2442
2443/*
2444 * "ch_sendraw()" function
2445 */
2446 static void
2447f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2448{
2449 ch_raw_common(argvars, rettv, FALSE);
2450}
2451
2452/*
2453 * "ch_setoptions()" function
2454 */
2455 static void
2456f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2457{
2458 channel_T *channel;
2459 jobopt_T opt;
2460
2461 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2462 if (channel == NULL)
2463 return;
2464 clear_job_options(&opt);
2465 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002466 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467 channel_set_options(channel, &opt);
2468 free_job_options(&opt);
2469}
2470
2471/*
2472 * "ch_status()" function
2473 */
2474 static void
2475f_ch_status(typval_T *argvars, typval_T *rettv)
2476{
2477 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002478 jobopt_T opt;
2479 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002480
2481 /* return an empty string by default */
2482 rettv->v_type = VAR_STRING;
2483 rettv->vval.v_string = NULL;
2484
2485 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002486
2487 if (argvars[1].v_type != VAR_UNKNOWN)
2488 {
2489 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002490 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002491 && (opt.jo_set & JO_PART))
2492 part = opt.jo_part;
2493 }
2494
2495 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496}
2497#endif
2498
2499/*
2500 * "changenr()" function
2501 */
2502 static void
2503f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2504{
2505 rettv->vval.v_number = curbuf->b_u_seq_cur;
2506}
2507
2508/*
2509 * "char2nr(string)" function
2510 */
2511 static void
2512f_char2nr(typval_T *argvars, typval_T *rettv)
2513{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002514 if (has_mbyte)
2515 {
2516 int utf8 = 0;
2517
2518 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002519 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002520
2521 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002522 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002523 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002524 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002525 }
2526 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002527 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528}
2529
2530/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002531 * "chdir(dir)" function
2532 */
2533 static void
2534f_chdir(typval_T *argvars, typval_T *rettv)
2535{
2536 char_u *cwd;
2537 cdscope_T scope = CDSCOPE_GLOBAL;
2538
2539 rettv->v_type = VAR_STRING;
2540 rettv->vval.v_string = NULL;
2541
2542 if (argvars[0].v_type != VAR_STRING)
2543 return;
2544
2545 // Return the current directory
2546 cwd = alloc(MAXPATHL);
2547 if (cwd != NULL)
2548 {
2549 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2550 {
2551#ifdef BACKSLASH_IN_FILENAME
2552 slash_adjust(cwd);
2553#endif
2554 rettv->vval.v_string = vim_strsave(cwd);
2555 }
2556 vim_free(cwd);
2557 }
2558
2559 if (curwin->w_localdir != NULL)
2560 scope = CDSCOPE_WINDOW;
2561 else if (curtab->tp_localdir != NULL)
2562 scope = CDSCOPE_TABPAGE;
2563
2564 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2565 // Directory change failed
2566 VIM_CLEAR(rettv->vval.v_string);
2567}
2568
2569/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002570 * "cindent(lnum)" function
2571 */
2572 static void
2573f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2574{
2575#ifdef FEAT_CINDENT
2576 pos_T pos;
2577 linenr_T lnum;
2578
2579 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002580 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2582 {
2583 curwin->w_cursor.lnum = lnum;
2584 rettv->vval.v_number = get_c_indent();
2585 curwin->w_cursor = pos;
2586 }
2587 else
2588#endif
2589 rettv->vval.v_number = -1;
2590}
2591
Bram Moolenaaraff74912019-03-30 18:11:49 +01002592 static win_T *
2593get_optional_window(typval_T *argvars, int idx)
2594{
2595 win_T *win = curwin;
2596
2597 if (argvars[idx].v_type != VAR_UNKNOWN)
2598 {
2599 win = find_win_by_nr_or_id(&argvars[idx]);
2600 if (win == NULL)
2601 {
2602 emsg(_(e_invalwindow));
2603 return NULL;
2604 }
2605 }
2606 return win;
2607}
2608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609/*
2610 * "clearmatches()" function
2611 */
2612 static void
2613f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2614{
2615#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002616 win_T *win = get_optional_window(argvars, 0);
2617
2618 if (win != NULL)
2619 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620#endif
2621}
2622
2623/*
2624 * "col(string)" function
2625 */
2626 static void
2627f_col(typval_T *argvars, typval_T *rettv)
2628{
2629 colnr_T col = 0;
2630 pos_T *fp;
2631 int fnum = curbuf->b_fnum;
2632
2633 fp = var2fpos(&argvars[0], FALSE, &fnum);
2634 if (fp != NULL && fnum == curbuf->b_fnum)
2635 {
2636 if (fp->col == MAXCOL)
2637 {
2638 /* '> can be MAXCOL, get the length of the line then */
2639 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2640 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2641 else
2642 col = MAXCOL;
2643 }
2644 else
2645 {
2646 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002647 /* col(".") when the cursor is on the NUL at the end of the line
2648 * because of "coladd" can be seen as an extra column. */
2649 if (virtual_active() && fp == &curwin->w_cursor)
2650 {
2651 char_u *p = ml_get_cursor();
2652
2653 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2654 curwin->w_virtcol - curwin->w_cursor.coladd))
2655 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 int l;
2657
2658 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2659 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002660 }
2661 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002662 }
2663 }
2664 rettv->vval.v_number = col;
2665}
2666
2667#if defined(FEAT_INS_EXPAND)
2668/*
2669 * "complete()" function
2670 */
2671 static void
2672f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2673{
2674 int startcol;
2675
2676 if ((State & INSERT) == 0)
2677 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002678 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002679 return;
2680 }
2681
2682 /* Check for undo allowed here, because if something was already inserted
2683 * the line was already saved for undo and this check isn't done. */
2684 if (!undo_allowed())
2685 return;
2686
2687 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2688 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002689 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690 return;
2691 }
2692
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002693 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 if (startcol <= 0)
2695 return;
2696
2697 set_completion(startcol - 1, argvars[1].vval.v_list);
2698}
2699
2700/*
2701 * "complete_add()" function
2702 */
2703 static void
2704f_complete_add(typval_T *argvars, typval_T *rettv)
2705{
2706 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2707}
2708
2709/*
2710 * "complete_check()" function
2711 */
2712 static void
2713f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2714{
2715 int saved = RedrawingDisabled;
2716
2717 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002718 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002719 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002720 RedrawingDisabled = saved;
2721}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002722
2723/*
2724 * "complete_info()" function
2725 */
2726 static void
2727f_complete_info(typval_T *argvars, typval_T *rettv)
2728{
2729 list_T *what_list = NULL;
2730
2731 if (rettv_dict_alloc(rettv) != OK)
2732 return;
2733
2734 if (argvars[0].v_type != VAR_UNKNOWN)
2735 {
2736 if (argvars[0].v_type != VAR_LIST)
2737 {
2738 emsg(_(e_listreq));
2739 return;
2740 }
2741 what_list = argvars[0].vval.v_list;
2742 }
2743 get_complete_info(what_list, rettv->vval.v_dict);
2744}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002745#endif
2746
2747/*
2748 * "confirm(message, buttons[, default [, type]])" function
2749 */
2750 static void
2751f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2752{
2753#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2754 char_u *message;
2755 char_u *buttons = NULL;
2756 char_u buf[NUMBUFLEN];
2757 char_u buf2[NUMBUFLEN];
2758 int def = 1;
2759 int type = VIM_GENERIC;
2760 char_u *typestr;
2761 int error = FALSE;
2762
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002763 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002764 if (message == NULL)
2765 error = TRUE;
2766 if (argvars[1].v_type != VAR_UNKNOWN)
2767 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002768 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002769 if (buttons == NULL)
2770 error = TRUE;
2771 if (argvars[2].v_type != VAR_UNKNOWN)
2772 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002773 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002774 if (argvars[3].v_type != VAR_UNKNOWN)
2775 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002776 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002777 if (typestr == NULL)
2778 error = TRUE;
2779 else
2780 {
2781 switch (TOUPPER_ASC(*typestr))
2782 {
2783 case 'E': type = VIM_ERROR; break;
2784 case 'Q': type = VIM_QUESTION; break;
2785 case 'I': type = VIM_INFO; break;
2786 case 'W': type = VIM_WARNING; break;
2787 case 'G': type = VIM_GENERIC; break;
2788 }
2789 }
2790 }
2791 }
2792 }
2793
2794 if (buttons == NULL || *buttons == NUL)
2795 buttons = (char_u *)_("&Ok");
2796
2797 if (!error)
2798 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2799 def, NULL, FALSE);
2800#endif
2801}
2802
2803/*
2804 * "copy()" function
2805 */
2806 static void
2807f_copy(typval_T *argvars, typval_T *rettv)
2808{
2809 item_copy(&argvars[0], rettv, FALSE, 0);
2810}
2811
2812#ifdef FEAT_FLOAT
2813/*
2814 * "cos()" function
2815 */
2816 static void
2817f_cos(typval_T *argvars, typval_T *rettv)
2818{
2819 float_T f = 0.0;
2820
2821 rettv->v_type = VAR_FLOAT;
2822 if (get_float_arg(argvars, &f) == OK)
2823 rettv->vval.v_float = cos(f);
2824 else
2825 rettv->vval.v_float = 0.0;
2826}
2827
2828/*
2829 * "cosh()" function
2830 */
2831 static void
2832f_cosh(typval_T *argvars, typval_T *rettv)
2833{
2834 float_T f = 0.0;
2835
2836 rettv->v_type = VAR_FLOAT;
2837 if (get_float_arg(argvars, &f) == OK)
2838 rettv->vval.v_float = cosh(f);
2839 else
2840 rettv->vval.v_float = 0.0;
2841}
2842#endif
2843
2844/*
2845 * "count()" function
2846 */
2847 static void
2848f_count(typval_T *argvars, typval_T *rettv)
2849{
2850 long n = 0;
2851 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002852 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002853
Bram Moolenaar9966b212017-07-28 16:46:57 +02002854 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002855 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002856
2857 if (argvars[0].v_type == VAR_STRING)
2858 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002859 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002860 char_u *p = argvars[0].vval.v_string;
2861 char_u *next;
2862
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002863 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002864 {
2865 if (ic)
2866 {
2867 size_t len = STRLEN(expr);
2868
2869 while (*p != NUL)
2870 {
2871 if (MB_STRNICMP(p, expr, len) == 0)
2872 {
2873 ++n;
2874 p += len;
2875 }
2876 else
2877 MB_PTR_ADV(p);
2878 }
2879 }
2880 else
2881 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2882 != NULL)
2883 {
2884 ++n;
2885 p = next + STRLEN(expr);
2886 }
2887 }
2888
2889 }
2890 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002891 {
2892 listitem_T *li;
2893 list_T *l;
2894 long idx;
2895
2896 if ((l = argvars[0].vval.v_list) != NULL)
2897 {
2898 li = l->lv_first;
2899 if (argvars[2].v_type != VAR_UNKNOWN)
2900 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002901 if (argvars[3].v_type != VAR_UNKNOWN)
2902 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002903 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002904 if (!error)
2905 {
2906 li = list_find(l, idx);
2907 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002908 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002909 }
2910 }
2911 if (error)
2912 li = NULL;
2913 }
2914
2915 for ( ; li != NULL; li = li->li_next)
2916 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2917 ++n;
2918 }
2919 }
2920 else if (argvars[0].v_type == VAR_DICT)
2921 {
2922 int todo;
2923 dict_T *d;
2924 hashitem_T *hi;
2925
2926 if ((d = argvars[0].vval.v_dict) != NULL)
2927 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928 if (argvars[2].v_type != VAR_UNKNOWN)
2929 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002930 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002931 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002932 }
2933
2934 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2935 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2936 {
2937 if (!HASHITEM_EMPTY(hi))
2938 {
2939 --todo;
2940 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2941 ++n;
2942 }
2943 }
2944 }
2945 }
2946 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002947 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002948 rettv->vval.v_number = n;
2949}
2950
2951/*
2952 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2953 *
2954 * Checks the existence of a cscope connection.
2955 */
2956 static void
2957f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2958{
2959#ifdef FEAT_CSCOPE
2960 int num = 0;
2961 char_u *dbpath = NULL;
2962 char_u *prepend = NULL;
2963 char_u buf[NUMBUFLEN];
2964
2965 if (argvars[0].v_type != VAR_UNKNOWN
2966 && argvars[1].v_type != VAR_UNKNOWN)
2967 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002968 num = (int)tv_get_number(&argvars[0]);
2969 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002970 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002971 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972 }
2973
2974 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2975#endif
2976}
2977
2978/*
2979 * "cursor(lnum, col)" function, or
2980 * "cursor(list)"
2981 *
2982 * Moves the cursor to the specified line and column.
2983 * Returns 0 when the position could be set, -1 otherwise.
2984 */
2985 static void
2986f_cursor(typval_T *argvars, typval_T *rettv)
2987{
2988 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002990 int set_curswant = TRUE;
2991
2992 rettv->vval.v_number = -1;
2993 if (argvars[1].v_type == VAR_UNKNOWN)
2994 {
2995 pos_T pos;
2996 colnr_T curswant = -1;
2997
2998 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2999 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003000 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003001 return;
3002 }
3003 line = pos.lnum;
3004 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003005 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006 if (curswant >= 0)
3007 {
3008 curwin->w_curswant = curswant - 1;
3009 set_curswant = FALSE;
3010 }
3011 }
3012 else
3013 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003014 line = tv_get_lnum(argvars);
3015 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003017 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003018 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003019 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003020 return; /* type error; errmsg already given */
3021 if (line > 0)
3022 curwin->w_cursor.lnum = line;
3023 if (col > 0)
3024 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003025 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003026
3027 /* Make sure the cursor is in a valid position. */
3028 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029 /* Correct cursor for multi-byte character. */
3030 if (has_mbyte)
3031 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003032
3033 curwin->w_set_curswant = set_curswant;
3034 rettv->vval.v_number = 0;
3035}
3036
Bram Moolenaar4f974752019-02-17 17:44:42 +01003037#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02003038/*
3039 * "debugbreak()" function
3040 */
3041 static void
3042f_debugbreak(typval_T *argvars, typval_T *rettv)
3043{
3044 int pid;
3045
3046 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003047 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02003048 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003049 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02003050 else
3051 {
3052 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
3053
3054 if (hProcess != NULL)
3055 {
3056 DebugBreakProcess(hProcess);
3057 CloseHandle(hProcess);
3058 rettv->vval.v_number = OK;
3059 }
3060 }
3061}
3062#endif
3063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003064/*
3065 * "deepcopy()" function
3066 */
3067 static void
3068f_deepcopy(typval_T *argvars, typval_T *rettv)
3069{
3070 int noref = 0;
3071 int copyID;
3072
3073 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003074 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003076 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 else
3078 {
3079 copyID = get_copyID();
3080 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
3081 }
3082}
3083
3084/*
3085 * "delete()" function
3086 */
3087 static void
3088f_delete(typval_T *argvars, typval_T *rettv)
3089{
3090 char_u nbuf[NUMBUFLEN];
3091 char_u *name;
3092 char_u *flags;
3093
3094 rettv->vval.v_number = -1;
3095 if (check_restricted() || check_secure())
3096 return;
3097
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003098 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 if (name == NULL || *name == NUL)
3100 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003101 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102 return;
3103 }
3104
3105 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003106 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 else
3108 flags = (char_u *)"";
3109
3110 if (*flags == NUL)
3111 /* delete a file */
3112 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
3113 else if (STRCMP(flags, "d") == 0)
3114 /* delete an empty directory */
3115 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
3116 else if (STRCMP(flags, "rf") == 0)
3117 /* delete a directory recursively */
3118 rettv->vval.v_number = delete_recursive(name);
3119 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003120 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003121}
3122
3123/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02003124 * "deletebufline()" function
3125 */
3126 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02003127f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02003128{
3129 buf_T *buf;
3130 linenr_T first, last;
3131 linenr_T lnum;
3132 long count;
3133 int is_curbuf;
3134 buf_T *curbuf_save = NULL;
3135 win_T *curwin_save = NULL;
3136 tabpage_T *tp;
3137 win_T *wp;
3138
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003139 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003140 if (buf == NULL)
3141 {
3142 rettv->vval.v_number = 1; /* FAIL */
3143 return;
3144 }
3145 is_curbuf = buf == curbuf;
3146
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003147 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003148 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003149 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003150 else
3151 last = first;
3152
3153 if (buf->b_ml.ml_mfp == NULL || first < 1
3154 || first > buf->b_ml.ml_line_count || last < first)
3155 {
3156 rettv->vval.v_number = 1; /* FAIL */
3157 return;
3158 }
3159
3160 if (!is_curbuf)
3161 {
3162 curbuf_save = curbuf;
3163 curwin_save = curwin;
3164 curbuf = buf;
3165 find_win_for_curbuf();
3166 }
3167 if (last > curbuf->b_ml.ml_line_count)
3168 last = curbuf->b_ml.ml_line_count;
3169 count = last - first + 1;
3170
3171 // When coming here from Insert mode, sync undo, so that this can be
3172 // undone separately from what was previously inserted.
3173 if (u_sync_once == 2)
3174 {
3175 u_sync_once = 1; // notify that u_sync() was called
3176 u_sync(TRUE);
3177 }
3178
3179 if (u_save(first - 1, last + 1) == FAIL)
3180 {
3181 rettv->vval.v_number = 1; /* FAIL */
3182 return;
3183 }
3184
3185 for (lnum = first; lnum <= last; ++lnum)
3186 ml_delete(first, TRUE);
3187
3188 FOR_ALL_TAB_WINDOWS(tp, wp)
3189 if (wp->w_buffer == buf)
3190 {
3191 if (wp->w_cursor.lnum > last)
3192 wp->w_cursor.lnum -= count;
3193 else if (wp->w_cursor.lnum> first)
3194 wp->w_cursor.lnum = first;
3195 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3196 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3197 }
3198 check_cursor_col();
3199 deleted_lines_mark(first, count);
3200
3201 if (!is_curbuf)
3202 {
3203 curbuf = curbuf_save;
3204 curwin = curwin_save;
3205 }
3206}
3207
3208/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003209 * "did_filetype()" function
3210 */
3211 static void
3212f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3213{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003214 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215}
3216
3217/*
3218 * "diff_filler()" function
3219 */
3220 static void
3221f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3222{
3223#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003224 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003225#endif
3226}
3227
3228/*
3229 * "diff_hlID()" function
3230 */
3231 static void
3232f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3233{
3234#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003235 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003236 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003237 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 static int fnum = 0;
3239 static int change_start = 0;
3240 static int change_end = 0;
3241 static hlf_T hlID = (hlf_T)0;
3242 int filler_lines;
3243 int col;
3244
3245 if (lnum < 0) /* ignore type error in {lnum} arg */
3246 lnum = 0;
3247 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003248 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003249 || fnum != curbuf->b_fnum)
3250 {
3251 /* New line, buffer, change: need to get the values. */
3252 filler_lines = diff_check(curwin, lnum);
3253 if (filler_lines < 0)
3254 {
3255 if (filler_lines == -1)
3256 {
3257 change_start = MAXCOL;
3258 change_end = -1;
3259 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3260 hlID = HLF_ADD; /* added line */
3261 else
3262 hlID = HLF_CHD; /* changed line */
3263 }
3264 else
3265 hlID = HLF_ADD; /* added line */
3266 }
3267 else
3268 hlID = (hlf_T)0;
3269 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003270 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 fnum = curbuf->b_fnum;
3272 }
3273
3274 if (hlID == HLF_CHD || hlID == HLF_TXD)
3275 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003276 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003277 if (col >= change_start && col <= change_end)
3278 hlID = HLF_TXD; /* changed text */
3279 else
3280 hlID = HLF_CHD; /* changed line */
3281 }
3282 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3283#endif
3284}
3285
3286/*
3287 * "empty({expr})" function
3288 */
3289 static void
3290f_empty(typval_T *argvars, typval_T *rettv)
3291{
3292 int n = FALSE;
3293
3294 switch (argvars[0].v_type)
3295 {
3296 case VAR_STRING:
3297 case VAR_FUNC:
3298 n = argvars[0].vval.v_string == NULL
3299 || *argvars[0].vval.v_string == NUL;
3300 break;
3301 case VAR_PARTIAL:
3302 n = FALSE;
3303 break;
3304 case VAR_NUMBER:
3305 n = argvars[0].vval.v_number == 0;
3306 break;
3307 case VAR_FLOAT:
3308#ifdef FEAT_FLOAT
3309 n = argvars[0].vval.v_float == 0.0;
3310 break;
3311#endif
3312 case VAR_LIST:
3313 n = argvars[0].vval.v_list == NULL
3314 || argvars[0].vval.v_list->lv_first == NULL;
3315 break;
3316 case VAR_DICT:
3317 n = argvars[0].vval.v_dict == NULL
3318 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3319 break;
3320 case VAR_SPECIAL:
3321 n = argvars[0].vval.v_number != VVAL_TRUE;
3322 break;
3323
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003324 case VAR_BLOB:
3325 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003326 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3327 break;
3328
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003329 case VAR_JOB:
3330#ifdef FEAT_JOB_CHANNEL
3331 n = argvars[0].vval.v_job == NULL
3332 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3333 break;
3334#endif
3335 case VAR_CHANNEL:
3336#ifdef FEAT_JOB_CHANNEL
3337 n = argvars[0].vval.v_channel == NULL
3338 || !channel_is_open(argvars[0].vval.v_channel);
3339 break;
3340#endif
3341 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003342 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003343 n = TRUE;
3344 break;
3345 }
3346
3347 rettv->vval.v_number = n;
3348}
3349
3350/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003351 * "environ()" function
3352 */
3353 static void
3354f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3355{
3356#if !defined(AMIGA)
3357 int i = 0;
3358 char_u *entry, *value;
3359# ifdef MSWIN
3360 extern wchar_t **_wenviron;
3361# else
3362 extern char **environ;
3363# endif
3364
3365 if (rettv_dict_alloc(rettv) != OK)
3366 return;
3367
3368# ifdef MSWIN
3369 if (*_wenviron == NULL)
3370 return;
3371# else
3372 if (*environ == NULL)
3373 return;
3374# endif
3375
3376 for (i = 0; ; ++i)
3377 {
3378# ifdef MSWIN
3379 short_u *p;
3380
3381 if ((p = (short_u *)_wenviron[i]) == NULL)
3382 return;
3383 entry = utf16_to_enc(p, NULL);
3384# else
3385 if ((entry = (char_u *)environ[i]) == NULL)
3386 return;
3387 entry = vim_strsave(entry);
3388# endif
3389 if (entry == NULL) // out of memory
3390 return;
3391 if ((value = vim_strchr(entry, '=')) == NULL)
3392 {
3393 vim_free(entry);
3394 continue;
3395 }
3396 *value++ = NUL;
3397 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3398 vim_free(entry);
3399 }
3400#endif
3401}
3402
3403/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003404 * "escape({string}, {chars})" function
3405 */
3406 static void
3407f_escape(typval_T *argvars, typval_T *rettv)
3408{
3409 char_u buf[NUMBUFLEN];
3410
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003411 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3412 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003413 rettv->v_type = VAR_STRING;
3414}
3415
3416/*
3417 * "eval()" function
3418 */
3419 static void
3420f_eval(typval_T *argvars, typval_T *rettv)
3421{
3422 char_u *s, *p;
3423
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003424 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 if (s != NULL)
3426 s = skipwhite(s);
3427
3428 p = s;
3429 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3430 {
3431 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003432 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003433 need_clr_eos = FALSE;
3434 rettv->v_type = VAR_NUMBER;
3435 rettv->vval.v_number = 0;
3436 }
3437 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003438 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439}
3440
3441/*
3442 * "eventhandler()" function
3443 */
3444 static void
3445f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3446{
3447 rettv->vval.v_number = vgetc_busy;
3448}
3449
3450/*
3451 * "executable()" function
3452 */
3453 static void
3454f_executable(typval_T *argvars, typval_T *rettv)
3455{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003456 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457
3458 /* Check in $PATH and also check directly if there is a directory name. */
3459 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3460 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3461}
3462
3463static garray_T redir_execute_ga;
3464
3465/*
3466 * Append "value[value_len]" to the execute() output.
3467 */
3468 void
3469execute_redir_str(char_u *value, int value_len)
3470{
3471 int len;
3472
3473 if (value_len == -1)
3474 len = (int)STRLEN(value); /* Append the entire string */
3475 else
3476 len = value_len; /* Append only "value_len" characters */
3477 if (ga_grow(&redir_execute_ga, len) == OK)
3478 {
3479 mch_memmove((char *)redir_execute_ga.ga_data
3480 + redir_execute_ga.ga_len, value, len);
3481 redir_execute_ga.ga_len += len;
3482 }
3483}
3484
3485/*
3486 * Get next line from a list.
3487 * Called by do_cmdline() to get the next line.
3488 * Returns allocated string, or NULL for end of function.
3489 */
3490
3491 static char_u *
3492get_list_line(
3493 int c UNUSED,
3494 void *cookie,
3495 int indent UNUSED)
3496{
3497 listitem_T **p = (listitem_T **)cookie;
3498 listitem_T *item = *p;
3499 char_u buf[NUMBUFLEN];
3500 char_u *s;
3501
3502 if (item == NULL)
3503 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003504 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 *p = item->li_next;
3506 return s == NULL ? NULL : vim_strsave(s);
3507}
3508
3509/*
3510 * "execute()" function
3511 */
3512 static void
3513f_execute(typval_T *argvars, typval_T *rettv)
3514{
3515 char_u *cmd = NULL;
3516 list_T *list = NULL;
3517 int save_msg_silent = msg_silent;
3518 int save_emsg_silent = emsg_silent;
3519 int save_emsg_noredir = emsg_noredir;
3520 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003521 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003523 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003524 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003525
3526 rettv->vval.v_string = NULL;
3527 rettv->v_type = VAR_STRING;
3528
3529 if (argvars[0].v_type == VAR_LIST)
3530 {
3531 list = argvars[0].vval.v_list;
3532 if (list == NULL || list->lv_first == NULL)
3533 /* empty list, no commands, empty output */
3534 return;
3535 ++list->lv_refcount;
3536 }
3537 else
3538 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003539 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003540 if (cmd == NULL)
3541 return;
3542 }
3543
3544 if (argvars[1].v_type != VAR_UNKNOWN)
3545 {
3546 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003547 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003548
3549 if (s == NULL)
3550 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003551 if (*s == NUL)
3552 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003553 if (STRNCMP(s, "silent", 6) == 0)
3554 ++msg_silent;
3555 if (STRCMP(s, "silent!") == 0)
3556 {
3557 emsg_silent = TRUE;
3558 emsg_noredir = TRUE;
3559 }
3560 }
3561 else
3562 ++msg_silent;
3563
3564 if (redir_execute)
3565 save_ga = redir_execute_ga;
3566 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3567 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003568 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003569 if (!echo_output)
3570 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003571
3572 if (cmd != NULL)
3573 do_cmdline_cmd(cmd);
3574 else
3575 {
3576 listitem_T *item = list->lv_first;
3577
3578 do_cmdline(NULL, get_list_line, (void *)&item,
3579 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3580 --list->lv_refcount;
3581 }
3582
Bram Moolenaard297f352017-01-29 20:31:21 +01003583 /* Need to append a NUL to the result. */
3584 if (ga_grow(&redir_execute_ga, 1) == OK)
3585 {
3586 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3587 rettv->vval.v_string = redir_execute_ga.ga_data;
3588 }
3589 else
3590 {
3591 ga_clear(&redir_execute_ga);
3592 rettv->vval.v_string = NULL;
3593 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003594 msg_silent = save_msg_silent;
3595 emsg_silent = save_emsg_silent;
3596 emsg_noredir = save_emsg_noredir;
3597
3598 redir_execute = save_redir_execute;
3599 if (redir_execute)
3600 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003601 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003603 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003604 if (echo_output)
3605 // When not working silently: put it in column zero. A following
3606 // "echon" will overwrite the message, unavoidably.
3607 msg_col = 0;
3608 else
3609 // When working silently: Put it back where it was, since nothing
3610 // should have been written.
3611 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003612}
3613
3614/*
3615 * "exepath()" function
3616 */
3617 static void
3618f_exepath(typval_T *argvars, typval_T *rettv)
3619{
3620 char_u *p = NULL;
3621
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003622 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003623 rettv->v_type = VAR_STRING;
3624 rettv->vval.v_string = p;
3625}
3626
3627/*
3628 * "exists()" function
3629 */
3630 static void
3631f_exists(typval_T *argvars, typval_T *rettv)
3632{
3633 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003636 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 if (*p == '$') /* environment variable */
3638 {
3639 /* first try "normal" environment variables (fast) */
3640 if (mch_getenv(p + 1) != NULL)
3641 n = TRUE;
3642 else
3643 {
3644 /* try expanding things like $VIM and ${HOME} */
3645 p = expand_env_save(p);
3646 if (p != NULL && *p != '$')
3647 n = TRUE;
3648 vim_free(p);
3649 }
3650 }
3651 else if (*p == '&' || *p == '+') /* option */
3652 {
3653 n = (get_option_tv(&p, NULL, TRUE) == OK);
3654 if (*skipwhite(p) != NUL)
3655 n = FALSE; /* trailing garbage */
3656 }
3657 else if (*p == '*') /* internal or user defined function */
3658 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003659 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003660 }
3661 else if (*p == ':')
3662 {
3663 n = cmd_exists(p + 1);
3664 }
3665 else if (*p == '#')
3666 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003667 if (p[1] == '#')
3668 n = autocmd_supported(p + 2);
3669 else
3670 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003671 }
3672 else /* internal variable */
3673 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003674 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675 }
3676
3677 rettv->vval.v_number = n;
3678}
3679
3680#ifdef FEAT_FLOAT
3681/*
3682 * "exp()" function
3683 */
3684 static void
3685f_exp(typval_T *argvars, typval_T *rettv)
3686{
3687 float_T f = 0.0;
3688
3689 rettv->v_type = VAR_FLOAT;
3690 if (get_float_arg(argvars, &f) == OK)
3691 rettv->vval.v_float = exp(f);
3692 else
3693 rettv->vval.v_float = 0.0;
3694}
3695#endif
3696
3697/*
3698 * "expand()" function
3699 */
3700 static void
3701f_expand(typval_T *argvars, typval_T *rettv)
3702{
3703 char_u *s;
3704 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003705 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003706 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3707 expand_T xpc;
3708 int error = FALSE;
3709 char_u *result;
3710
3711 rettv->v_type = VAR_STRING;
3712 if (argvars[1].v_type != VAR_UNKNOWN
3713 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003714 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003716 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003717
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003718 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003719 if (*s == '%' || *s == '#' || *s == '<')
3720 {
3721 ++emsg_off;
3722 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3723 --emsg_off;
3724 if (rettv->v_type == VAR_LIST)
3725 {
3726 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3727 list_append_string(rettv->vval.v_list, result, -1);
3728 else
3729 vim_free(result);
3730 }
3731 else
3732 rettv->vval.v_string = result;
3733 }
3734 else
3735 {
3736 /* When the optional second argument is non-zero, don't remove matches
3737 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3738 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003739 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 options |= WILD_KEEP_ALL;
3741 if (!error)
3742 {
3743 ExpandInit(&xpc);
3744 xpc.xp_context = EXPAND_FILES;
3745 if (p_wic)
3746 options += WILD_ICASE;
3747 if (rettv->v_type == VAR_STRING)
3748 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3749 options, WILD_ALL);
3750 else if (rettv_list_alloc(rettv) != FAIL)
3751 {
3752 int i;
3753
3754 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3755 for (i = 0; i < xpc.xp_numfiles; i++)
3756 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3757 ExpandCleanup(&xpc);
3758 }
3759 }
3760 else
3761 rettv->vval.v_string = NULL;
3762 }
3763}
3764
3765/*
3766 * "extend(list, list [, idx])" function
3767 * "extend(dict, dict [, action])" function
3768 */
3769 static void
3770f_extend(typval_T *argvars, typval_T *rettv)
3771{
3772 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3773
3774 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3775 {
3776 list_T *l1, *l2;
3777 listitem_T *item;
3778 long before;
3779 int error = FALSE;
3780
3781 l1 = argvars[0].vval.v_list;
3782 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003783 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003784 && l2 != NULL)
3785 {
3786 if (argvars[2].v_type != VAR_UNKNOWN)
3787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003788 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003789 if (error)
3790 return; /* type error; errmsg already given */
3791
3792 if (before == l1->lv_len)
3793 item = NULL;
3794 else
3795 {
3796 item = list_find(l1, before);
3797 if (item == NULL)
3798 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003799 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003800 return;
3801 }
3802 }
3803 }
3804 else
3805 item = NULL;
3806 list_extend(l1, l2, item);
3807
3808 copy_tv(&argvars[0], rettv);
3809 }
3810 }
3811 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3812 {
3813 dict_T *d1, *d2;
3814 char_u *action;
3815 int i;
3816
3817 d1 = argvars[0].vval.v_dict;
3818 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003819 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003820 && d2 != NULL)
3821 {
3822 /* Check the third argument. */
3823 if (argvars[2].v_type != VAR_UNKNOWN)
3824 {
3825 static char *(av[]) = {"keep", "force", "error"};
3826
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003827 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003828 if (action == NULL)
3829 return; /* type error; errmsg already given */
3830 for (i = 0; i < 3; ++i)
3831 if (STRCMP(action, av[i]) == 0)
3832 break;
3833 if (i == 3)
3834 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003835 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003836 return;
3837 }
3838 }
3839 else
3840 action = (char_u *)"force";
3841
3842 dict_extend(d1, d2, action);
3843
3844 copy_tv(&argvars[0], rettv);
3845 }
3846 }
3847 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003848 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003849}
3850
3851/*
3852 * "feedkeys()" function
3853 */
3854 static void
3855f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3856{
3857 int remap = TRUE;
3858 int insert = FALSE;
3859 char_u *keys, *flags;
3860 char_u nbuf[NUMBUFLEN];
3861 int typed = FALSE;
3862 int execute = FALSE;
3863 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003864 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003865 char_u *keys_esc;
3866
3867 /* This is not allowed in the sandbox. If the commands would still be
3868 * executed in the sandbox it would be OK, but it probably happens later,
3869 * when "sandbox" is no longer set. */
3870 if (check_secure())
3871 return;
3872
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003873 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003874
3875 if (argvars[1].v_type != VAR_UNKNOWN)
3876 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003877 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878 for ( ; *flags != NUL; ++flags)
3879 {
3880 switch (*flags)
3881 {
3882 case 'n': remap = FALSE; break;
3883 case 'm': remap = TRUE; break;
3884 case 't': typed = TRUE; break;
3885 case 'i': insert = TRUE; break;
3886 case 'x': execute = TRUE; break;
3887 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003888 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889 }
3890 }
3891 }
3892
3893 if (*keys != NUL || execute)
3894 {
3895 /* Need to escape K_SPECIAL and CSI before putting the string in the
3896 * typeahead buffer. */
3897 keys_esc = vim_strsave_escape_csi(keys);
3898 if (keys_esc != NULL)
3899 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003900 if (lowlevel)
3901 {
3902#ifdef USE_INPUT_BUF
3903 add_to_input_buf(keys, (int)STRLEN(keys));
3904#else
3905 emsg(_("E980: lowlevel input not supported"));
3906#endif
3907 }
3908 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003909 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003910 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003911 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003912 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003913#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003914 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003915#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003916 )
3917 typebuf_was_filled = TRUE;
3918 }
3919 vim_free(keys_esc);
3920
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 if (execute)
3922 {
3923 int save_msg_scroll = msg_scroll;
3924
3925 /* Avoid a 1 second delay when the keys start Insert mode. */
3926 msg_scroll = FALSE;
3927
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003928 if (!dangerous)
3929 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003930 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003931 if (!dangerous)
3932 --ex_normal_busy;
3933
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 msg_scroll |= save_msg_scroll;
3935 }
3936 }
3937 }
3938}
3939
3940/*
3941 * "filereadable()" function
3942 */
3943 static void
3944f_filereadable(typval_T *argvars, typval_T *rettv)
3945{
3946 int fd;
3947 char_u *p;
3948 int n;
3949
3950#ifndef O_NONBLOCK
3951# define O_NONBLOCK 0
3952#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003953 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3955 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3956 {
3957 n = TRUE;
3958 close(fd);
3959 }
3960 else
3961 n = FALSE;
3962
3963 rettv->vval.v_number = n;
3964}
3965
3966/*
3967 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3968 * rights to write into.
3969 */
3970 static void
3971f_filewritable(typval_T *argvars, typval_T *rettv)
3972{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003973 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003974}
3975
3976 static void
3977findfilendir(
3978 typval_T *argvars UNUSED,
3979 typval_T *rettv,
3980 int find_what UNUSED)
3981{
3982#ifdef FEAT_SEARCHPATH
3983 char_u *fname;
3984 char_u *fresult = NULL;
3985 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3986 char_u *p;
3987 char_u pathbuf[NUMBUFLEN];
3988 int count = 1;
3989 int first = TRUE;
3990 int error = FALSE;
3991#endif
3992
3993 rettv->vval.v_string = NULL;
3994 rettv->v_type = VAR_STRING;
3995
3996#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003997 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003998
3999 if (argvars[1].v_type != VAR_UNKNOWN)
4000 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004001 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002 if (p == NULL)
4003 error = TRUE;
4004 else
4005 {
4006 if (*p != NUL)
4007 path = p;
4008
4009 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004010 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004011 }
4012 }
4013
4014 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
4015 error = TRUE;
4016
4017 if (*fname != NUL && !error)
4018 {
4019 do
4020 {
4021 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
4022 vim_free(fresult);
4023 fresult = find_file_in_path_option(first ? fname : NULL,
4024 first ? (int)STRLEN(fname) : 0,
4025 0, first, path,
4026 find_what,
4027 curbuf->b_ffname,
4028 find_what == FINDFILE_DIR
4029 ? (char_u *)"" : curbuf->b_p_sua);
4030 first = FALSE;
4031
4032 if (fresult != NULL && rettv->v_type == VAR_LIST)
4033 list_append_string(rettv->vval.v_list, fresult, -1);
4034
4035 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
4036 }
4037
4038 if (rettv->v_type == VAR_STRING)
4039 rettv->vval.v_string = fresult;
4040#endif
4041}
4042
4043/*
4044 * "filter()" function
4045 */
4046 static void
4047f_filter(typval_T *argvars, typval_T *rettv)
4048{
4049 filter_map(argvars, rettv, FALSE);
4050}
4051
4052/*
4053 * "finddir({fname}[, {path}[, {count}]])" function
4054 */
4055 static void
4056f_finddir(typval_T *argvars, typval_T *rettv)
4057{
4058 findfilendir(argvars, rettv, FINDFILE_DIR);
4059}
4060
4061/*
4062 * "findfile({fname}[, {path}[, {count}]])" function
4063 */
4064 static void
4065f_findfile(typval_T *argvars, typval_T *rettv)
4066{
4067 findfilendir(argvars, rettv, FINDFILE_FILE);
4068}
4069
4070#ifdef FEAT_FLOAT
4071/*
4072 * "float2nr({float})" function
4073 */
4074 static void
4075f_float2nr(typval_T *argvars, typval_T *rettv)
4076{
4077 float_T f = 0.0;
4078
4079 if (get_float_arg(argvars, &f) == OK)
4080 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02004081 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01004082 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02004083 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01004084 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004085 else
4086 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004087 }
4088}
4089
4090/*
4091 * "floor({float})" function
4092 */
4093 static void
4094f_floor(typval_T *argvars, typval_T *rettv)
4095{
4096 float_T f = 0.0;
4097
4098 rettv->v_type = VAR_FLOAT;
4099 if (get_float_arg(argvars, &f) == OK)
4100 rettv->vval.v_float = floor(f);
4101 else
4102 rettv->vval.v_float = 0.0;
4103}
4104
4105/*
4106 * "fmod()" function
4107 */
4108 static void
4109f_fmod(typval_T *argvars, typval_T *rettv)
4110{
4111 float_T fx = 0.0, fy = 0.0;
4112
4113 rettv->v_type = VAR_FLOAT;
4114 if (get_float_arg(argvars, &fx) == OK
4115 && get_float_arg(&argvars[1], &fy) == OK)
4116 rettv->vval.v_float = fmod(fx, fy);
4117 else
4118 rettv->vval.v_float = 0.0;
4119}
4120#endif
4121
4122/*
4123 * "fnameescape({string})" function
4124 */
4125 static void
4126f_fnameescape(typval_T *argvars, typval_T *rettv)
4127{
4128 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004129 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004130 rettv->v_type = VAR_STRING;
4131}
4132
4133/*
4134 * "fnamemodify({fname}, {mods})" function
4135 */
4136 static void
4137f_fnamemodify(typval_T *argvars, typval_T *rettv)
4138{
4139 char_u *fname;
4140 char_u *mods;
4141 int usedlen = 0;
4142 int len;
4143 char_u *fbuf = NULL;
4144 char_u buf[NUMBUFLEN];
4145
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004146 fname = tv_get_string_chk(&argvars[0]);
4147 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 if (fname == NULL || mods == NULL)
4149 fname = NULL;
4150 else
4151 {
4152 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02004153 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004154 }
4155
4156 rettv->v_type = VAR_STRING;
4157 if (fname == NULL)
4158 rettv->vval.v_string = NULL;
4159 else
4160 rettv->vval.v_string = vim_strnsave(fname, len);
4161 vim_free(fbuf);
4162}
4163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004164/*
4165 * "foldclosed()" function
4166 */
4167 static void
4168foldclosed_both(
4169 typval_T *argvars UNUSED,
4170 typval_T *rettv,
4171 int end UNUSED)
4172{
4173#ifdef FEAT_FOLDING
4174 linenr_T lnum;
4175 linenr_T first, last;
4176
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004177 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004178 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4179 {
4180 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4181 {
4182 if (end)
4183 rettv->vval.v_number = (varnumber_T)last;
4184 else
4185 rettv->vval.v_number = (varnumber_T)first;
4186 return;
4187 }
4188 }
4189#endif
4190 rettv->vval.v_number = -1;
4191}
4192
4193/*
4194 * "foldclosed()" function
4195 */
4196 static void
4197f_foldclosed(typval_T *argvars, typval_T *rettv)
4198{
4199 foldclosed_both(argvars, rettv, FALSE);
4200}
4201
4202/*
4203 * "foldclosedend()" function
4204 */
4205 static void
4206f_foldclosedend(typval_T *argvars, typval_T *rettv)
4207{
4208 foldclosed_both(argvars, rettv, TRUE);
4209}
4210
4211/*
4212 * "foldlevel()" function
4213 */
4214 static void
4215f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4216{
4217#ifdef FEAT_FOLDING
4218 linenr_T lnum;
4219
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004220 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004221 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4222 rettv->vval.v_number = foldLevel(lnum);
4223#endif
4224}
4225
4226/*
4227 * "foldtext()" function
4228 */
4229 static void
4230f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4231{
4232#ifdef FEAT_FOLDING
4233 linenr_T foldstart;
4234 linenr_T foldend;
4235 char_u *dashes;
4236 linenr_T lnum;
4237 char_u *s;
4238 char_u *r;
4239 int len;
4240 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004241 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004242#endif
4243
4244 rettv->v_type = VAR_STRING;
4245 rettv->vval.v_string = NULL;
4246#ifdef FEAT_FOLDING
4247 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4248 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4249 dashes = get_vim_var_str(VV_FOLDDASHES);
4250 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4251 && dashes != NULL)
4252 {
4253 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004254 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255 if (!linewhite(lnum))
4256 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257
4258 /* Find interesting text in this line. */
4259 s = skipwhite(ml_get(lnum));
4260 /* skip C comment-start */
4261 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4262 {
4263 s = skipwhite(s + 2);
4264 if (*skipwhite(s) == NUL
4265 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4266 {
4267 s = skipwhite(ml_get(lnum + 1));
4268 if (*s == '*')
4269 s = skipwhite(s + 1);
4270 }
4271 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004272 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004273 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004274 r = alloc((unsigned)(STRLEN(txt)
4275 + STRLEN(dashes) /* for %s */
4276 + 20 /* for %3ld */
4277 + STRLEN(s))); /* concatenated */
4278 if (r != NULL)
4279 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004280 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004281 len = (int)STRLEN(r);
4282 STRCAT(r, s);
4283 /* remove 'foldmarker' and 'commentstring' */
4284 foldtext_cleanup(r + len);
4285 rettv->vval.v_string = r;
4286 }
4287 }
4288#endif
4289}
4290
4291/*
4292 * "foldtextresult(lnum)" function
4293 */
4294 static void
4295f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4296{
4297#ifdef FEAT_FOLDING
4298 linenr_T lnum;
4299 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004300 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301 foldinfo_T foldinfo;
4302 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004303 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004304#endif
4305
4306 rettv->v_type = VAR_STRING;
4307 rettv->vval.v_string = NULL;
4308#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004309 if (entered)
4310 return; /* reject recursive use */
4311 entered = TRUE;
4312
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004313 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314 /* treat illegal types and illegal string values for {lnum} the same */
4315 if (lnum < 0)
4316 lnum = 0;
4317 fold_count = foldedCount(curwin, lnum, &foldinfo);
4318 if (fold_count > 0)
4319 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004320 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4321 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004322 if (text == buf)
4323 text = vim_strsave(text);
4324 rettv->vval.v_string = text;
4325 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004326
4327 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004328#endif
4329}
4330
4331/*
4332 * "foreground()" function
4333 */
4334 static void
4335f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4336{
4337#ifdef FEAT_GUI
4338 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004339 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004340 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004341 return;
4342 }
4343#endif
4344#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004345 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004346#endif
4347}
4348
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004349 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004350common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004351{
4352 char_u *s;
4353 char_u *name;
4354 int use_string = FALSE;
4355 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004356 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004357
4358 if (argvars[0].v_type == VAR_FUNC)
4359 {
4360 /* function(MyFunc, [arg], dict) */
4361 s = argvars[0].vval.v_string;
4362 }
4363 else if (argvars[0].v_type == VAR_PARTIAL
4364 && argvars[0].vval.v_partial != NULL)
4365 {
4366 /* function(dict.MyFunc, [arg]) */
4367 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004368 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004369 }
4370 else
4371 {
4372 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004373 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004374 use_string = TRUE;
4375 }
4376
Bram Moolenaar843b8842016-08-21 14:36:15 +02004377 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004378 {
4379 name = s;
4380 trans_name = trans_function_name(&name, FALSE,
4381 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4382 if (*name != NUL)
4383 s = NULL;
4384 }
4385
Bram Moolenaar843b8842016-08-21 14:36:15 +02004386 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4387 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004388 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004389 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004390 else if (trans_name != NULL && (is_funcref
4391 ? find_func(trans_name) == NULL
4392 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004393 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004394 else
4395 {
4396 int dict_idx = 0;
4397 int arg_idx = 0;
4398 list_T *list = NULL;
4399
4400 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4401 {
4402 char sid_buf[25];
4403 int off = *s == 's' ? 2 : 5;
4404
4405 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4406 * also be called from another script. Using trans_function_name()
4407 * would also work, but some plugins depend on the name being
4408 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004409 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004410 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4411 if (name != NULL)
4412 {
4413 STRCPY(name, sid_buf);
4414 STRCAT(name, s + off);
4415 }
4416 }
4417 else
4418 name = vim_strsave(s);
4419
4420 if (argvars[1].v_type != VAR_UNKNOWN)
4421 {
4422 if (argvars[2].v_type != VAR_UNKNOWN)
4423 {
4424 /* function(name, [args], dict) */
4425 arg_idx = 1;
4426 dict_idx = 2;
4427 }
4428 else if (argvars[1].v_type == VAR_DICT)
4429 /* function(name, dict) */
4430 dict_idx = 1;
4431 else
4432 /* function(name, [args]) */
4433 arg_idx = 1;
4434 if (dict_idx > 0)
4435 {
4436 if (argvars[dict_idx].v_type != VAR_DICT)
4437 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004438 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004439 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004440 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004441 }
4442 if (argvars[dict_idx].vval.v_dict == NULL)
4443 dict_idx = 0;
4444 }
4445 if (arg_idx > 0)
4446 {
4447 if (argvars[arg_idx].v_type != VAR_LIST)
4448 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004449 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004450 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004451 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452 }
4453 list = argvars[arg_idx].vval.v_list;
4454 if (list == NULL || list->lv_len == 0)
4455 arg_idx = 0;
4456 }
4457 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004458 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459 {
4460 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4461
4462 /* result is a VAR_PARTIAL */
4463 if (pt == NULL)
4464 vim_free(name);
4465 else
4466 {
4467 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4468 {
4469 listitem_T *li;
4470 int i = 0;
4471 int arg_len = 0;
4472 int lv_len = 0;
4473
4474 if (arg_pt != NULL)
4475 arg_len = arg_pt->pt_argc;
4476 if (list != NULL)
4477 lv_len = list->lv_len;
4478 pt->pt_argc = arg_len + lv_len;
4479 pt->pt_argv = (typval_T *)alloc(
4480 sizeof(typval_T) * pt->pt_argc);
4481 if (pt->pt_argv == NULL)
4482 {
4483 vim_free(pt);
4484 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004485 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004486 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004487 for (i = 0; i < arg_len; i++)
4488 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4489 if (lv_len > 0)
4490 for (li = list->lv_first; li != NULL;
4491 li = li->li_next)
4492 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493 }
4494
4495 /* For "function(dict.func, [], dict)" and "func" is a partial
4496 * use "dict". That is backwards compatible. */
4497 if (dict_idx > 0)
4498 {
4499 /* The dict is bound explicitly, pt_auto is FALSE. */
4500 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4501 ++pt->pt_dict->dv_refcount;
4502 }
4503 else if (arg_pt != NULL)
4504 {
4505 /* If the dict was bound automatically the result is also
4506 * bound automatically. */
4507 pt->pt_dict = arg_pt->pt_dict;
4508 pt->pt_auto = arg_pt->pt_auto;
4509 if (pt->pt_dict != NULL)
4510 ++pt->pt_dict->dv_refcount;
4511 }
4512
4513 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004514 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4515 {
4516 pt->pt_func = arg_pt->pt_func;
4517 func_ptr_ref(pt->pt_func);
4518 vim_free(name);
4519 }
4520 else if (is_funcref)
4521 {
4522 pt->pt_func = find_func(trans_name);
4523 func_ptr_ref(pt->pt_func);
4524 vim_free(name);
4525 }
4526 else
4527 {
4528 pt->pt_name = name;
4529 func_ref(name);
4530 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004531 }
4532 rettv->v_type = VAR_PARTIAL;
4533 rettv->vval.v_partial = pt;
4534 }
4535 else
4536 {
4537 /* result is a VAR_FUNC */
4538 rettv->v_type = VAR_FUNC;
4539 rettv->vval.v_string = name;
4540 func_ref(name);
4541 }
4542 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004543theend:
4544 vim_free(trans_name);
4545}
4546
4547/*
4548 * "funcref()" function
4549 */
4550 static void
4551f_funcref(typval_T *argvars, typval_T *rettv)
4552{
4553 common_function(argvars, rettv, TRUE);
4554}
4555
4556/*
4557 * "function()" function
4558 */
4559 static void
4560f_function(typval_T *argvars, typval_T *rettv)
4561{
4562 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563}
4564
4565/*
4566 * "garbagecollect()" function
4567 */
4568 static void
4569f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4570{
4571 /* This is postponed until we are back at the toplevel, because we may be
4572 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4573 want_garbage_collect = TRUE;
4574
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004575 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004576 garbage_collect_at_exit = TRUE;
4577}
4578
4579/*
4580 * "get()" function
4581 */
4582 static void
4583f_get(typval_T *argvars, typval_T *rettv)
4584{
4585 listitem_T *li;
4586 list_T *l;
4587 dictitem_T *di;
4588 dict_T *d;
4589 typval_T *tv = NULL;
4590
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004591 if (argvars[0].v_type == VAR_BLOB)
4592 {
4593 int error = FALSE;
4594 int idx = tv_get_number_chk(&argvars[1], &error);
4595
4596 if (!error)
4597 {
4598 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004599 if (idx < 0)
4600 idx = blob_len(argvars[0].vval.v_blob) + idx;
4601 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4602 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004603 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004604 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004605 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004606 tv = rettv;
4607 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004608 }
4609 }
4610 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611 {
4612 if ((l = argvars[0].vval.v_list) != NULL)
4613 {
4614 int error = FALSE;
4615
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004616 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004617 if (!error && li != NULL)
4618 tv = &li->li_tv;
4619 }
4620 }
4621 else if (argvars[0].v_type == VAR_DICT)
4622 {
4623 if ((d = argvars[0].vval.v_dict) != NULL)
4624 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004625 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004626 if (di != NULL)
4627 tv = &di->di_tv;
4628 }
4629 }
4630 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4631 {
4632 partial_T *pt;
4633 partial_T fref_pt;
4634
4635 if (argvars[0].v_type == VAR_PARTIAL)
4636 pt = argvars[0].vval.v_partial;
4637 else
4638 {
4639 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4640 fref_pt.pt_name = argvars[0].vval.v_string;
4641 pt = &fref_pt;
4642 }
4643
4644 if (pt != NULL)
4645 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004646 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004647 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004648
4649 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4650 {
4651 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004652 n = partial_name(pt);
4653 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004654 rettv->vval.v_string = NULL;
4655 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004656 {
4657 rettv->vval.v_string = vim_strsave(n);
4658 if (rettv->v_type == VAR_FUNC)
4659 func_ref(rettv->vval.v_string);
4660 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661 }
4662 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004663 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664 else if (STRCMP(what, "args") == 0)
4665 {
4666 rettv->v_type = VAR_LIST;
4667 if (rettv_list_alloc(rettv) == OK)
4668 {
4669 int i;
4670
4671 for (i = 0; i < pt->pt_argc; ++i)
4672 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4673 }
4674 }
4675 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004676 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004677 return;
4678 }
4679 }
4680 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004681 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004682
4683 if (tv == NULL)
4684 {
4685 if (argvars[2].v_type != VAR_UNKNOWN)
4686 copy_tv(&argvars[2], rettv);
4687 }
4688 else
4689 copy_tv(tv, rettv);
4690}
4691
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004692/*
4693 * Returns buffer options, variables and other attributes in a dictionary.
4694 */
4695 static dict_T *
4696get_buffer_info(buf_T *buf)
4697{
4698 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004699 tabpage_T *tp;
4700 win_T *wp;
4701 list_T *windows;
4702
4703 dict = dict_alloc();
4704 if (dict == NULL)
4705 return NULL;
4706
Bram Moolenaare0be1672018-07-08 16:50:37 +02004707 dict_add_number(dict, "bufnr", buf->b_fnum);
4708 dict_add_string(dict, "name", buf->b_ffname);
4709 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4710 : buflist_findlnum(buf));
4711 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4712 dict_add_number(dict, "listed", buf->b_p_bl);
4713 dict_add_number(dict, "changed", bufIsChanged(buf));
4714 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4715 dict_add_number(dict, "hidden",
4716 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004717
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004718 /* Get a reference to buffer variables */
4719 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004720
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004721 /* List of windows displaying this buffer */
4722 windows = list_alloc();
4723 if (windows != NULL)
4724 {
4725 FOR_ALL_TAB_WINDOWS(tp, wp)
4726 if (wp->w_buffer == buf)
4727 list_append_number(windows, (varnumber_T)wp->w_id);
4728 dict_add_list(dict, "windows", windows);
4729 }
4730
4731#ifdef FEAT_SIGNS
4732 if (buf->b_signlist != NULL)
4733 {
4734 /* List of signs placed in this buffer */
4735 list_T *signs = list_alloc();
4736 if (signs != NULL)
4737 {
4738 get_buffer_signs(buf, signs);
4739 dict_add_list(dict, "signs", signs);
4740 }
4741 }
4742#endif
4743
4744 return dict;
4745}
4746
4747/*
4748 * "getbufinfo()" function
4749 */
4750 static void
4751f_getbufinfo(typval_T *argvars, typval_T *rettv)
4752{
4753 buf_T *buf = NULL;
4754 buf_T *argbuf = NULL;
4755 dict_T *d;
4756 int filtered = FALSE;
4757 int sel_buflisted = FALSE;
4758 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004759 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004760
4761 if (rettv_list_alloc(rettv) != OK)
4762 return;
4763
4764 /* List of all the buffers or selected buffers */
4765 if (argvars[0].v_type == VAR_DICT)
4766 {
4767 dict_T *sel_d = argvars[0].vval.v_dict;
4768
4769 if (sel_d != NULL)
4770 {
4771 dictitem_T *di;
4772
4773 filtered = TRUE;
4774
4775 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004776 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004777 sel_buflisted = TRUE;
4778
4779 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004780 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004781 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004782
4783 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004784 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004785 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004786 }
4787 }
4788 else if (argvars[0].v_type != VAR_UNKNOWN)
4789 {
4790 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004791 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004792 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004793 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004794 --emsg_off;
4795 if (argbuf == NULL)
4796 return;
4797 }
4798
4799 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004800 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004801 {
4802 if (argbuf != NULL && argbuf != buf)
4803 continue;
4804 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004805 || (sel_buflisted && !buf->b_p_bl)
4806 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004807 continue;
4808
4809 d = get_buffer_info(buf);
4810 if (d != NULL)
4811 list_append_dict(rettv->vval.v_list, d);
4812 if (argbuf != NULL)
4813 return;
4814 }
4815}
4816
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004817/*
4818 * Get line or list of lines from buffer "buf" into "rettv".
4819 * Return a range (from start to end) of lines in rettv from the specified
4820 * buffer.
4821 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4822 */
4823 static void
4824get_buffer_lines(
4825 buf_T *buf,
4826 linenr_T start,
4827 linenr_T end,
4828 int retlist,
4829 typval_T *rettv)
4830{
4831 char_u *p;
4832
4833 rettv->v_type = VAR_STRING;
4834 rettv->vval.v_string = NULL;
4835 if (retlist && rettv_list_alloc(rettv) == FAIL)
4836 return;
4837
4838 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4839 return;
4840
4841 if (!retlist)
4842 {
4843 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4844 p = ml_get_buf(buf, start, FALSE);
4845 else
4846 p = (char_u *)"";
4847 rettv->vval.v_string = vim_strsave(p);
4848 }
4849 else
4850 {
4851 if (end < start)
4852 return;
4853
4854 if (start < 1)
4855 start = 1;
4856 if (end > buf->b_ml.ml_line_count)
4857 end = buf->b_ml.ml_line_count;
4858 while (start <= end)
4859 if (list_append_string(rettv->vval.v_list,
4860 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4861 break;
4862 }
4863}
4864
4865/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004866 * "getbufline()" function
4867 */
4868 static void
4869f_getbufline(typval_T *argvars, typval_T *rettv)
4870{
4871 linenr_T lnum;
4872 linenr_T end;
4873 buf_T *buf;
4874
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004875 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004876 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004877 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878 --emsg_off;
4879
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004880 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004881 if (argvars[2].v_type == VAR_UNKNOWN)
4882 end = lnum;
4883 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004884 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004885
4886 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4887}
4888
4889/*
4890 * "getbufvar()" function
4891 */
4892 static void
4893f_getbufvar(typval_T *argvars, typval_T *rettv)
4894{
4895 buf_T *buf;
4896 buf_T *save_curbuf;
4897 char_u *varname;
4898 dictitem_T *v;
4899 int done = FALSE;
4900
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004901 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4902 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004904 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004905
4906 rettv->v_type = VAR_STRING;
4907 rettv->vval.v_string = NULL;
4908
4909 if (buf != NULL && varname != NULL)
4910 {
4911 /* set curbuf to be our buf, temporarily */
4912 save_curbuf = curbuf;
4913 curbuf = buf;
4914
Bram Moolenaar30567352016-08-27 21:25:44 +02004915 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004917 if (varname[1] == NUL)
4918 {
4919 /* get all buffer-local options in a dict */
4920 dict_T *opts = get_winbuf_options(TRUE);
4921
4922 if (opts != NULL)
4923 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004924 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004925 done = TRUE;
4926 }
4927 }
4928 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4929 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 done = TRUE;
4931 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004932 else
4933 {
4934 /* Look up the variable. */
4935 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4936 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4937 'b', varname, FALSE);
4938 if (v != NULL)
4939 {
4940 copy_tv(&v->di_tv, rettv);
4941 done = TRUE;
4942 }
4943 }
4944
4945 /* restore previous notion of curbuf */
4946 curbuf = save_curbuf;
4947 }
4948
4949 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4950 /* use the default value */
4951 copy_tv(&argvars[2], rettv);
4952
4953 --emsg_off;
4954}
4955
4956/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004957 * "getchangelist()" function
4958 */
4959 static void
4960f_getchangelist(typval_T *argvars, typval_T *rettv)
4961{
4962#ifdef FEAT_JUMPLIST
4963 buf_T *buf;
4964 int i;
4965 list_T *l;
4966 dict_T *d;
4967#endif
4968
4969 if (rettv_list_alloc(rettv) != OK)
4970 return;
4971
4972#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004973 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004974 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004975 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004976 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004977 if (buf == NULL)
4978 return;
4979
4980 l = list_alloc();
4981 if (l == NULL)
4982 return;
4983
4984 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4985 return;
4986 /*
4987 * The current window change list index tracks only the position in the
4988 * current buffer change list. For other buffers, use the change list
4989 * length as the current index.
4990 */
4991 list_append_number(rettv->vval.v_list,
4992 (varnumber_T)((buf == curwin->w_buffer)
4993 ? curwin->w_changelistidx : buf->b_changelistlen));
4994
4995 for (i = 0; i < buf->b_changelistlen; ++i)
4996 {
4997 if (buf->b_changelist[i].lnum == 0)
4998 continue;
4999 if ((d = dict_alloc()) == NULL)
5000 return;
5001 if (list_append_dict(l, d) == FAIL)
5002 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005003 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
5004 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005005 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01005006 }
5007#endif
5008}
5009/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010 * "getchar()" function
5011 */
5012 static void
5013f_getchar(typval_T *argvars, typval_T *rettv)
5014{
5015 varnumber_T n;
5016 int error = FALSE;
5017
Bram Moolenaar84d93902018-09-11 20:10:20 +02005018#ifdef MESSAGE_QUEUE
5019 // vpeekc() used to check for messages, but that caused problems, invoking
5020 // a callback where it was not expected. Some plugins use getchar(1) in a
5021 // loop to await a message, therefore make sure we check for messages here.
5022 parse_queued_messages();
5023#endif
5024
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 /* Position the cursor. Needed after a message that ends in a space. */
5026 windgoto(msg_row, msg_col);
5027
5028 ++no_mapping;
5029 ++allow_keys;
5030 for (;;)
5031 {
5032 if (argvars[0].v_type == VAR_UNKNOWN)
5033 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01005034 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005035 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036 /* getchar(1): only check if char avail */
5037 n = vpeekc_any();
5038 else if (error || vpeekc_any() == NUL)
5039 /* illegal argument or getchar(0) and no char avail: return zero */
5040 n = 0;
5041 else
5042 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01005043 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044
5045 if (n == K_IGNORE)
5046 continue;
5047 break;
5048 }
5049 --no_mapping;
5050 --allow_keys;
5051
5052 set_vim_var_nr(VV_MOUSE_WIN, 0);
5053 set_vim_var_nr(VV_MOUSE_WINID, 0);
5054 set_vim_var_nr(VV_MOUSE_LNUM, 0);
5055 set_vim_var_nr(VV_MOUSE_COL, 0);
5056
5057 rettv->vval.v_number = n;
5058 if (IS_SPECIAL(n) || mod_mask != 0)
5059 {
5060 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
5061 int i = 0;
5062
5063 /* Turn a special key into three bytes, plus modifier. */
5064 if (mod_mask != 0)
5065 {
5066 temp[i++] = K_SPECIAL;
5067 temp[i++] = KS_MODIFIER;
5068 temp[i++] = mod_mask;
5069 }
5070 if (IS_SPECIAL(n))
5071 {
5072 temp[i++] = K_SPECIAL;
5073 temp[i++] = K_SECOND(n);
5074 temp[i++] = K_THIRD(n);
5075 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076 else if (has_mbyte)
5077 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 else
5079 temp[i++] = n;
5080 temp[i++] = NUL;
5081 rettv->v_type = VAR_STRING;
5082 rettv->vval.v_string = vim_strsave(temp);
5083
5084#ifdef FEAT_MOUSE
5085 if (is_mouse_key(n))
5086 {
5087 int row = mouse_row;
5088 int col = mouse_col;
5089 win_T *win;
5090 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005091 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005092 int winnr = 1;
5093
5094 if (row >= 0 && col >= 0)
5095 {
5096 /* Find the window at the mouse coordinates and compute the
5097 * text position. */
5098 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02005099 if (win == NULL)
5100 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 for (wp = firstwin; wp != win; wp = wp->w_next)
5103 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 set_vim_var_nr(VV_MOUSE_WIN, winnr);
5105 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
5106 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
5107 set_vim_var_nr(VV_MOUSE_COL, col + 1);
5108 }
5109 }
5110#endif
5111 }
5112}
5113
5114/*
5115 * "getcharmod()" function
5116 */
5117 static void
5118f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
5119{
5120 rettv->vval.v_number = mod_mask;
5121}
5122
5123/*
5124 * "getcharsearch()" function
5125 */
5126 static void
5127f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
5128{
5129 if (rettv_dict_alloc(rettv) != FAIL)
5130 {
5131 dict_T *dict = rettv->vval.v_dict;
5132
Bram Moolenaare0be1672018-07-08 16:50:37 +02005133 dict_add_string(dict, "char", last_csearch());
5134 dict_add_number(dict, "forward", last_csearch_forward());
5135 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005136 }
5137}
5138
5139/*
5140 * "getcmdline()" function
5141 */
5142 static void
5143f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
5144{
5145 rettv->v_type = VAR_STRING;
5146 rettv->vval.v_string = get_cmdline_str();
5147}
5148
5149/*
5150 * "getcmdpos()" function
5151 */
5152 static void
5153f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
5154{
5155 rettv->vval.v_number = get_cmdline_pos() + 1;
5156}
5157
5158/*
5159 * "getcmdtype()" function
5160 */
5161 static void
5162f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
5163{
5164 rettv->v_type = VAR_STRING;
5165 rettv->vval.v_string = alloc(2);
5166 if (rettv->vval.v_string != NULL)
5167 {
5168 rettv->vval.v_string[0] = get_cmdline_type();
5169 rettv->vval.v_string[1] = NUL;
5170 }
5171}
5172
5173/*
5174 * "getcmdwintype()" function
5175 */
5176 static void
5177f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5178{
5179 rettv->v_type = VAR_STRING;
5180 rettv->vval.v_string = NULL;
5181#ifdef FEAT_CMDWIN
5182 rettv->vval.v_string = alloc(2);
5183 if (rettv->vval.v_string != NULL)
5184 {
5185 rettv->vval.v_string[0] = cmdwin_type;
5186 rettv->vval.v_string[1] = NUL;
5187 }
5188#endif
5189}
5190
5191#if defined(FEAT_CMDL_COMPL)
5192/*
5193 * "getcompletion()" function
5194 */
5195 static void
5196f_getcompletion(typval_T *argvars, typval_T *rettv)
5197{
5198 char_u *pat;
5199 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005200 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005201 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5202 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005204 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005205 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207 if (p_wic)
5208 options |= WILD_ICASE;
5209
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005210 /* For filtered results, 'wildignore' is used */
5211 if (!filtered)
5212 options |= WILD_KEEP_ALL;
5213
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005214 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005215 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005216 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005217 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005218 if (xpc.xp_context == EXPAND_NOTHING)
5219 {
5220 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005221 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005222 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005223 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005224 return;
5225 }
5226
5227# if defined(FEAT_MENU)
5228 if (xpc.xp_context == EXPAND_MENUS)
5229 {
5230 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5231 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5232 }
5233# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005234#ifdef FEAT_CSCOPE
5235 if (xpc.xp_context == EXPAND_CSCOPE)
5236 {
5237 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5238 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5239 }
5240#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005241#ifdef FEAT_SIGNS
5242 if (xpc.xp_context == EXPAND_SIGN)
5243 {
5244 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5245 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5246 }
5247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005248
5249 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5250 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5251 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005252 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005253
5254 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5255
5256 for (i = 0; i < xpc.xp_numfiles; i++)
5257 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5258 }
5259 vim_free(pat);
5260 ExpandCleanup(&xpc);
5261}
5262#endif
5263
5264/*
5265 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005266 *
5267 * Return the current working directory of a window in a tab page.
5268 * First optional argument 'winnr' is the window number or -1 and the second
5269 * optional argument 'tabnr' is the tab page number.
5270 *
5271 * If no arguments are supplied, then return the directory of the current
5272 * window.
5273 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
5274 * the specified window.
5275 * If 'winnr' is 0 then return the directory of the current window.
5276 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
5277 * directory of the specified tab page. Otherwise return the directory of the
5278 * specified window in the specified tab page.
5279 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005280 */
5281 static void
5282f_getcwd(typval_T *argvars, typval_T *rettv)
5283{
5284 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005285 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005287 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288
5289 rettv->v_type = VAR_STRING;
5290 rettv->vval.v_string = NULL;
5291
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005292 if (argvars[0].v_type == VAR_NUMBER
5293 && argvars[0].vval.v_number == -1
5294 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01005295 global = TRUE;
5296 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005297 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01005298
5299 if (wp != NULL && wp->w_localdir != NULL)
5300 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005301 else if (tp != NULL && tp->tp_localdir != NULL)
5302 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
5303 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005304 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005305 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306 rettv->vval.v_string = vim_strsave(globaldir);
5307 else
5308 {
5309 cwd = alloc(MAXPATHL);
5310 if (cwd != NULL)
5311 {
5312 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5313 rettv->vval.v_string = vim_strsave(cwd);
5314 vim_free(cwd);
5315 }
5316 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005317 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005318#ifdef BACKSLASH_IN_FILENAME
5319 if (rettv->vval.v_string != NULL)
5320 slash_adjust(rettv->vval.v_string);
5321#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005322}
5323
5324/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02005325 * "getenv()" function
5326 */
5327 static void
5328f_getenv(typval_T *argvars, typval_T *rettv)
5329{
5330 int mustfree = FALSE;
5331 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
5332
5333 if (p == NULL)
5334 {
5335 rettv->v_type = VAR_SPECIAL;
5336 rettv->vval.v_number = VVAL_NULL;
5337 return;
5338 }
5339 if (!mustfree)
5340 p = vim_strsave(p);
5341 rettv->vval.v_string = p;
5342 rettv->v_type = VAR_STRING;
5343}
5344
5345/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005346 * "getfontname()" function
5347 */
5348 static void
5349f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5350{
5351 rettv->v_type = VAR_STRING;
5352 rettv->vval.v_string = NULL;
5353#ifdef FEAT_GUI
5354 if (gui.in_use)
5355 {
5356 GuiFont font;
5357 char_u *name = NULL;
5358
5359 if (argvars[0].v_type == VAR_UNKNOWN)
5360 {
5361 /* Get the "Normal" font. Either the name saved by
5362 * hl_set_font_name() or from the font ID. */
5363 font = gui.norm_font;
5364 name = hl_get_font_name();
5365 }
5366 else
5367 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005368 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005369 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5370 return;
5371 font = gui_mch_get_font(name, FALSE);
5372 if (font == NOFONT)
5373 return; /* Invalid font name, return empty string. */
5374 }
5375 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5376 if (argvars[0].v_type != VAR_UNKNOWN)
5377 gui_mch_free_font(font);
5378 }
5379#endif
5380}
5381
5382/*
5383 * "getfperm({fname})" function
5384 */
5385 static void
5386f_getfperm(typval_T *argvars, typval_T *rettv)
5387{
5388 char_u *fname;
5389 stat_T st;
5390 char_u *perm = NULL;
5391 char_u flags[] = "rwx";
5392 int i;
5393
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005394 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005395
5396 rettv->v_type = VAR_STRING;
5397 if (mch_stat((char *)fname, &st) >= 0)
5398 {
5399 perm = vim_strsave((char_u *)"---------");
5400 if (perm != NULL)
5401 {
5402 for (i = 0; i < 9; i++)
5403 {
5404 if (st.st_mode & (1 << (8 - i)))
5405 perm[i] = flags[i % 3];
5406 }
5407 }
5408 }
5409 rettv->vval.v_string = perm;
5410}
5411
5412/*
5413 * "getfsize({fname})" function
5414 */
5415 static void
5416f_getfsize(typval_T *argvars, typval_T *rettv)
5417{
5418 char_u *fname;
5419 stat_T st;
5420
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005421 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005422
5423 rettv->v_type = VAR_NUMBER;
5424
5425 if (mch_stat((char *)fname, &st) >= 0)
5426 {
5427 if (mch_isdir(fname))
5428 rettv->vval.v_number = 0;
5429 else
5430 {
5431 rettv->vval.v_number = (varnumber_T)st.st_size;
5432
5433 /* non-perfect check for overflow */
5434 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5435 rettv->vval.v_number = -2;
5436 }
5437 }
5438 else
5439 rettv->vval.v_number = -1;
5440}
5441
5442/*
5443 * "getftime({fname})" function
5444 */
5445 static void
5446f_getftime(typval_T *argvars, typval_T *rettv)
5447{
5448 char_u *fname;
5449 stat_T st;
5450
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005451 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452
5453 if (mch_stat((char *)fname, &st) >= 0)
5454 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5455 else
5456 rettv->vval.v_number = -1;
5457}
5458
5459/*
5460 * "getftype({fname})" function
5461 */
5462 static void
5463f_getftype(typval_T *argvars, typval_T *rettv)
5464{
5465 char_u *fname;
5466 stat_T st;
5467 char_u *type = NULL;
5468 char *t;
5469
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005470 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005471
5472 rettv->v_type = VAR_STRING;
5473 if (mch_lstat((char *)fname, &st) >= 0)
5474 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005475 if (S_ISREG(st.st_mode))
5476 t = "file";
5477 else if (S_ISDIR(st.st_mode))
5478 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 else if (S_ISLNK(st.st_mode))
5480 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005481 else if (S_ISBLK(st.st_mode))
5482 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005483 else if (S_ISCHR(st.st_mode))
5484 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005485 else if (S_ISFIFO(st.st_mode))
5486 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005487 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005488 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 else
5490 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 type = vim_strsave((char_u *)t);
5492 }
5493 rettv->vval.v_string = type;
5494}
5495
5496/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005497 * "getjumplist()" function
5498 */
5499 static void
5500f_getjumplist(typval_T *argvars, typval_T *rettv)
5501{
5502#ifdef FEAT_JUMPLIST
5503 win_T *wp;
5504 int i;
5505 list_T *l;
5506 dict_T *d;
5507#endif
5508
5509 if (rettv_list_alloc(rettv) != OK)
5510 return;
5511
5512#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005513 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005514 if (wp == NULL)
5515 return;
5516
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005517 cleanup_jumplist(wp, TRUE);
5518
Bram Moolenaar4f505882018-02-10 21:06:32 +01005519 l = list_alloc();
5520 if (l == NULL)
5521 return;
5522
5523 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5524 return;
5525 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5526
5527 for (i = 0; i < wp->w_jumplistlen; ++i)
5528 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005529 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5530 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005531 if ((d = dict_alloc()) == NULL)
5532 return;
5533 if (list_append_dict(l, d) == FAIL)
5534 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005535 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5536 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005537 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005538 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005539 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005540 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005541 }
5542#endif
5543}
5544
5545/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005546 * "getline(lnum, [end])" function
5547 */
5548 static void
5549f_getline(typval_T *argvars, typval_T *rettv)
5550{
5551 linenr_T lnum;
5552 linenr_T end;
5553 int retlist;
5554
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005555 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556 if (argvars[1].v_type == VAR_UNKNOWN)
5557 {
5558 end = 0;
5559 retlist = FALSE;
5560 }
5561 else
5562 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005563 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005564 retlist = TRUE;
5565 }
5566
5567 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5568}
5569
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005570#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005571 static void
5572get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5573{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005574 if (what_arg->v_type == VAR_UNKNOWN)
5575 {
5576 if (rettv_list_alloc(rettv) == OK)
5577 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005578 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005579 }
5580 else
5581 {
5582 if (rettv_dict_alloc(rettv) == OK)
5583 if (is_qf || (wp != NULL))
5584 {
5585 if (what_arg->v_type == VAR_DICT)
5586 {
5587 dict_T *d = what_arg->vval.v_dict;
5588
5589 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005590 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005591 }
5592 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005593 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005594 }
5595 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005596}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005597#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005598
5599/*
5600 * "getloclist()" function
5601 */
5602 static void
5603f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5604{
5605#ifdef FEAT_QUICKFIX
5606 win_T *wp;
5607
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005608 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005609 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5610#endif
5611}
5612
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005613/*
5614 * "getmatches()" function
5615 */
5616 static void
5617f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5618{
5619#ifdef FEAT_SEARCH_EXTRA
5620 dict_T *dict;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005621 matchitem_T *cur;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622 int i;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005623 win_T *win = get_optional_window(argvars, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005624
Bram Moolenaaraff74912019-03-30 18:11:49 +01005625 if (rettv_list_alloc(rettv) == FAIL || win == NULL)
5626 return;
5627
5628 cur = win->w_match_head;
5629 while (cur != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005631 dict = dict_alloc();
5632 if (dict == NULL)
5633 return;
5634 if (cur->match.regprog == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005635 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005636 /* match added with matchaddpos() */
5637 for (i = 0; i < MAXPOSMATCH; ++i)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005638 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005639 llpos_T *llpos;
Bram Moolenaar54315892019-04-26 22:33:49 +02005640 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaaraff74912019-03-30 18:11:49 +01005641 list_T *l;
5642
5643 llpos = &cur->pos.pos[i];
5644 if (llpos->lnum == 0)
5645 break;
5646 l = list_alloc();
5647 if (l == NULL)
5648 break;
5649 list_append_number(l, (varnumber_T)llpos->lnum);
5650 if (llpos->col > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005651 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005652 list_append_number(l, (varnumber_T)llpos->col);
5653 list_append_number(l, (varnumber_T)llpos->len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005654 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005655 sprintf(buf, "pos%d", i + 1);
5656 dict_add_list(dict, buf, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005657 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005658 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005659 else
5660 {
5661 dict_add_string(dict, "pattern", cur->pattern);
5662 }
5663 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5664 dict_add_number(dict, "priority", (long)cur->priority);
5665 dict_add_number(dict, "id", (long)cur->id);
5666# if defined(FEAT_CONCEAL)
5667 if (cur->conceal_char)
5668 {
5669 char_u buf[MB_MAXBYTES + 1];
5670
5671 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5672 dict_add_string(dict, "conceal", (char_u *)&buf);
5673 }
5674# endif
5675 list_append_dict(rettv->vval.v_list, dict);
5676 cur = cur->next;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005677 }
5678#endif
5679}
5680
5681/*
5682 * "getpid()" function
5683 */
5684 static void
5685f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5686{
5687 rettv->vval.v_number = mch_get_pid();
5688}
5689
5690 static void
5691getpos_both(
5692 typval_T *argvars,
5693 typval_T *rettv,
5694 int getcurpos)
5695{
5696 pos_T *fp;
5697 list_T *l;
5698 int fnum = -1;
5699
5700 if (rettv_list_alloc(rettv) == OK)
5701 {
5702 l = rettv->vval.v_list;
5703 if (getcurpos)
5704 fp = &curwin->w_cursor;
5705 else
5706 fp = var2fpos(&argvars[0], TRUE, &fnum);
5707 if (fnum != -1)
5708 list_append_number(l, (varnumber_T)fnum);
5709 else
5710 list_append_number(l, (varnumber_T)0);
5711 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5712 : (varnumber_T)0);
5713 list_append_number(l, (fp != NULL)
5714 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5715 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005716 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005717 (varnumber_T)0);
5718 if (getcurpos)
5719 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005720 int save_set_curswant = curwin->w_set_curswant;
5721 colnr_T save_curswant = curwin->w_curswant;
5722 colnr_T save_virtcol = curwin->w_virtcol;
5723
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005724 update_curswant();
5725 list_append_number(l, curwin->w_curswant == MAXCOL ?
5726 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005727
5728 // Do not change "curswant", as it is unexpected that a get
5729 // function has a side effect.
5730 if (save_set_curswant)
5731 {
5732 curwin->w_set_curswant = save_set_curswant;
5733 curwin->w_curswant = save_curswant;
5734 curwin->w_virtcol = save_virtcol;
5735 curwin->w_valid &= ~VALID_VIRTCOL;
5736 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737 }
5738 }
5739 else
5740 rettv->vval.v_number = FALSE;
5741}
5742
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743/*
5744 * "getcurpos()" function
5745 */
5746 static void
5747f_getcurpos(typval_T *argvars, typval_T *rettv)
5748{
5749 getpos_both(argvars, rettv, TRUE);
5750}
5751
5752/*
5753 * "getpos(string)" function
5754 */
5755 static void
5756f_getpos(typval_T *argvars, typval_T *rettv)
5757{
5758 getpos_both(argvars, rettv, FALSE);
5759}
5760
5761/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005762 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005763 */
5764 static void
5765f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5766{
5767#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005768 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005769#endif
5770}
5771
5772/*
5773 * "getreg()" function
5774 */
5775 static void
5776f_getreg(typval_T *argvars, typval_T *rettv)
5777{
5778 char_u *strregname;
5779 int regname;
5780 int arg2 = FALSE;
5781 int return_list = FALSE;
5782 int error = FALSE;
5783
5784 if (argvars[0].v_type != VAR_UNKNOWN)
5785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005786 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005787 error = strregname == NULL;
5788 if (argvars[1].v_type != VAR_UNKNOWN)
5789 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005790 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005792 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005793 }
5794 }
5795 else
5796 strregname = get_vim_var_str(VV_REG);
5797
5798 if (error)
5799 return;
5800
5801 regname = (strregname == NULL ? '"' : *strregname);
5802 if (regname == 0)
5803 regname = '"';
5804
5805 if (return_list)
5806 {
5807 rettv->v_type = VAR_LIST;
5808 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5809 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5810 if (rettv->vval.v_list == NULL)
5811 (void)rettv_list_alloc(rettv);
5812 else
5813 ++rettv->vval.v_list->lv_refcount;
5814 }
5815 else
5816 {
5817 rettv->v_type = VAR_STRING;
5818 rettv->vval.v_string = get_reg_contents(regname,
5819 arg2 ? GREG_EXPR_SRC : 0);
5820 }
5821}
5822
5823/*
5824 * "getregtype()" function
5825 */
5826 static void
5827f_getregtype(typval_T *argvars, typval_T *rettv)
5828{
5829 char_u *strregname;
5830 int regname;
5831 char_u buf[NUMBUFLEN + 2];
5832 long reglen = 0;
5833
5834 if (argvars[0].v_type != VAR_UNKNOWN)
5835 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005836 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005837 if (strregname == NULL) /* type error; errmsg already given */
5838 {
5839 rettv->v_type = VAR_STRING;
5840 rettv->vval.v_string = NULL;
5841 return;
5842 }
5843 }
5844 else
5845 /* Default to v:register */
5846 strregname = get_vim_var_str(VV_REG);
5847
5848 regname = (strregname == NULL ? '"' : *strregname);
5849 if (regname == 0)
5850 regname = '"';
5851
5852 buf[0] = NUL;
5853 buf[1] = NUL;
5854 switch (get_reg_type(regname, &reglen))
5855 {
5856 case MLINE: buf[0] = 'V'; break;
5857 case MCHAR: buf[0] = 'v'; break;
5858 case MBLOCK:
5859 buf[0] = Ctrl_V;
5860 sprintf((char *)buf + 1, "%ld", reglen + 1);
5861 break;
5862 }
5863 rettv->v_type = VAR_STRING;
5864 rettv->vval.v_string = vim_strsave(buf);
5865}
5866
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005867/*
5868 * Returns information (variables, options, etc.) about a tab page
5869 * as a dictionary.
5870 */
5871 static dict_T *
5872get_tabpage_info(tabpage_T *tp, int tp_idx)
5873{
5874 win_T *wp;
5875 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005876 list_T *l;
5877
5878 dict = dict_alloc();
5879 if (dict == NULL)
5880 return NULL;
5881
Bram Moolenaare0be1672018-07-08 16:50:37 +02005882 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005883
5884 l = list_alloc();
5885 if (l != NULL)
5886 {
5887 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5888 wp; wp = wp->w_next)
5889 list_append_number(l, (varnumber_T)wp->w_id);
5890 dict_add_list(dict, "windows", l);
5891 }
5892
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005893 /* Make a reference to tabpage variables */
5894 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005895
5896 return dict;
5897}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005898
5899/*
5900 * "gettabinfo()" function
5901 */
5902 static void
5903f_gettabinfo(typval_T *argvars, typval_T *rettv)
5904{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005905 tabpage_T *tp, *tparg = NULL;
5906 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005907 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005908
5909 if (rettv_list_alloc(rettv) != OK)
5910 return;
5911
5912 if (argvars[0].v_type != VAR_UNKNOWN)
5913 {
5914 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005915 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005916 if (tparg == NULL)
5917 return;
5918 }
5919
5920 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005921 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005922 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005923 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005924 if (tparg != NULL && tp != tparg)
5925 continue;
5926 d = get_tabpage_info(tp, tpnr);
5927 if (d != NULL)
5928 list_append_dict(rettv->vval.v_list, d);
5929 if (tparg != NULL)
5930 return;
5931 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005932}
5933
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934/*
5935 * "gettabvar()" function
5936 */
5937 static void
5938f_gettabvar(typval_T *argvars, typval_T *rettv)
5939{
5940 win_T *oldcurwin;
5941 tabpage_T *tp, *oldtabpage;
5942 dictitem_T *v;
5943 char_u *varname;
5944 int done = FALSE;
5945
5946 rettv->v_type = VAR_STRING;
5947 rettv->vval.v_string = NULL;
5948
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005949 varname = tv_get_string_chk(&argvars[1]);
5950 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005951 if (tp != NULL && varname != NULL)
5952 {
5953 /* Set tp to be our tabpage, temporarily. Also set the window to the
5954 * first window in the tabpage, otherwise the window is not valid. */
5955 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005956 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5957 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005958 {
5959 /* look up the variable */
5960 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5961 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5962 if (v != NULL)
5963 {
5964 copy_tv(&v->di_tv, rettv);
5965 done = TRUE;
5966 }
5967 }
5968
5969 /* restore previous notion of curwin */
5970 restore_win(oldcurwin, oldtabpage, TRUE);
5971 }
5972
5973 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5974 copy_tv(&argvars[2], rettv);
5975}
5976
5977/*
5978 * "gettabwinvar()" function
5979 */
5980 static void
5981f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5982{
5983 getwinvar(argvars, rettv, 1);
5984}
5985
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005986/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005987 * "gettagstack()" function
5988 */
5989 static void
5990f_gettagstack(typval_T *argvars, typval_T *rettv)
5991{
5992 win_T *wp = curwin; // default is current window
5993
5994 if (rettv_dict_alloc(rettv) != OK)
5995 return;
5996
5997 if (argvars[0].v_type != VAR_UNKNOWN)
5998 {
5999 wp = find_win_by_nr_or_id(&argvars[0]);
6000 if (wp == NULL)
6001 return;
6002 }
6003
6004 get_tagstack(wp, rettv->vval.v_dict);
6005}
6006
6007/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006008 * Returns information about a window as a dictionary.
6009 */
6010 static dict_T *
6011get_win_info(win_T *wp, short tpnr, short winnr)
6012{
6013 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006014
6015 dict = dict_alloc();
6016 if (dict == NULL)
6017 return NULL;
6018
Bram Moolenaare0be1672018-07-08 16:50:37 +02006019 dict_add_number(dict, "tabnr", tpnr);
6020 dict_add_number(dict, "winnr", winnr);
6021 dict_add_number(dict, "winid", wp->w_id);
6022 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02006023 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01006024 dict_add_number(dict, "topline", wp->w_topline);
6025 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02006026#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02006027 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02006028#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02006029 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02006030 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02006031 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006032
Bram Moolenaar69905d12017-08-13 18:14:47 +02006033#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02006034 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02006035#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02006036#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02006037 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
6038 dict_add_number(dict, "loclist",
6039 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02006040#endif
6041
Bram Moolenaar30567352016-08-27 21:25:44 +02006042 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02006043 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006044
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006045 return dict;
6046}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006047
6048/*
6049 * "getwininfo()" function
6050 */
6051 static void
6052f_getwininfo(typval_T *argvars, typval_T *rettv)
6053{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006054 tabpage_T *tp;
6055 win_T *wp = NULL, *wparg = NULL;
6056 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02006057 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006058
6059 if (rettv_list_alloc(rettv) != OK)
6060 return;
6061
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006062 if (argvars[0].v_type != VAR_UNKNOWN)
6063 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01006064 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006065 if (wparg == NULL)
6066 return;
6067 }
6068
6069 /* Collect information about either all the windows across all the tab
6070 * pages or one particular window.
6071 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02006072 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006073 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02006074 tabnr++;
6075 winnr = 0;
6076 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006077 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02006078 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006079 if (wparg != NULL && wp != wparg)
6080 continue;
6081 d = get_win_info(wp, tabnr, winnr);
6082 if (d != NULL)
6083 list_append_dict(rettv->vval.v_list, d);
6084 if (wparg != NULL)
6085 /* found information about a specific window */
6086 return;
6087 }
6088 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006089}
6090
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006091/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006092 * "win_findbuf()" function
6093 */
6094 static void
6095f_win_findbuf(typval_T *argvars, typval_T *rettv)
6096{
6097 if (rettv_list_alloc(rettv) != FAIL)
6098 win_findbuf(argvars, rettv->vval.v_list);
6099}
6100
6101/*
6102 * "win_getid()" function
6103 */
6104 static void
6105f_win_getid(typval_T *argvars, typval_T *rettv)
6106{
6107 rettv->vval.v_number = win_getid(argvars);
6108}
6109
6110/*
6111 * "win_gotoid()" function
6112 */
6113 static void
6114f_win_gotoid(typval_T *argvars, typval_T *rettv)
6115{
6116 rettv->vval.v_number = win_gotoid(argvars);
6117}
6118
6119/*
6120 * "win_id2tabwin()" function
6121 */
6122 static void
6123f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
6124{
6125 if (rettv_list_alloc(rettv) != FAIL)
6126 win_id2tabwin(argvars, rettv->vval.v_list);
6127}
6128
6129/*
6130 * "win_id2win()" function
6131 */
6132 static void
6133f_win_id2win(typval_T *argvars, typval_T *rettv)
6134{
6135 rettv->vval.v_number = win_id2win(argvars);
6136}
6137
6138/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01006139 * "win_screenpos()" function
6140 */
6141 static void
6142f_win_screenpos(typval_T *argvars, typval_T *rettv)
6143{
6144 win_T *wp;
6145
6146 if (rettv_list_alloc(rettv) == FAIL)
6147 return;
6148
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02006149 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01006150 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
6151 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
6152}
6153
6154/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006155 * "getwinpos({timeout})" function
6156 */
6157 static void
6158f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
6159{
6160 int x = -1;
6161 int y = -1;
6162
6163 if (rettv_list_alloc(rettv) == FAIL)
6164 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006165#if defined(FEAT_GUI) \
6166 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6167 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006168 {
6169 varnumber_T timeout = 100;
6170
6171 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006172 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006173
6174 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006175 }
6176#endif
6177 list_append_number(rettv->vval.v_list, (varnumber_T)x);
6178 list_append_number(rettv->vval.v_list, (varnumber_T)y);
6179}
6180
6181
6182/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006183 * "getwinposx()" function
6184 */
6185 static void
6186f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
6187{
6188 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006189#if defined(FEAT_GUI) \
6190 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6191 || defined(MSWIN)
6192
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006193 {
6194 int x, y;
6195
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006196 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006197 rettv->vval.v_number = x;
6198 }
6199#endif
6200}
6201
6202/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006203 * "getwinposy()" function
6204 */
6205 static void
6206f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6207{
6208 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006209#if defined(FEAT_GUI) \
6210 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6211 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212 {
6213 int x, y;
6214
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006215 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006216 rettv->vval.v_number = y;
6217 }
6218#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006219}
6220
6221/*
6222 * "getwinvar()" function
6223 */
6224 static void
6225f_getwinvar(typval_T *argvars, typval_T *rettv)
6226{
6227 getwinvar(argvars, rettv, 0);
6228}
6229
6230/*
6231 * "glob()" function
6232 */
6233 static void
6234f_glob(typval_T *argvars, typval_T *rettv)
6235{
6236 int options = WILD_SILENT|WILD_USE_NL;
6237 expand_T xpc;
6238 int error = FALSE;
6239
6240 /* When the optional second argument is non-zero, don't remove matches
6241 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6242 rettv->v_type = VAR_STRING;
6243 if (argvars[1].v_type != VAR_UNKNOWN)
6244 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006245 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006246 options |= WILD_KEEP_ALL;
6247 if (argvars[2].v_type != VAR_UNKNOWN)
6248 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006249 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006250 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006251 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006252 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006253 options |= WILD_ALLLINKS;
6254 }
6255 }
6256 if (!error)
6257 {
6258 ExpandInit(&xpc);
6259 xpc.xp_context = EXPAND_FILES;
6260 if (p_wic)
6261 options += WILD_ICASE;
6262 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006263 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264 NULL, options, WILD_ALL);
6265 else if (rettv_list_alloc(rettv) != FAIL)
6266 {
6267 int i;
6268
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006269 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 NULL, options, WILD_ALL_KEEP);
6271 for (i = 0; i < xpc.xp_numfiles; i++)
6272 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6273
6274 ExpandCleanup(&xpc);
6275 }
6276 }
6277 else
6278 rettv->vval.v_string = NULL;
6279}
6280
6281/*
6282 * "globpath()" function
6283 */
6284 static void
6285f_globpath(typval_T *argvars, typval_T *rettv)
6286{
6287 int flags = 0;
6288 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006289 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 int error = FALSE;
6291 garray_T ga;
6292 int i;
6293
6294 /* When the optional second argument is non-zero, don't remove matches
6295 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6296 rettv->v_type = VAR_STRING;
6297 if (argvars[2].v_type != VAR_UNKNOWN)
6298 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006299 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 flags |= WILD_KEEP_ALL;
6301 if (argvars[3].v_type != VAR_UNKNOWN)
6302 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006303 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006304 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006305 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006306 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 flags |= WILD_ALLLINKS;
6308 }
6309 }
6310 if (file != NULL && !error)
6311 {
6312 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006313 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006314 if (rettv->v_type == VAR_STRING)
6315 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6316 else if (rettv_list_alloc(rettv) != FAIL)
6317 for (i = 0; i < ga.ga_len; ++i)
6318 list_append_string(rettv->vval.v_list,
6319 ((char_u **)(ga.ga_data))[i], -1);
6320 ga_clear_strings(&ga);
6321 }
6322 else
6323 rettv->vval.v_string = NULL;
6324}
6325
6326/*
6327 * "glob2regpat()" function
6328 */
6329 static void
6330f_glob2regpat(typval_T *argvars, typval_T *rettv)
6331{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006332 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333
6334 rettv->v_type = VAR_STRING;
6335 rettv->vval.v_string = (pat == NULL)
6336 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6337}
6338
6339/* for VIM_VERSION_ defines */
6340#include "version.h"
6341
6342/*
6343 * "has()" function
6344 */
6345 static void
6346f_has(typval_T *argvars, typval_T *rettv)
6347{
6348 int i;
6349 char_u *name;
6350 int n = FALSE;
6351 static char *(has_list[]) =
6352 {
6353#ifdef AMIGA
6354 "amiga",
6355# ifdef FEAT_ARP
6356 "arp",
6357# endif
6358#endif
6359#ifdef __BEOS__
6360 "beos",
6361#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006362#if defined(BSD) && !defined(MACOS_X)
6363 "bsd",
6364#endif
6365#ifdef hpux
6366 "hpux",
6367#endif
6368#ifdef __linux__
6369 "linux",
6370#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006371#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006372 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6373 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006374# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006375 "macunix", /* Mac OS X, with the darwin feature */
6376 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006377# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006378#endif
6379#ifdef __QNX__
6380 "qnx",
6381#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006382#ifdef SUN_SYSTEM
6383 "sun",
6384#else
6385 "moon",
6386#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387#ifdef UNIX
6388 "unix",
6389#endif
6390#ifdef VMS
6391 "vms",
6392#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006393#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394 "win32",
6395#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006396#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006397 "win32unix",
6398#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006399#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 "win64",
6401#endif
6402#ifdef EBCDIC
6403 "ebcdic",
6404#endif
6405#ifndef CASE_INSENSITIVE_FILENAME
6406 "fname_case",
6407#endif
6408#ifdef HAVE_ACL
6409 "acl",
6410#endif
6411#ifdef FEAT_ARABIC
6412 "arabic",
6413#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006414 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006415#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006416 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006417#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006418#ifdef FEAT_AUTOSERVERNAME
6419 "autoservername",
6420#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006421#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006423# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424 "balloon_multiline",
6425# endif
6426#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006427#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006428 "balloon_eval_term",
6429#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6431 "builtin_terms",
6432# ifdef ALL_BUILTIN_TCAPS
6433 "all_builtin_terms",
6434# endif
6435#endif
6436#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006437 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006438 || defined(FEAT_GUI_MOTIF))
6439 "browsefilter",
6440#endif
6441#ifdef FEAT_BYTEOFF
6442 "byte_offset",
6443#endif
6444#ifdef FEAT_JOB_CHANNEL
6445 "channel",
6446#endif
6447#ifdef FEAT_CINDENT
6448 "cindent",
6449#endif
6450#ifdef FEAT_CLIENTSERVER
6451 "clientserver",
6452#endif
6453#ifdef FEAT_CLIPBOARD
6454 "clipboard",
6455#endif
6456#ifdef FEAT_CMDL_COMPL
6457 "cmdline_compl",
6458#endif
6459#ifdef FEAT_CMDHIST
6460 "cmdline_hist",
6461#endif
6462#ifdef FEAT_COMMENTS
6463 "comments",
6464#endif
6465#ifdef FEAT_CONCEAL
6466 "conceal",
6467#endif
6468#ifdef FEAT_CRYPT
6469 "cryptv",
6470 "crypt-blowfish",
6471 "crypt-blowfish2",
6472#endif
6473#ifdef FEAT_CSCOPE
6474 "cscope",
6475#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477#ifdef CURSOR_SHAPE
6478 "cursorshape",
6479#endif
6480#ifdef DEBUG
6481 "debug",
6482#endif
6483#ifdef FEAT_CON_DIALOG
6484 "dialog_con",
6485#endif
6486#ifdef FEAT_GUI_DIALOG
6487 "dialog_gui",
6488#endif
6489#ifdef FEAT_DIFF
6490 "diff",
6491#endif
6492#ifdef FEAT_DIGRAPHS
6493 "digraphs",
6494#endif
6495#ifdef FEAT_DIRECTX
6496 "directx",
6497#endif
6498#ifdef FEAT_DND
6499 "dnd",
6500#endif
6501#ifdef FEAT_EMACS_TAGS
6502 "emacs_tags",
6503#endif
6504 "eval", /* always present, of course! */
6505 "ex_extra", /* graduated feature */
6506#ifdef FEAT_SEARCH_EXTRA
6507 "extra_search",
6508#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006509#ifdef FEAT_SEARCHPATH
6510 "file_in_path",
6511#endif
6512#ifdef FEAT_FILTERPIPE
6513 "filterpipe",
6514#endif
6515#ifdef FEAT_FIND_ID
6516 "find_in_path",
6517#endif
6518#ifdef FEAT_FLOAT
6519 "float",
6520#endif
6521#ifdef FEAT_FOLDING
6522 "folding",
6523#endif
6524#ifdef FEAT_FOOTER
6525 "footer",
6526#endif
6527#if !defined(USE_SYSTEM) && defined(UNIX)
6528 "fork",
6529#endif
6530#ifdef FEAT_GETTEXT
6531 "gettext",
6532#endif
6533#ifdef FEAT_GUI
6534 "gui",
6535#endif
6536#ifdef FEAT_GUI_ATHENA
6537# ifdef FEAT_GUI_NEXTAW
6538 "gui_neXtaw",
6539# else
6540 "gui_athena",
6541# endif
6542#endif
6543#ifdef FEAT_GUI_GTK
6544 "gui_gtk",
6545# ifdef USE_GTK3
6546 "gui_gtk3",
6547# else
6548 "gui_gtk2",
6549# endif
6550#endif
6551#ifdef FEAT_GUI_GNOME
6552 "gui_gnome",
6553#endif
6554#ifdef FEAT_GUI_MAC
6555 "gui_mac",
6556#endif
6557#ifdef FEAT_GUI_MOTIF
6558 "gui_motif",
6559#endif
6560#ifdef FEAT_GUI_PHOTON
6561 "gui_photon",
6562#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006563#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006564 "gui_win32",
6565#endif
6566#ifdef FEAT_HANGULIN
6567 "hangul_input",
6568#endif
6569#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6570 "iconv",
6571#endif
6572#ifdef FEAT_INS_EXPAND
6573 "insert_expand",
6574#endif
6575#ifdef FEAT_JOB_CHANNEL
6576 "job",
6577#endif
6578#ifdef FEAT_JUMPLIST
6579 "jumplist",
6580#endif
6581#ifdef FEAT_KEYMAP
6582 "keymap",
6583#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006584 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006585#ifdef FEAT_LANGMAP
6586 "langmap",
6587#endif
6588#ifdef FEAT_LIBCALL
6589 "libcall",
6590#endif
6591#ifdef FEAT_LINEBREAK
6592 "linebreak",
6593#endif
6594#ifdef FEAT_LISP
6595 "lispindent",
6596#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006598#ifdef FEAT_LOCALMAP
6599 "localmap",
6600#endif
6601#ifdef FEAT_LUA
6602# ifndef DYNAMIC_LUA
6603 "lua",
6604# endif
6605#endif
6606#ifdef FEAT_MENU
6607 "menu",
6608#endif
6609#ifdef FEAT_SESSION
6610 "mksession",
6611#endif
6612#ifdef FEAT_MODIFY_FNAME
6613 "modify_fname",
6614#endif
6615#ifdef FEAT_MOUSE
6616 "mouse",
6617#endif
6618#ifdef FEAT_MOUSESHAPE
6619 "mouseshape",
6620#endif
6621#if defined(UNIX) || defined(VMS)
6622# ifdef FEAT_MOUSE_DEC
6623 "mouse_dec",
6624# endif
6625# ifdef FEAT_MOUSE_GPM
6626 "mouse_gpm",
6627# endif
6628# ifdef FEAT_MOUSE_JSB
6629 "mouse_jsbterm",
6630# endif
6631# ifdef FEAT_MOUSE_NET
6632 "mouse_netterm",
6633# endif
6634# ifdef FEAT_MOUSE_PTERM
6635 "mouse_pterm",
6636# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006637# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006638 "mouse_sgr",
6639# endif
6640# ifdef FEAT_SYSMOUSE
6641 "mouse_sysmouse",
6642# endif
6643# ifdef FEAT_MOUSE_URXVT
6644 "mouse_urxvt",
6645# endif
6646# ifdef FEAT_MOUSE_XTERM
6647 "mouse_xterm",
6648# endif
6649#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651#ifdef FEAT_MBYTE_IME
6652 "multi_byte_ime",
6653#endif
6654#ifdef FEAT_MULTI_LANG
6655 "multi_lang",
6656#endif
6657#ifdef FEAT_MZSCHEME
6658#ifndef DYNAMIC_MZSCHEME
6659 "mzscheme",
6660#endif
6661#endif
6662#ifdef FEAT_NUM64
6663 "num64",
6664#endif
6665#ifdef FEAT_OLE
6666 "ole",
6667#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006668#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006669 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006670#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671#ifdef FEAT_PATH_EXTRA
6672 "path_extra",
6673#endif
6674#ifdef FEAT_PERL
6675#ifndef DYNAMIC_PERL
6676 "perl",
6677#endif
6678#endif
6679#ifdef FEAT_PERSISTENT_UNDO
6680 "persistent_undo",
6681#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006682#if defined(FEAT_PYTHON)
6683 "python_compiled",
6684# if defined(DYNAMIC_PYTHON)
6685 "python_dynamic",
6686# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006687 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006688 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006689# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006691#if defined(FEAT_PYTHON3)
6692 "python3_compiled",
6693# if defined(DYNAMIC_PYTHON3)
6694 "python3_dynamic",
6695# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006696 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006697 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006698# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699#endif
6700#ifdef FEAT_POSTSCRIPT
6701 "postscript",
6702#endif
6703#ifdef FEAT_PRINTER
6704 "printer",
6705#endif
6706#ifdef FEAT_PROFILE
6707 "profile",
6708#endif
6709#ifdef FEAT_RELTIME
6710 "reltime",
6711#endif
6712#ifdef FEAT_QUICKFIX
6713 "quickfix",
6714#endif
6715#ifdef FEAT_RIGHTLEFT
6716 "rightleft",
6717#endif
6718#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6719 "ruby",
6720#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006721 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722#ifdef FEAT_CMDL_INFO
6723 "showcmd",
6724 "cmdline_info",
6725#endif
6726#ifdef FEAT_SIGNS
6727 "signs",
6728#endif
6729#ifdef FEAT_SMARTINDENT
6730 "smartindent",
6731#endif
6732#ifdef STARTUPTIME
6733 "startuptime",
6734#endif
6735#ifdef FEAT_STL_OPT
6736 "statusline",
6737#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006738#ifdef FEAT_NETBEANS_INTG
6739 "netbeans_intg",
6740#endif
6741#ifdef FEAT_SPELL
6742 "spell",
6743#endif
6744#ifdef FEAT_SYN_HL
6745 "syntax",
6746#endif
6747#if defined(USE_SYSTEM) || !defined(UNIX)
6748 "system",
6749#endif
6750#ifdef FEAT_TAG_BINS
6751 "tag_binary",
6752#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006753#ifdef FEAT_TCL
6754# ifndef DYNAMIC_TCL
6755 "tcl",
6756# endif
6757#endif
6758#ifdef FEAT_TERMGUICOLORS
6759 "termguicolors",
6760#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006761#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006762 "terminal",
6763#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006764#ifdef TERMINFO
6765 "terminfo",
6766#endif
6767#ifdef FEAT_TERMRESPONSE
6768 "termresponse",
6769#endif
6770#ifdef FEAT_TEXTOBJ
6771 "textobjects",
6772#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006773#ifdef FEAT_TEXT_PROP
6774 "textprop",
6775#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776#ifdef HAVE_TGETENT
6777 "tgetent",
6778#endif
6779#ifdef FEAT_TIMERS
6780 "timers",
6781#endif
6782#ifdef FEAT_TITLE
6783 "title",
6784#endif
6785#ifdef FEAT_TOOLBAR
6786 "toolbar",
6787#endif
6788#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6789 "unnamedplus",
6790#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 "user-commands", /* was accidentally included in 5.4 */
6792 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006793#ifdef FEAT_VARTABS
6794 "vartabs",
6795#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006796 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797#ifdef FEAT_VIMINFO
6798 "viminfo",
6799#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006800 "vimscript-1",
6801 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006802 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006803 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006805 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006806 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006807#ifdef FEAT_VTP
6808 "vtp",
6809#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810#ifdef FEAT_WILDIGN
6811 "wildignore",
6812#endif
6813#ifdef FEAT_WILDMENU
6814 "wildmenu",
6815#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006816 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817#ifdef FEAT_WAK
6818 "winaltkeys",
6819#endif
6820#ifdef FEAT_WRITEBACKUP
6821 "writebackup",
6822#endif
6823#ifdef FEAT_XIM
6824 "xim",
6825#endif
6826#ifdef FEAT_XFONTSET
6827 "xfontset",
6828#endif
6829#ifdef FEAT_XPM_W32
6830 "xpm",
6831 "xpm_w32", /* for backward compatibility */
6832#else
6833# if defined(HAVE_XPM)
6834 "xpm",
6835# endif
6836#endif
6837#ifdef USE_XSMP
6838 "xsmp",
6839#endif
6840#ifdef USE_XSMP_INTERACT
6841 "xsmp_interact",
6842#endif
6843#ifdef FEAT_XCLIPBOARD
6844 "xterm_clipboard",
6845#endif
6846#ifdef FEAT_XTERM_SAVE
6847 "xterm_save",
6848#endif
6849#if defined(UNIX) && defined(FEAT_X11)
6850 "X11",
6851#endif
6852 NULL
6853 };
6854
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006855 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856 for (i = 0; has_list[i] != NULL; ++i)
6857 if (STRICMP(name, has_list[i]) == 0)
6858 {
6859 n = TRUE;
6860 break;
6861 }
6862
6863 if (n == FALSE)
6864 {
6865 if (STRNICMP(name, "patch", 5) == 0)
6866 {
6867 if (name[5] == '-'
6868 && STRLEN(name) >= 11
6869 && vim_isdigit(name[6])
6870 && vim_isdigit(name[8])
6871 && vim_isdigit(name[10]))
6872 {
6873 int major = atoi((char *)name + 6);
6874 int minor = atoi((char *)name + 8);
6875
6876 /* Expect "patch-9.9.01234". */
6877 n = (major < VIM_VERSION_MAJOR
6878 || (major == VIM_VERSION_MAJOR
6879 && (minor < VIM_VERSION_MINOR
6880 || (minor == VIM_VERSION_MINOR
6881 && has_patch(atoi((char *)name + 10))))));
6882 }
6883 else
6884 n = has_patch(atoi((char *)name + 5));
6885 }
6886 else if (STRICMP(name, "vim_starting") == 0)
6887 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006888 else if (STRICMP(name, "ttyin") == 0)
6889 n = mch_input_isatty();
6890 else if (STRICMP(name, "ttyout") == 0)
6891 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892 else if (STRICMP(name, "multi_byte_encoding") == 0)
6893 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006894#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895 else if (STRICMP(name, "balloon_multiline") == 0)
6896 n = multiline_balloon_available();
6897#endif
6898#ifdef DYNAMIC_TCL
6899 else if (STRICMP(name, "tcl") == 0)
6900 n = tcl_enabled(FALSE);
6901#endif
6902#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6903 else if (STRICMP(name, "iconv") == 0)
6904 n = iconv_enabled(FALSE);
6905#endif
6906#ifdef DYNAMIC_LUA
6907 else if (STRICMP(name, "lua") == 0)
6908 n = lua_enabled(FALSE);
6909#endif
6910#ifdef DYNAMIC_MZSCHEME
6911 else if (STRICMP(name, "mzscheme") == 0)
6912 n = mzscheme_enabled(FALSE);
6913#endif
6914#ifdef DYNAMIC_RUBY
6915 else if (STRICMP(name, "ruby") == 0)
6916 n = ruby_enabled(FALSE);
6917#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006918#ifdef DYNAMIC_PYTHON
6919 else if (STRICMP(name, "python") == 0)
6920 n = python_enabled(FALSE);
6921#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922#ifdef DYNAMIC_PYTHON3
6923 else if (STRICMP(name, "python3") == 0)
6924 n = python3_enabled(FALSE);
6925#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006926#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6927 else if (STRICMP(name, "pythonx") == 0)
6928 {
6929# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6930 if (p_pyx == 0)
6931 n = python3_enabled(FALSE) || python_enabled(FALSE);
6932 else if (p_pyx == 3)
6933 n = python3_enabled(FALSE);
6934 else if (p_pyx == 2)
6935 n = python_enabled(FALSE);
6936# elif defined(DYNAMIC_PYTHON)
6937 n = python_enabled(FALSE);
6938# elif defined(DYNAMIC_PYTHON3)
6939 n = python3_enabled(FALSE);
6940# endif
6941 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006942#endif
6943#ifdef DYNAMIC_PERL
6944 else if (STRICMP(name, "perl") == 0)
6945 n = perl_enabled(FALSE);
6946#endif
6947#ifdef FEAT_GUI
6948 else if (STRICMP(name, "gui_running") == 0)
6949 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950# ifdef FEAT_BROWSE
6951 else if (STRICMP(name, "browse") == 0)
6952 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6953# endif
6954#endif
6955#ifdef FEAT_SYN_HL
6956 else if (STRICMP(name, "syntax_items") == 0)
6957 n = syntax_present(curwin);
6958#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006959#ifdef FEAT_VTP
6960 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006961 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006962#endif
6963#ifdef FEAT_NETBEANS_INTG
6964 else if (STRICMP(name, "netbeans_enabled") == 0)
6965 n = netbeans_active();
6966#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006967#ifdef FEAT_MOUSE_GPM
6968 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6969 n = gpm_enabled();
6970#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006971#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006972 else if (STRICMP(name, "terminal") == 0)
6973 n = terminal_enabled();
6974#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006975#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006976 else if (STRICMP(name, "conpty") == 0)
6977 n = use_conpty();
6978#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979 }
6980
6981 rettv->vval.v_number = n;
6982}
6983
6984/*
6985 * "has_key()" function
6986 */
6987 static void
6988f_has_key(typval_T *argvars, typval_T *rettv)
6989{
6990 if (argvars[0].v_type != VAR_DICT)
6991 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006992 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006993 return;
6994 }
6995 if (argvars[0].vval.v_dict == NULL)
6996 return;
6997
6998 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006999 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007000}
7001
7002/*
7003 * "haslocaldir()" function
7004 */
7005 static void
7006f_haslocaldir(typval_T *argvars, typval_T *rettv)
7007{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02007008 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007009 win_T *wp = NULL;
7010
Bram Moolenaar00aa0692019-04-27 20:37:57 +02007011 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
7012
7013 // Check for window-local and tab-local directories
7014 if (wp != NULL && wp->w_localdir != NULL)
7015 rettv->vval.v_number = 1;
7016 else if (tp != NULL && tp->tp_localdir != NULL)
7017 rettv->vval.v_number = 2;
7018 else
7019 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020}
7021
7022/*
7023 * "hasmapto()" function
7024 */
7025 static void
7026f_hasmapto(typval_T *argvars, typval_T *rettv)
7027{
7028 char_u *name;
7029 char_u *mode;
7030 char_u buf[NUMBUFLEN];
7031 int abbr = FALSE;
7032
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007033 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 if (argvars[1].v_type == VAR_UNKNOWN)
7035 mode = (char_u *)"nvo";
7036 else
7037 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007038 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007040 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007041 }
7042
7043 if (map_to_exists(name, mode, abbr))
7044 rettv->vval.v_number = TRUE;
7045 else
7046 rettv->vval.v_number = FALSE;
7047}
7048
7049/*
7050 * "histadd()" function
7051 */
7052 static void
7053f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
7054{
7055#ifdef FEAT_CMDHIST
7056 int histype;
7057 char_u *str;
7058 char_u buf[NUMBUFLEN];
7059#endif
7060
7061 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007062 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 return;
7064#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007065 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066 histype = str != NULL ? get_histtype(str) : -1;
7067 if (histype >= 0)
7068 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007069 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070 if (*str != NUL)
7071 {
7072 init_history();
7073 add_to_history(histype, str, FALSE, NUL);
7074 rettv->vval.v_number = TRUE;
7075 return;
7076 }
7077 }
7078#endif
7079}
7080
7081/*
7082 * "histdel()" function
7083 */
7084 static void
7085f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7086{
7087#ifdef FEAT_CMDHIST
7088 int n;
7089 char_u buf[NUMBUFLEN];
7090 char_u *str;
7091
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007092 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007093 if (str == NULL)
7094 n = 0;
7095 else if (argvars[1].v_type == VAR_UNKNOWN)
7096 /* only one argument: clear entire history */
7097 n = clr_history(get_histtype(str));
7098 else if (argvars[1].v_type == VAR_NUMBER)
7099 /* index given: remove that entry */
7100 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007101 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007102 else
7103 /* string given: remove all matching entries */
7104 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007105 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007106 rettv->vval.v_number = n;
7107#endif
7108}
7109
7110/*
7111 * "histget()" function
7112 */
7113 static void
7114f_histget(typval_T *argvars UNUSED, typval_T *rettv)
7115{
7116#ifdef FEAT_CMDHIST
7117 int type;
7118 int idx;
7119 char_u *str;
7120
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007121 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007122 if (str == NULL)
7123 rettv->vval.v_string = NULL;
7124 else
7125 {
7126 type = get_histtype(str);
7127 if (argvars[1].v_type == VAR_UNKNOWN)
7128 idx = get_history_idx(type);
7129 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007130 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 /* -1 on type error */
7132 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
7133 }
7134#else
7135 rettv->vval.v_string = NULL;
7136#endif
7137 rettv->v_type = VAR_STRING;
7138}
7139
7140/*
7141 * "histnr()" function
7142 */
7143 static void
7144f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
7145{
7146 int i;
7147
7148#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007149 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150
7151 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
7152 if (i >= HIST_CMD && i < HIST_COUNT)
7153 i = get_history_idx(i);
7154 else
7155#endif
7156 i = -1;
7157 rettv->vval.v_number = i;
7158}
7159
7160/*
7161 * "highlightID(name)" function
7162 */
7163 static void
7164f_hlID(typval_T *argvars, typval_T *rettv)
7165{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007166 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007167}
7168
7169/*
7170 * "highlight_exists()" function
7171 */
7172 static void
7173f_hlexists(typval_T *argvars, typval_T *rettv)
7174{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007175 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007176}
7177
7178/*
7179 * "hostname()" function
7180 */
7181 static void
7182f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
7183{
7184 char_u hostname[256];
7185
7186 mch_get_host_name(hostname, 256);
7187 rettv->v_type = VAR_STRING;
7188 rettv->vval.v_string = vim_strsave(hostname);
7189}
7190
7191/*
7192 * iconv() function
7193 */
7194 static void
7195f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7196{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 char_u buf1[NUMBUFLEN];
7198 char_u buf2[NUMBUFLEN];
7199 char_u *from, *to, *str;
7200 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007201
7202 rettv->v_type = VAR_STRING;
7203 rettv->vval.v_string = NULL;
7204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007205 str = tv_get_string(&argvars[0]);
7206 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7207 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208 vimconv.vc_type = CONV_NONE;
7209 convert_setup(&vimconv, from, to);
7210
7211 /* If the encodings are equal, no conversion needed. */
7212 if (vimconv.vc_type == CONV_NONE)
7213 rettv->vval.v_string = vim_strsave(str);
7214 else
7215 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7216
7217 convert_setup(&vimconv, NULL, NULL);
7218 vim_free(from);
7219 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007220}
7221
7222/*
7223 * "indent()" function
7224 */
7225 static void
7226f_indent(typval_T *argvars, typval_T *rettv)
7227{
7228 linenr_T lnum;
7229
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007230 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007231 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7232 rettv->vval.v_number = get_indent_lnum(lnum);
7233 else
7234 rettv->vval.v_number = -1;
7235}
7236
7237/*
7238 * "index()" function
7239 */
7240 static void
7241f_index(typval_T *argvars, typval_T *rettv)
7242{
7243 list_T *l;
7244 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007245 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007246 long idx = 0;
7247 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007248 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249
7250 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007251 if (argvars[0].v_type == VAR_BLOB)
7252 {
7253 typval_T tv;
7254 int start = 0;
7255
7256 if (argvars[2].v_type != VAR_UNKNOWN)
7257 {
7258 start = tv_get_number_chk(&argvars[2], &error);
7259 if (error)
7260 return;
7261 }
7262 b = argvars[0].vval.v_blob;
7263 if (b == NULL)
7264 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007265 if (start < 0)
7266 {
7267 start = blob_len(b) + start;
7268 if (start < 0)
7269 start = 0;
7270 }
7271
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007272 for (idx = start; idx < blob_len(b); ++idx)
7273 {
7274 tv.v_type = VAR_NUMBER;
7275 tv.vval.v_number = blob_get(b, idx);
7276 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7277 {
7278 rettv->vval.v_number = idx;
7279 return;
7280 }
7281 }
7282 return;
7283 }
7284 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007286 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287 return;
7288 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007289
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007290 l = argvars[0].vval.v_list;
7291 if (l != NULL)
7292 {
7293 item = l->lv_first;
7294 if (argvars[2].v_type != VAR_UNKNOWN)
7295 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296 /* Start at specified item. Use the cached index that list_find()
7297 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007298 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007299 idx = l->lv_idx;
7300 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007301 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302 if (error)
7303 item = NULL;
7304 }
7305
7306 for ( ; item != NULL; item = item->li_next, ++idx)
7307 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7308 {
7309 rettv->vval.v_number = idx;
7310 break;
7311 }
7312 }
7313}
7314
7315static int inputsecret_flag = 0;
7316
7317/*
7318 * "input()" function
7319 * Also handles inputsecret() when inputsecret is set.
7320 */
7321 static void
7322f_input(typval_T *argvars, typval_T *rettv)
7323{
7324 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7325}
7326
7327/*
7328 * "inputdialog()" function
7329 */
7330 static void
7331f_inputdialog(typval_T *argvars, typval_T *rettv)
7332{
7333#if defined(FEAT_GUI_TEXTDIALOG)
7334 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7335 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7336 {
7337 char_u *message;
7338 char_u buf[NUMBUFLEN];
7339 char_u *defstr = (char_u *)"";
7340
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007341 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007343 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7345 else
7346 IObuff[0] = NUL;
7347 if (message != NULL && defstr != NULL
7348 && do_dialog(VIM_QUESTION, NULL, message,
7349 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7350 rettv->vval.v_string = vim_strsave(IObuff);
7351 else
7352 {
7353 if (message != NULL && defstr != NULL
7354 && argvars[1].v_type != VAR_UNKNOWN
7355 && argvars[2].v_type != VAR_UNKNOWN)
7356 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007357 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358 else
7359 rettv->vval.v_string = NULL;
7360 }
7361 rettv->v_type = VAR_STRING;
7362 }
7363 else
7364#endif
7365 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7366}
7367
7368/*
7369 * "inputlist()" function
7370 */
7371 static void
7372f_inputlist(typval_T *argvars, typval_T *rettv)
7373{
7374 listitem_T *li;
7375 int selected;
7376 int mouse_used;
7377
7378#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007379 /* While starting up, there is no place to enter text. When running tests
7380 * with --not-a-term we assume feedkeys() will be used. */
7381 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 return;
7383#endif
7384 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7385 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007386 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 return;
7388 }
7389
7390 msg_start();
7391 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7392 lines_left = Rows; /* avoid more prompt */
7393 msg_scroll = TRUE;
7394 msg_clr_eos();
7395
7396 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7397 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007398 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007399 msg_putchar('\n');
7400 }
7401
7402 /* Ask for choice. */
7403 selected = prompt_for_number(&mouse_used);
7404 if (mouse_used)
7405 selected -= lines_left;
7406
7407 rettv->vval.v_number = selected;
7408}
7409
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7411
7412/*
7413 * "inputrestore()" function
7414 */
7415 static void
7416f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7417{
7418 if (ga_userinput.ga_len > 0)
7419 {
7420 --ga_userinput.ga_len;
7421 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7422 + ga_userinput.ga_len);
7423 /* default return is zero == OK */
7424 }
7425 else if (p_verbose > 1)
7426 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007427 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 rettv->vval.v_number = 1; /* Failed */
7429 }
7430}
7431
7432/*
7433 * "inputsave()" function
7434 */
7435 static void
7436f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7437{
7438 /* Add an entry to the stack of typeahead storage. */
7439 if (ga_grow(&ga_userinput, 1) == OK)
7440 {
7441 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7442 + ga_userinput.ga_len);
7443 ++ga_userinput.ga_len;
7444 /* default return is zero == OK */
7445 }
7446 else
7447 rettv->vval.v_number = 1; /* Failed */
7448}
7449
7450/*
7451 * "inputsecret()" function
7452 */
7453 static void
7454f_inputsecret(typval_T *argvars, typval_T *rettv)
7455{
7456 ++cmdline_star;
7457 ++inputsecret_flag;
7458 f_input(argvars, rettv);
7459 --cmdline_star;
7460 --inputsecret_flag;
7461}
7462
7463/*
7464 * "insert()" function
7465 */
7466 static void
7467f_insert(typval_T *argvars, typval_T *rettv)
7468{
7469 long before = 0;
7470 listitem_T *item;
7471 list_T *l;
7472 int error = FALSE;
7473
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007474 if (argvars[0].v_type == VAR_BLOB)
7475 {
7476 int val, len;
7477 char_u *p;
7478
7479 len = blob_len(argvars[0].vval.v_blob);
7480 if (argvars[2].v_type != VAR_UNKNOWN)
7481 {
7482 before = (long)tv_get_number_chk(&argvars[2], &error);
7483 if (error)
7484 return; // type error; errmsg already given
7485 if (before < 0 || before > len)
7486 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007487 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007488 return;
7489 }
7490 }
7491 val = tv_get_number_chk(&argvars[1], &error);
7492 if (error)
7493 return;
7494 if (val < 0 || val > 255)
7495 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007496 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007497 return;
7498 }
7499
7500 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7501 return;
7502 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7503 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7504 *(p + before) = val;
7505 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7506
7507 copy_tv(&argvars[0], rettv);
7508 }
7509 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007510 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007511 else if ((l = argvars[0].vval.v_list) != NULL
7512 && !var_check_lock(l->lv_lock,
7513 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007514 {
7515 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007516 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 if (error)
7518 return; /* type error; errmsg already given */
7519
7520 if (before == l->lv_len)
7521 item = NULL;
7522 else
7523 {
7524 item = list_find(l, before);
7525 if (item == NULL)
7526 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007527 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007528 l = NULL;
7529 }
7530 }
7531 if (l != NULL)
7532 {
7533 list_insert_tv(l, &argvars[1], item);
7534 copy_tv(&argvars[0], rettv);
7535 }
7536 }
7537}
7538
7539/*
7540 * "invert(expr)" function
7541 */
7542 static void
7543f_invert(typval_T *argvars, typval_T *rettv)
7544{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007545 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546}
7547
7548/*
7549 * "isdirectory()" function
7550 */
7551 static void
7552f_isdirectory(typval_T *argvars, typval_T *rettv)
7553{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007554 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007555}
7556
7557/*
7558 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7559 * or it refers to a List or Dictionary that is locked.
7560 */
7561 static int
7562tv_islocked(typval_T *tv)
7563{
7564 return (tv->v_lock & VAR_LOCKED)
7565 || (tv->v_type == VAR_LIST
7566 && tv->vval.v_list != NULL
7567 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7568 || (tv->v_type == VAR_DICT
7569 && tv->vval.v_dict != NULL
7570 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7571}
7572
7573/*
7574 * "islocked()" function
7575 */
7576 static void
7577f_islocked(typval_T *argvars, typval_T *rettv)
7578{
7579 lval_T lv;
7580 char_u *end;
7581 dictitem_T *di;
7582
7583 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007584 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007585 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007586 if (end != NULL && lv.ll_name != NULL)
7587 {
7588 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007589 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590 else
7591 {
7592 if (lv.ll_tv == NULL)
7593 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007594 di = find_var(lv.ll_name, NULL, TRUE);
7595 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007596 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007597 /* Consider a variable locked when:
7598 * 1. the variable itself is locked
7599 * 2. the value of the variable is locked.
7600 * 3. the List or Dict value is locked.
7601 */
7602 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7603 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007604 }
7605 }
7606 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007607 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007609 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 else if (lv.ll_list != NULL)
7611 /* List item. */
7612 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7613 else
7614 /* Dictionary item. */
7615 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7616 }
7617 }
7618
7619 clear_lval(&lv);
7620}
7621
7622#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7623/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007624 * "isinf()" function
7625 */
7626 static void
7627f_isinf(typval_T *argvars, typval_T *rettv)
7628{
7629 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7630 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7631}
7632
7633/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634 * "isnan()" function
7635 */
7636 static void
7637f_isnan(typval_T *argvars, typval_T *rettv)
7638{
7639 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7640 && isnan(argvars[0].vval.v_float);
7641}
7642#endif
7643
7644/*
7645 * "items(dict)" function
7646 */
7647 static void
7648f_items(typval_T *argvars, typval_T *rettv)
7649{
7650 dict_list(argvars, rettv, 2);
7651}
7652
7653#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7654/*
7655 * Get the job from the argument.
7656 * Returns NULL if the job is invalid.
7657 */
7658 static job_T *
7659get_job_arg(typval_T *tv)
7660{
7661 job_T *job;
7662
7663 if (tv->v_type != VAR_JOB)
7664 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007665 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007666 return NULL;
7667 }
7668 job = tv->vval.v_job;
7669
7670 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007671 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 return job;
7673}
7674
7675/*
7676 * "job_getchannel()" function
7677 */
7678 static void
7679f_job_getchannel(typval_T *argvars, typval_T *rettv)
7680{
7681 job_T *job = get_job_arg(&argvars[0]);
7682
7683 if (job != NULL)
7684 {
7685 rettv->v_type = VAR_CHANNEL;
7686 rettv->vval.v_channel = job->jv_channel;
7687 if (job->jv_channel != NULL)
7688 ++job->jv_channel->ch_refcount;
7689 }
7690}
7691
7692/*
7693 * "job_info()" function
7694 */
7695 static void
7696f_job_info(typval_T *argvars, typval_T *rettv)
7697{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007698 if (argvars[0].v_type != VAR_UNKNOWN)
7699 {
7700 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007701
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007702 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7703 job_info(job, rettv->vval.v_dict);
7704 }
7705 else if (rettv_list_alloc(rettv) == OK)
7706 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007707}
7708
7709/*
7710 * "job_setoptions()" function
7711 */
7712 static void
7713f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7714{
7715 job_T *job = get_job_arg(&argvars[0]);
7716 jobopt_T opt;
7717
7718 if (job == NULL)
7719 return;
7720 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007721 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722 job_set_options(job, &opt);
7723 free_job_options(&opt);
7724}
7725
7726/*
7727 * "job_start()" function
7728 */
7729 static void
7730f_job_start(typval_T *argvars, typval_T *rettv)
7731{
7732 rettv->v_type = VAR_JOB;
7733 if (check_restricted() || check_secure())
7734 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007735 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736}
7737
7738/*
7739 * "job_status()" function
7740 */
7741 static void
7742f_job_status(typval_T *argvars, typval_T *rettv)
7743{
7744 job_T *job = get_job_arg(&argvars[0]);
7745
7746 if (job != NULL)
7747 {
7748 rettv->v_type = VAR_STRING;
7749 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7750 }
7751}
7752
7753/*
7754 * "job_stop()" function
7755 */
7756 static void
7757f_job_stop(typval_T *argvars, typval_T *rettv)
7758{
7759 job_T *job = get_job_arg(&argvars[0]);
7760
7761 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007762 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007763}
7764#endif
7765
7766/*
7767 * "join()" function
7768 */
7769 static void
7770f_join(typval_T *argvars, typval_T *rettv)
7771{
7772 garray_T ga;
7773 char_u *sep;
7774
7775 if (argvars[0].v_type != VAR_LIST)
7776 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007777 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778 return;
7779 }
7780 if (argvars[0].vval.v_list == NULL)
7781 return;
7782 if (argvars[1].v_type == VAR_UNKNOWN)
7783 sep = (char_u *)" ";
7784 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007785 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007786
7787 rettv->v_type = VAR_STRING;
7788
7789 if (sep != NULL)
7790 {
7791 ga_init2(&ga, (int)sizeof(char), 80);
7792 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7793 ga_append(&ga, NUL);
7794 rettv->vval.v_string = (char_u *)ga.ga_data;
7795 }
7796 else
7797 rettv->vval.v_string = NULL;
7798}
7799
7800/*
7801 * "js_decode()" function
7802 */
7803 static void
7804f_js_decode(typval_T *argvars, typval_T *rettv)
7805{
7806 js_read_T reader;
7807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007808 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809 reader.js_fill = NULL;
7810 reader.js_used = 0;
7811 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007812 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813}
7814
7815/*
7816 * "js_encode()" function
7817 */
7818 static void
7819f_js_encode(typval_T *argvars, typval_T *rettv)
7820{
7821 rettv->v_type = VAR_STRING;
7822 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7823}
7824
7825/*
7826 * "json_decode()" function
7827 */
7828 static void
7829f_json_decode(typval_T *argvars, typval_T *rettv)
7830{
7831 js_read_T reader;
7832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007833 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007834 reader.js_fill = NULL;
7835 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007836 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007837}
7838
7839/*
7840 * "json_encode()" function
7841 */
7842 static void
7843f_json_encode(typval_T *argvars, typval_T *rettv)
7844{
7845 rettv->v_type = VAR_STRING;
7846 rettv->vval.v_string = json_encode(&argvars[0], 0);
7847}
7848
7849/*
7850 * "keys()" function
7851 */
7852 static void
7853f_keys(typval_T *argvars, typval_T *rettv)
7854{
7855 dict_list(argvars, rettv, 0);
7856}
7857
7858/*
7859 * "last_buffer_nr()" function.
7860 */
7861 static void
7862f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7863{
7864 int n = 0;
7865 buf_T *buf;
7866
Bram Moolenaar29323592016-07-24 22:04:11 +02007867 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 if (n < buf->b_fnum)
7869 n = buf->b_fnum;
7870
7871 rettv->vval.v_number = n;
7872}
7873
7874/*
7875 * "len()" function
7876 */
7877 static void
7878f_len(typval_T *argvars, typval_T *rettv)
7879{
7880 switch (argvars[0].v_type)
7881 {
7882 case VAR_STRING:
7883 case VAR_NUMBER:
7884 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007885 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007886 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007887 case VAR_BLOB:
7888 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7889 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 case VAR_LIST:
7891 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7892 break;
7893 case VAR_DICT:
7894 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7895 break;
7896 case VAR_UNKNOWN:
7897 case VAR_SPECIAL:
7898 case VAR_FLOAT:
7899 case VAR_FUNC:
7900 case VAR_PARTIAL:
7901 case VAR_JOB:
7902 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007903 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 break;
7905 }
7906}
7907
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007909libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910{
7911#ifdef FEAT_LIBCALL
7912 char_u *string_in;
7913 char_u **string_result;
7914 int nr_result;
7915#endif
7916
7917 rettv->v_type = type;
7918 if (type != VAR_NUMBER)
7919 rettv->vval.v_string = NULL;
7920
7921 if (check_restricted() || check_secure())
7922 return;
7923
7924#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007925 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007926 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7927 {
7928 string_in = NULL;
7929 if (argvars[2].v_type == VAR_STRING)
7930 string_in = argvars[2].vval.v_string;
7931 if (type == VAR_NUMBER)
7932 string_result = NULL;
7933 else
7934 string_result = &rettv->vval.v_string;
7935 if (mch_libcall(argvars[0].vval.v_string,
7936 argvars[1].vval.v_string,
7937 string_in,
7938 argvars[2].vval.v_number,
7939 string_result,
7940 &nr_result) == OK
7941 && type == VAR_NUMBER)
7942 rettv->vval.v_number = nr_result;
7943 }
7944#endif
7945}
7946
7947/*
7948 * "libcall()" function
7949 */
7950 static void
7951f_libcall(typval_T *argvars, typval_T *rettv)
7952{
7953 libcall_common(argvars, rettv, VAR_STRING);
7954}
7955
7956/*
7957 * "libcallnr()" function
7958 */
7959 static void
7960f_libcallnr(typval_T *argvars, typval_T *rettv)
7961{
7962 libcall_common(argvars, rettv, VAR_NUMBER);
7963}
7964
7965/*
7966 * "line(string)" function
7967 */
7968 static void
7969f_line(typval_T *argvars, typval_T *rettv)
7970{
7971 linenr_T lnum = 0;
7972 pos_T *fp;
7973 int fnum;
7974
7975 fp = var2fpos(&argvars[0], TRUE, &fnum);
7976 if (fp != NULL)
7977 lnum = fp->lnum;
7978 rettv->vval.v_number = lnum;
7979}
7980
7981/*
7982 * "line2byte(lnum)" function
7983 */
7984 static void
7985f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7986{
7987#ifndef FEAT_BYTEOFF
7988 rettv->vval.v_number = -1;
7989#else
7990 linenr_T lnum;
7991
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007992 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7994 rettv->vval.v_number = -1;
7995 else
7996 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7997 if (rettv->vval.v_number >= 0)
7998 ++rettv->vval.v_number;
7999#endif
8000}
8001
8002/*
8003 * "lispindent(lnum)" function
8004 */
8005 static void
8006f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
8007{
8008#ifdef FEAT_LISP
8009 pos_T pos;
8010 linenr_T lnum;
8011
8012 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008013 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008014 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
8015 {
8016 curwin->w_cursor.lnum = lnum;
8017 rettv->vval.v_number = get_lisp_indent();
8018 curwin->w_cursor = pos;
8019 }
8020 else
8021#endif
8022 rettv->vval.v_number = -1;
8023}
8024
8025/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008026 * "list2str()" function
8027 */
8028 static void
8029f_list2str(typval_T *argvars, typval_T *rettv)
8030{
8031 list_T *l;
8032 listitem_T *li;
8033 garray_T ga;
8034 int utf8 = FALSE;
8035
8036 rettv->v_type = VAR_STRING;
8037 rettv->vval.v_string = NULL;
8038 if (argvars[0].v_type != VAR_LIST)
8039 {
8040 emsg(_(e_invarg));
8041 return;
8042 }
8043
8044 l = argvars[0].vval.v_list;
8045 if (l == NULL)
8046 return; // empty list results in empty string
8047
8048 if (argvars[1].v_type != VAR_UNKNOWN)
8049 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8050
8051 ga_init2(&ga, 1, 80);
8052 if (has_mbyte || utf8)
8053 {
8054 char_u buf[MB_MAXBYTES + 1];
8055 int (*char2bytes)(int, char_u *);
8056
8057 if (utf8 || enc_utf8)
8058 char2bytes = utf_char2bytes;
8059 else
8060 char2bytes = mb_char2bytes;
8061
8062 for (li = l->lv_first; li != NULL; li = li->li_next)
8063 {
8064 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
8065 ga_concat(&ga, buf);
8066 }
8067 ga_append(&ga, NUL);
8068 }
8069 else if (ga_grow(&ga, list_len(l) + 1) == OK)
8070 {
8071 for (li = l->lv_first; li != NULL; li = li->li_next)
8072 ga_append(&ga, tv_get_number(&li->li_tv));
8073 ga_append(&ga, NUL);
8074 }
8075
8076 rettv->v_type = VAR_STRING;
8077 rettv->vval.v_string = ga.ga_data;
8078}
8079
8080/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081 * "localtime()" function
8082 */
8083 static void
8084f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
8085{
8086 rettv->vval.v_number = (varnumber_T)time(NULL);
8087}
8088
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089 static void
8090get_maparg(typval_T *argvars, typval_T *rettv, int exact)
8091{
8092 char_u *keys;
8093 char_u *which;
8094 char_u buf[NUMBUFLEN];
8095 char_u *keys_buf = NULL;
8096 char_u *rhs;
8097 int mode;
8098 int abbr = FALSE;
8099 int get_dict = FALSE;
8100 mapblock_T *mp;
8101 int buffer_local;
8102
8103 /* return empty string for failure */
8104 rettv->v_type = VAR_STRING;
8105 rettv->vval.v_string = NULL;
8106
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008107 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008108 if (*keys == NUL)
8109 return;
8110
8111 if (argvars[1].v_type != VAR_UNKNOWN)
8112 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008113 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114 if (argvars[2].v_type != VAR_UNKNOWN)
8115 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008116 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008117 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008118 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 }
8120 }
8121 else
8122 which = (char_u *)"";
8123 if (which == NULL)
8124 return;
8125
8126 mode = get_map_mode(&which, 0);
8127
8128 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
8129 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
8130 vim_free(keys_buf);
8131
8132 if (!get_dict)
8133 {
8134 /* Return a string. */
8135 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02008136 {
8137 if (*rhs == NUL)
8138 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
8139 else
8140 rettv->vval.v_string = str2special_save(rhs, FALSE);
8141 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142
8143 }
8144 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
8145 {
8146 /* Return a dictionary. */
8147 char_u *lhs = str2special_save(mp->m_keys, TRUE);
8148 char_u *mapmode = map_mode_to_chars(mp->m_mode);
8149 dict_T *dict = rettv->vval.v_dict;
8150
Bram Moolenaare0be1672018-07-08 16:50:37 +02008151 dict_add_string(dict, "lhs", lhs);
8152 dict_add_string(dict, "rhs", mp->m_orig_str);
8153 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
8154 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
8155 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02008156 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
8157 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02008158 dict_add_number(dict, "buffer", (long)buffer_local);
8159 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
8160 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161
8162 vim_free(lhs);
8163 vim_free(mapmode);
8164 }
8165}
8166
8167#ifdef FEAT_FLOAT
8168/*
8169 * "log()" function
8170 */
8171 static void
8172f_log(typval_T *argvars, typval_T *rettv)
8173{
8174 float_T f = 0.0;
8175
8176 rettv->v_type = VAR_FLOAT;
8177 if (get_float_arg(argvars, &f) == OK)
8178 rettv->vval.v_float = log(f);
8179 else
8180 rettv->vval.v_float = 0.0;
8181}
8182
8183/*
8184 * "log10()" function
8185 */
8186 static void
8187f_log10(typval_T *argvars, typval_T *rettv)
8188{
8189 float_T f = 0.0;
8190
8191 rettv->v_type = VAR_FLOAT;
8192 if (get_float_arg(argvars, &f) == OK)
8193 rettv->vval.v_float = log10(f);
8194 else
8195 rettv->vval.v_float = 0.0;
8196}
8197#endif
8198
8199#ifdef FEAT_LUA
8200/*
8201 * "luaeval()" function
8202 */
8203 static void
8204f_luaeval(typval_T *argvars, typval_T *rettv)
8205{
8206 char_u *str;
8207 char_u buf[NUMBUFLEN];
8208
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008209 if (check_restricted() || check_secure())
8210 return;
8211
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008212 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 do_luaeval(str, argvars + 1, rettv);
8214}
8215#endif
8216
8217/*
8218 * "map()" function
8219 */
8220 static void
8221f_map(typval_T *argvars, typval_T *rettv)
8222{
8223 filter_map(argvars, rettv, TRUE);
8224}
8225
8226/*
8227 * "maparg()" function
8228 */
8229 static void
8230f_maparg(typval_T *argvars, typval_T *rettv)
8231{
8232 get_maparg(argvars, rettv, TRUE);
8233}
8234
8235/*
8236 * "mapcheck()" function
8237 */
8238 static void
8239f_mapcheck(typval_T *argvars, typval_T *rettv)
8240{
8241 get_maparg(argvars, rettv, FALSE);
8242}
8243
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008244typedef enum
8245{
8246 MATCH_END, /* matchend() */
8247 MATCH_MATCH, /* match() */
8248 MATCH_STR, /* matchstr() */
8249 MATCH_LIST, /* matchlist() */
8250 MATCH_POS /* matchstrpos() */
8251} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008252
8253 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008254find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008255{
8256 char_u *str = NULL;
8257 long len = 0;
8258 char_u *expr = NULL;
8259 char_u *pat;
8260 regmatch_T regmatch;
8261 char_u patbuf[NUMBUFLEN];
8262 char_u strbuf[NUMBUFLEN];
8263 char_u *save_cpo;
8264 long start = 0;
8265 long nth = 1;
8266 colnr_T startcol = 0;
8267 int match = 0;
8268 list_T *l = NULL;
8269 listitem_T *li = NULL;
8270 long idx = 0;
8271 char_u *tofree = NULL;
8272
8273 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8274 save_cpo = p_cpo;
8275 p_cpo = (char_u *)"";
8276
8277 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008278 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008280 /* type MATCH_LIST: return empty list when there are no matches.
8281 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008282 if (rettv_list_alloc(rettv) == FAIL)
8283 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008284 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008285 && (list_append_string(rettv->vval.v_list,
8286 (char_u *)"", 0) == FAIL
8287 || list_append_number(rettv->vval.v_list,
8288 (varnumber_T)-1) == FAIL
8289 || list_append_number(rettv->vval.v_list,
8290 (varnumber_T)-1) == FAIL
8291 || list_append_number(rettv->vval.v_list,
8292 (varnumber_T)-1) == FAIL))
8293 {
8294 list_free(rettv->vval.v_list);
8295 rettv->vval.v_list = NULL;
8296 goto theend;
8297 }
8298 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008299 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008300 {
8301 rettv->v_type = VAR_STRING;
8302 rettv->vval.v_string = NULL;
8303 }
8304
8305 if (argvars[0].v_type == VAR_LIST)
8306 {
8307 if ((l = argvars[0].vval.v_list) == NULL)
8308 goto theend;
8309 li = l->lv_first;
8310 }
8311 else
8312 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008313 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 len = (long)STRLEN(str);
8315 }
8316
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008317 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008318 if (pat == NULL)
8319 goto theend;
8320
8321 if (argvars[2].v_type != VAR_UNKNOWN)
8322 {
8323 int error = FALSE;
8324
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008325 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326 if (error)
8327 goto theend;
8328 if (l != NULL)
8329 {
8330 li = list_find(l, start);
8331 if (li == NULL)
8332 goto theend;
8333 idx = l->lv_idx; /* use the cached index */
8334 }
8335 else
8336 {
8337 if (start < 0)
8338 start = 0;
8339 if (start > len)
8340 goto theend;
8341 /* When "count" argument is there ignore matches before "start",
8342 * otherwise skip part of the string. Differs when pattern is "^"
8343 * or "\<". */
8344 if (argvars[3].v_type != VAR_UNKNOWN)
8345 startcol = start;
8346 else
8347 {
8348 str += start;
8349 len -= start;
8350 }
8351 }
8352
8353 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008354 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 if (error)
8356 goto theend;
8357 }
8358
8359 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8360 if (regmatch.regprog != NULL)
8361 {
8362 regmatch.rm_ic = p_ic;
8363
8364 for (;;)
8365 {
8366 if (l != NULL)
8367 {
8368 if (li == NULL)
8369 {
8370 match = FALSE;
8371 break;
8372 }
8373 vim_free(tofree);
8374 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8375 if (str == NULL)
8376 break;
8377 }
8378
8379 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8380
8381 if (match && --nth <= 0)
8382 break;
8383 if (l == NULL && !match)
8384 break;
8385
8386 /* Advance to just after the match. */
8387 if (l != NULL)
8388 {
8389 li = li->li_next;
8390 ++idx;
8391 }
8392 else
8393 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 startcol = (colnr_T)(regmatch.startp[0]
8395 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008396 if (startcol > (colnr_T)len
8397 || str + startcol <= regmatch.startp[0])
8398 {
8399 match = FALSE;
8400 break;
8401 }
8402 }
8403 }
8404
8405 if (match)
8406 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008407 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008408 {
8409 listitem_T *li1 = rettv->vval.v_list->lv_first;
8410 listitem_T *li2 = li1->li_next;
8411 listitem_T *li3 = li2->li_next;
8412 listitem_T *li4 = li3->li_next;
8413
8414 vim_free(li1->li_tv.vval.v_string);
8415 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8416 (int)(regmatch.endp[0] - regmatch.startp[0]));
8417 li3->li_tv.vval.v_number =
8418 (varnumber_T)(regmatch.startp[0] - expr);
8419 li4->li_tv.vval.v_number =
8420 (varnumber_T)(regmatch.endp[0] - expr);
8421 if (l != NULL)
8422 li2->li_tv.vval.v_number = (varnumber_T)idx;
8423 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008424 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008425 {
8426 int i;
8427
8428 /* return list with matched string and submatches */
8429 for (i = 0; i < NSUBEXP; ++i)
8430 {
8431 if (regmatch.endp[i] == NULL)
8432 {
8433 if (list_append_string(rettv->vval.v_list,
8434 (char_u *)"", 0) == FAIL)
8435 break;
8436 }
8437 else if (list_append_string(rettv->vval.v_list,
8438 regmatch.startp[i],
8439 (int)(regmatch.endp[i] - regmatch.startp[i]))
8440 == FAIL)
8441 break;
8442 }
8443 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008444 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008445 {
8446 /* return matched string */
8447 if (l != NULL)
8448 copy_tv(&li->li_tv, rettv);
8449 else
8450 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8451 (int)(regmatch.endp[0] - regmatch.startp[0]));
8452 }
8453 else if (l != NULL)
8454 rettv->vval.v_number = idx;
8455 else
8456 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008457 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458 rettv->vval.v_number =
8459 (varnumber_T)(regmatch.startp[0] - str);
8460 else
8461 rettv->vval.v_number =
8462 (varnumber_T)(regmatch.endp[0] - str);
8463 rettv->vval.v_number += (varnumber_T)(str - expr);
8464 }
8465 }
8466 vim_regfree(regmatch.regprog);
8467 }
8468
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008469theend:
8470 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 /* matchstrpos() without a list: drop the second item. */
8472 listitem_remove(rettv->vval.v_list,
8473 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008474 vim_free(tofree);
8475 p_cpo = save_cpo;
8476}
8477
8478/*
8479 * "match()" function
8480 */
8481 static void
8482f_match(typval_T *argvars, typval_T *rettv)
8483{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008484 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008485}
8486
Bram Moolenaar95e51472018-07-28 16:55:56 +02008487#ifdef FEAT_SEARCH_EXTRA
8488 static int
8489matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8490{
8491 dictitem_T *di;
8492
8493 if (tv->v_type != VAR_DICT)
8494 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008495 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008496 return FAIL;
8497 }
8498
8499 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008500 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008501 (char_u *)"conceal", FALSE);
8502
8503 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8504 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008505 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008506 if (*win == NULL)
8507 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01008508 emsg(_(e_invalwindow));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008509 return FAIL;
8510 }
8511 }
8512
8513 return OK;
8514}
8515#endif
8516
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008517/*
8518 * "matchadd()" function
8519 */
8520 static void
8521f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8522{
8523#ifdef FEAT_SEARCH_EXTRA
8524 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008525 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8526 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008527 int prio = 10; /* default priority */
8528 int id = -1;
8529 int error = FALSE;
8530 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008531 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008532
8533 rettv->vval.v_number = -1;
8534
8535 if (grp == NULL || pat == NULL)
8536 return;
8537 if (argvars[2].v_type != VAR_UNKNOWN)
8538 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008539 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008540 if (argvars[3].v_type != VAR_UNKNOWN)
8541 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008542 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008543 if (argvars[4].v_type != VAR_UNKNOWN
8544 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8545 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008546 }
8547 }
8548 if (error == TRUE)
8549 return;
8550 if (id >= 1 && id <= 3)
8551 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008552 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008553 return;
8554 }
8555
Bram Moolenaar95e51472018-07-28 16:55:56 +02008556 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557 conceal_char);
8558#endif
8559}
8560
8561/*
8562 * "matchaddpos()" function
8563 */
8564 static void
8565f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8566{
8567#ifdef FEAT_SEARCH_EXTRA
8568 char_u buf[NUMBUFLEN];
8569 char_u *group;
8570 int prio = 10;
8571 int id = -1;
8572 int error = FALSE;
8573 list_T *l;
8574 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008575 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008576
8577 rettv->vval.v_number = -1;
8578
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008579 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008580 if (group == NULL)
8581 return;
8582
8583 if (argvars[1].v_type != VAR_LIST)
8584 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008585 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008586 return;
8587 }
8588 l = argvars[1].vval.v_list;
8589 if (l == NULL)
8590 return;
8591
8592 if (argvars[2].v_type != VAR_UNKNOWN)
8593 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008594 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595 if (argvars[3].v_type != VAR_UNKNOWN)
8596 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008597 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008598
8599 if (argvars[4].v_type != VAR_UNKNOWN
8600 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8601 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008602 }
8603 }
8604 if (error == TRUE)
8605 return;
8606
8607 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8608 if (id == 1 || id == 2)
8609 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008610 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008611 return;
8612 }
8613
Bram Moolenaar95e51472018-07-28 16:55:56 +02008614 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008615 conceal_char);
8616#endif
8617}
8618
8619/*
8620 * "matcharg()" function
8621 */
8622 static void
8623f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8624{
8625 if (rettv_list_alloc(rettv) == OK)
8626 {
8627#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008628 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008629 matchitem_T *m;
8630
8631 if (id >= 1 && id <= 3)
8632 {
8633 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8634 {
8635 list_append_string(rettv->vval.v_list,
8636 syn_id2name(m->hlg_id), -1);
8637 list_append_string(rettv->vval.v_list, m->pattern, -1);
8638 }
8639 else
8640 {
8641 list_append_string(rettv->vval.v_list, NULL, -1);
8642 list_append_string(rettv->vval.v_list, NULL, -1);
8643 }
8644 }
8645#endif
8646 }
8647}
8648
8649/*
8650 * "matchdelete()" function
8651 */
8652 static void
8653f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8654{
8655#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01008656 win_T *win = get_optional_window(argvars, 1);
8657
8658 if (win == NULL)
8659 rettv->vval.v_number = -1;
8660 else
8661 rettv->vval.v_number = match_delete(win,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008662 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663#endif
8664}
8665
8666/*
8667 * "matchend()" function
8668 */
8669 static void
8670f_matchend(typval_T *argvars, typval_T *rettv)
8671{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008672 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008673}
8674
8675/*
8676 * "matchlist()" function
8677 */
8678 static void
8679f_matchlist(typval_T *argvars, typval_T *rettv)
8680{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008681 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008682}
8683
8684/*
8685 * "matchstr()" function
8686 */
8687 static void
8688f_matchstr(typval_T *argvars, typval_T *rettv)
8689{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008690 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691}
8692
8693/*
8694 * "matchstrpos()" function
8695 */
8696 static void
8697f_matchstrpos(typval_T *argvars, typval_T *rettv)
8698{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008699 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008700}
8701
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008702 static void
8703max_min(typval_T *argvars, typval_T *rettv, int domax)
8704{
8705 varnumber_T n = 0;
8706 varnumber_T i;
8707 int error = FALSE;
8708
8709 if (argvars[0].v_type == VAR_LIST)
8710 {
8711 list_T *l;
8712 listitem_T *li;
8713
8714 l = argvars[0].vval.v_list;
8715 if (l != NULL)
8716 {
8717 li = l->lv_first;
8718 if (li != NULL)
8719 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008720 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 for (;;)
8722 {
8723 li = li->li_next;
8724 if (li == NULL)
8725 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008726 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008727 if (domax ? i > n : i < n)
8728 n = i;
8729 }
8730 }
8731 }
8732 }
8733 else if (argvars[0].v_type == VAR_DICT)
8734 {
8735 dict_T *d;
8736 int first = TRUE;
8737 hashitem_T *hi;
8738 int todo;
8739
8740 d = argvars[0].vval.v_dict;
8741 if (d != NULL)
8742 {
8743 todo = (int)d->dv_hashtab.ht_used;
8744 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8745 {
8746 if (!HASHITEM_EMPTY(hi))
8747 {
8748 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008749 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008750 if (first)
8751 {
8752 n = i;
8753 first = FALSE;
8754 }
8755 else if (domax ? i > n : i < n)
8756 n = i;
8757 }
8758 }
8759 }
8760 }
8761 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008762 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008763 rettv->vval.v_number = error ? 0 : n;
8764}
8765
8766/*
8767 * "max()" function
8768 */
8769 static void
8770f_max(typval_T *argvars, typval_T *rettv)
8771{
8772 max_min(argvars, rettv, TRUE);
8773}
8774
8775/*
8776 * "min()" function
8777 */
8778 static void
8779f_min(typval_T *argvars, typval_T *rettv)
8780{
8781 max_min(argvars, rettv, FALSE);
8782}
8783
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008784/*
8785 * Create the directory in which "dir" is located, and higher levels when
8786 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008787 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008788 */
8789 static int
8790mkdir_recurse(char_u *dir, int prot)
8791{
8792 char_u *p;
8793 char_u *updir;
8794 int r = FAIL;
8795
8796 /* Get end of directory name in "dir".
8797 * We're done when it's "/" or "c:/". */
8798 p = gettail_sep(dir);
8799 if (p <= get_past_head(dir))
8800 return OK;
8801
8802 /* If the directory exists we're done. Otherwise: create it.*/
8803 updir = vim_strnsave(dir, (int)(p - dir));
8804 if (updir == NULL)
8805 return FAIL;
8806 if (mch_isdir(updir))
8807 r = OK;
8808 else if (mkdir_recurse(updir, prot) == OK)
8809 r = vim_mkdir_emsg(updir, prot);
8810 vim_free(updir);
8811 return r;
8812}
8813
8814#ifdef vim_mkdir
8815/*
8816 * "mkdir()" function
8817 */
8818 static void
8819f_mkdir(typval_T *argvars, typval_T *rettv)
8820{
8821 char_u *dir;
8822 char_u buf[NUMBUFLEN];
8823 int prot = 0755;
8824
8825 rettv->vval.v_number = FAIL;
8826 if (check_restricted() || check_secure())
8827 return;
8828
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008829 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008830 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008831 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008832
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008833 if (*gettail(dir) == NUL)
8834 /* remove trailing slashes */
8835 *gettail_sep(dir) = NUL;
8836
8837 if (argvars[1].v_type != VAR_UNKNOWN)
8838 {
8839 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008840 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008841 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008842 if (prot == -1)
8843 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008844 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008845 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008846 {
8847 if (mch_isdir(dir))
8848 {
8849 /* With the "p" flag it's OK if the dir already exists. */
8850 rettv->vval.v_number = OK;
8851 return;
8852 }
8853 mkdir_recurse(dir, prot);
8854 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008855 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008856 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008857}
8858#endif
8859
8860/*
8861 * "mode()" function
8862 */
8863 static void
8864f_mode(typval_T *argvars, typval_T *rettv)
8865{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008866 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008867
Bram Moolenaar612cc382018-07-29 15:34:26 +02008868 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008869
8870 if (time_for_testing == 93784)
8871 {
8872 /* Testing the two-character code. */
8873 buf[0] = 'x';
8874 buf[1] = '!';
8875 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008876#ifdef FEAT_TERMINAL
8877 else if (term_use_loop())
8878 buf[0] = 't';
8879#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880 else if (VIsual_active)
8881 {
8882 if (VIsual_select)
8883 buf[0] = VIsual_mode + 's' - 'v';
8884 else
8885 buf[0] = VIsual_mode;
8886 }
8887 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8888 || State == CONFIRM)
8889 {
8890 buf[0] = 'r';
8891 if (State == ASKMORE)
8892 buf[1] = 'm';
8893 else if (State == CONFIRM)
8894 buf[1] = '?';
8895 }
8896 else if (State == EXTERNCMD)
8897 buf[0] = '!';
8898 else if (State & INSERT)
8899 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008900 if (State & VREPLACE_FLAG)
8901 {
8902 buf[0] = 'R';
8903 buf[1] = 'v';
8904 }
8905 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008906 {
8907 if (State & REPLACE_FLAG)
8908 buf[0] = 'R';
8909 else
8910 buf[0] = 'i';
8911#ifdef FEAT_INS_EXPAND
8912 if (ins_compl_active())
8913 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008914 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008915 buf[1] = 'x';
8916#endif
8917 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008918 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008919 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008920 {
8921 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008922 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008923 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008924 else if (exmode_active == EXMODE_NORMAL)
8925 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008926 }
8927 else
8928 {
8929 buf[0] = 'n';
8930 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008931 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008932 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008933 // to be able to detect force-linewise/blockwise/characterwise operations
8934 buf[2] = motion_force;
8935 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008936 else if (restart_edit == 'I' || restart_edit == 'R'
8937 || restart_edit == 'V')
8938 {
8939 buf[1] = 'i';
8940 buf[2] = restart_edit;
8941 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 }
8943
8944 /* Clear out the minor mode when the argument is not a non-zero number or
8945 * non-empty string. */
8946 if (!non_zero_arg(&argvars[0]))
8947 buf[1] = NUL;
8948
8949 rettv->vval.v_string = vim_strsave(buf);
8950 rettv->v_type = VAR_STRING;
8951}
8952
8953#if defined(FEAT_MZSCHEME) || defined(PROTO)
8954/*
8955 * "mzeval()" function
8956 */
8957 static void
8958f_mzeval(typval_T *argvars, typval_T *rettv)
8959{
8960 char_u *str;
8961 char_u buf[NUMBUFLEN];
8962
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008963 if (check_restricted() || check_secure())
8964 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008965 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008966 do_mzeval(str, rettv);
8967}
8968
8969 void
8970mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8971{
8972 typval_T argvars[3];
8973
8974 argvars[0].v_type = VAR_STRING;
8975 argvars[0].vval.v_string = name;
8976 copy_tv(args, &argvars[1]);
8977 argvars[2].v_type = VAR_UNKNOWN;
8978 f_call(argvars, rettv);
8979 clear_tv(&argvars[1]);
8980}
8981#endif
8982
8983/*
8984 * "nextnonblank()" function
8985 */
8986 static void
8987f_nextnonblank(typval_T *argvars, typval_T *rettv)
8988{
8989 linenr_T lnum;
8990
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008991 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008992 {
8993 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8994 {
8995 lnum = 0;
8996 break;
8997 }
8998 if (*skipwhite(ml_get(lnum)) != NUL)
8999 break;
9000 }
9001 rettv->vval.v_number = lnum;
9002}
9003
9004/*
9005 * "nr2char()" function
9006 */
9007 static void
9008f_nr2char(typval_T *argvars, typval_T *rettv)
9009{
9010 char_u buf[NUMBUFLEN];
9011
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009012 if (has_mbyte)
9013 {
9014 int utf8 = 0;
9015
9016 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009017 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009018 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01009019 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009020 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009021 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009022 }
9023 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009024 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009025 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 buf[1] = NUL;
9027 }
9028 rettv->v_type = VAR_STRING;
9029 rettv->vval.v_string = vim_strsave(buf);
9030}
9031
9032/*
9033 * "or(expr, expr)" function
9034 */
9035 static void
9036f_or(typval_T *argvars, typval_T *rettv)
9037{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009038 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9039 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009040}
9041
9042/*
9043 * "pathshorten()" function
9044 */
9045 static void
9046f_pathshorten(typval_T *argvars, typval_T *rettv)
9047{
9048 char_u *p;
9049
9050 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009051 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009052 if (p == NULL)
9053 rettv->vval.v_string = NULL;
9054 else
9055 {
9056 p = vim_strsave(p);
9057 rettv->vval.v_string = p;
9058 if (p != NULL)
9059 shorten_dir(p);
9060 }
9061}
9062
9063#ifdef FEAT_PERL
9064/*
9065 * "perleval()" function
9066 */
9067 static void
9068f_perleval(typval_T *argvars, typval_T *rettv)
9069{
9070 char_u *str;
9071 char_u buf[NUMBUFLEN];
9072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009073 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009074 do_perleval(str, rettv);
9075}
9076#endif
9077
9078#ifdef FEAT_FLOAT
9079/*
9080 * "pow()" function
9081 */
9082 static void
9083f_pow(typval_T *argvars, typval_T *rettv)
9084{
9085 float_T fx = 0.0, fy = 0.0;
9086
9087 rettv->v_type = VAR_FLOAT;
9088 if (get_float_arg(argvars, &fx) == OK
9089 && get_float_arg(&argvars[1], &fy) == OK)
9090 rettv->vval.v_float = pow(fx, fy);
9091 else
9092 rettv->vval.v_float = 0.0;
9093}
9094#endif
9095
9096/*
9097 * "prevnonblank()" function
9098 */
9099 static void
9100f_prevnonblank(typval_T *argvars, typval_T *rettv)
9101{
9102 linenr_T lnum;
9103
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009104 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009105 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
9106 lnum = 0;
9107 else
9108 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
9109 --lnum;
9110 rettv->vval.v_number = lnum;
9111}
9112
9113/* This dummy va_list is here because:
9114 * - passing a NULL pointer doesn't work when va_list isn't a pointer
9115 * - locally in the function results in a "used before set" warning
9116 * - using va_start() to initialize it gives "function with fixed args" error */
9117static va_list ap;
9118
9119/*
9120 * "printf()" function
9121 */
9122 static void
9123f_printf(typval_T *argvars, typval_T *rettv)
9124{
9125 char_u buf[NUMBUFLEN];
9126 int len;
9127 char_u *s;
9128 int saved_did_emsg = did_emsg;
9129 char *fmt;
9130
9131 rettv->v_type = VAR_STRING;
9132 rettv->vval.v_string = NULL;
9133
9134 /* Get the required length, allocate the buffer and do it for real. */
9135 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009136 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02009137 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009138 if (!did_emsg)
9139 {
9140 s = alloc(len + 1);
9141 if (s != NULL)
9142 {
9143 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02009144 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
9145 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009146 }
9147 }
9148 did_emsg |= saved_did_emsg;
9149}
9150
Bram Moolenaarf2732452018-06-03 14:47:35 +02009151#ifdef FEAT_JOB_CHANNEL
9152/*
9153 * "prompt_setcallback({buffer}, {callback})" function
9154 */
9155 static void
9156f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
9157{
9158 buf_T *buf;
9159 char_u *callback;
9160 partial_T *partial;
9161
9162 if (check_secure())
9163 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009164 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02009165 if (buf == NULL)
9166 return;
9167
9168 callback = get_callback(&argvars[1], &partial);
9169 if (callback == NULL)
9170 return;
9171
9172 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
9173 if (partial == NULL)
9174 buf->b_prompt_callback = vim_strsave(callback);
9175 else
9176 /* pointer into the partial */
9177 buf->b_prompt_callback = callback;
9178 buf->b_prompt_partial = partial;
9179}
9180
9181/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02009182 * "prompt_setinterrupt({buffer}, {callback})" function
9183 */
9184 static void
9185f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
9186{
9187 buf_T *buf;
9188 char_u *callback;
9189 partial_T *partial;
9190
9191 if (check_secure())
9192 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009193 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02009194 if (buf == NULL)
9195 return;
9196
9197 callback = get_callback(&argvars[1], &partial);
9198 if (callback == NULL)
9199 return;
9200
9201 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
9202 if (partial == NULL)
9203 buf->b_prompt_interrupt = vim_strsave(callback);
9204 else
9205 /* pointer into the partial */
9206 buf->b_prompt_interrupt = callback;
9207 buf->b_prompt_int_partial = partial;
9208}
9209
9210/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02009211 * "prompt_setprompt({buffer}, {text})" function
9212 */
9213 static void
9214f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
9215{
9216 buf_T *buf;
9217 char_u *text;
9218
9219 if (check_secure())
9220 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009221 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02009222 if (buf == NULL)
9223 return;
9224
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009225 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02009226 vim_free(buf->b_prompt_text);
9227 buf->b_prompt_text = vim_strsave(text);
9228}
9229#endif
9230
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009231/*
9232 * "pumvisible()" function
9233 */
9234 static void
9235f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9236{
9237#ifdef FEAT_INS_EXPAND
9238 if (pum_visible())
9239 rettv->vval.v_number = 1;
9240#endif
9241}
9242
9243#ifdef FEAT_PYTHON3
9244/*
9245 * "py3eval()" function
9246 */
9247 static void
9248f_py3eval(typval_T *argvars, typval_T *rettv)
9249{
9250 char_u *str;
9251 char_u buf[NUMBUFLEN];
9252
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009253 if (check_restricted() || check_secure())
9254 return;
9255
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009256 if (p_pyx == 0)
9257 p_pyx = 3;
9258
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009259 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009260 do_py3eval(str, rettv);
9261}
9262#endif
9263
9264#ifdef FEAT_PYTHON
9265/*
9266 * "pyeval()" function
9267 */
9268 static void
9269f_pyeval(typval_T *argvars, typval_T *rettv)
9270{
9271 char_u *str;
9272 char_u buf[NUMBUFLEN];
9273
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009274 if (check_restricted() || check_secure())
9275 return;
9276
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009277 if (p_pyx == 0)
9278 p_pyx = 2;
9279
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009280 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009281 do_pyeval(str, rettv);
9282}
9283#endif
9284
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009285#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9286/*
9287 * "pyxeval()" function
9288 */
9289 static void
9290f_pyxeval(typval_T *argvars, typval_T *rettv)
9291{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009292 if (check_restricted() || check_secure())
9293 return;
9294
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009295# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9296 init_pyxversion();
9297 if (p_pyx == 2)
9298 f_pyeval(argvars, rettv);
9299 else
9300 f_py3eval(argvars, rettv);
9301# elif defined(FEAT_PYTHON)
9302 f_pyeval(argvars, rettv);
9303# elif defined(FEAT_PYTHON3)
9304 f_py3eval(argvars, rettv);
9305# endif
9306}
9307#endif
9308
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009309/*
9310 * "range()" function
9311 */
9312 static void
9313f_range(typval_T *argvars, typval_T *rettv)
9314{
9315 varnumber_T start;
9316 varnumber_T end;
9317 varnumber_T stride = 1;
9318 varnumber_T i;
9319 int error = FALSE;
9320
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009321 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009322 if (argvars[1].v_type == VAR_UNKNOWN)
9323 {
9324 end = start - 1;
9325 start = 0;
9326 }
9327 else
9328 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009329 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009330 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009331 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009332 }
9333
9334 if (error)
9335 return; /* type error; errmsg already given */
9336 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009337 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009338 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009339 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009340 else
9341 {
9342 if (rettv_list_alloc(rettv) == OK)
9343 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9344 if (list_append_number(rettv->vval.v_list,
9345 (varnumber_T)i) == FAIL)
9346 break;
9347 }
9348}
9349
9350/*
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009351 * Evaluate "expr" for readdir().
9352 */
9353 static int
9354readdir_checkitem(typval_T *expr, char_u *name)
9355{
9356 typval_T save_val;
9357 typval_T rettv;
9358 typval_T argv[2];
9359 int retval = 0;
9360 int error = FALSE;
9361
9362 prepare_vimvar(VV_VAL, &save_val);
9363 set_vim_var_string(VV_VAL, name, -1);
9364 argv[0].v_type = VAR_STRING;
9365 argv[0].vval.v_string = name;
9366
9367 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
9368 goto theend;
9369
9370 retval = tv_get_number_chk(&rettv, &error);
9371 if (error)
9372 retval = -1;
9373 clear_tv(&rettv);
9374
9375theend:
9376 set_vim_var_string(VV_VAL, NULL, 0);
9377 restore_vimvar(VV_VAL, &save_val);
9378 return retval;
9379}
9380
9381/*
9382 * "readdir()" function
9383 */
9384 static void
9385f_readdir(typval_T *argvars, typval_T *rettv)
9386{
9387 typval_T *expr;
9388 int failed = FALSE;
9389 char_u *path;
9390 garray_T ga;
9391 int i;
9392#ifdef MSWIN
9393 char_u *buf, *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009394 int ok;
9395 HANDLE hFind = INVALID_HANDLE_VALUE;
9396 WIN32_FIND_DATAW wfb;
9397 WCHAR *wn = NULL; // UCS-2 name, NULL when not used.
9398#endif
9399
9400 if (rettv_list_alloc(rettv) == FAIL)
9401 return;
9402 path = tv_get_string(&argvars[0]);
9403 expr = &argvars[1];
9404 ga_init2(&ga, (int)sizeof(char *), 20);
9405
9406#ifdef MSWIN
9407 buf = alloc((int)MAXPATHL);
9408 if (buf == NULL)
9409 return;
9410 STRNCPY(buf, path, MAXPATHL-5);
9411 p = vim_strpbrk(path, (char_u *)"\\/");
9412 if (p != NULL)
9413 *p = NUL;
9414 STRCAT(buf, "\\*");
9415
9416 wn = enc_to_utf16(buf, NULL);
9417 if (wn != NULL)
9418 hFind = FindFirstFileW(wn, &wfb);
9419 ok = (hFind != INVALID_HANDLE_VALUE);
9420 if (!ok)
9421 smsg(_(e_notopen), path);
9422 else
9423 {
9424 while (ok)
9425 {
9426 int ignore;
9427
9428 p = utf16_to_enc(wfb.cFileName, NULL); // p is allocated here
9429 if (p == NULL)
9430 break; // out of memory
9431
9432 ignore = p[0] == '.' && (p[1] == NUL
9433 || (p[1] == '.' && p[2] == NUL));
9434 if (!ignore && expr->v_type != VAR_UNKNOWN)
9435 {
9436 int r = readdir_checkitem(expr, p);
9437
9438 if (r < 0)
9439 {
9440 vim_free(p);
9441 break;
9442 }
9443 if (r == 0)
9444 ignore = TRUE;
9445 }
9446
9447 if (!ignore)
9448 {
9449 if (ga_grow(&ga, 1) == OK)
9450 ((char_u**)ga.ga_data)[ga.ga_len++] = vim_strsave(p);
9451 else
9452 {
9453 failed = TRUE;
9454 vim_free(p);
9455 break;
9456 }
9457 }
9458
9459 vim_free(p);
9460 ok = FindNextFileW(hFind, &wfb);
9461 }
9462 FindClose(hFind);
9463 }
9464
9465 vim_free(buf);
9466 vim_free(wn);
9467#else
9468 DIR *dirp;
9469 struct dirent *dp;
9470 char_u *p;
9471
9472 dirp = opendir((char *)path);
9473 if (dirp == NULL)
9474 smsg(_(e_notopen), path);
9475 else
9476 {
9477 for (;;)
9478 {
9479 int ignore;
9480
9481 dp = readdir(dirp);
9482 if (dp == NULL)
9483 break;
9484 p = (char_u *)dp->d_name;
9485
9486 ignore = p[0] == '.' &&
9487 (p[1] == NUL ||
9488 (p[1] == '.' && p[2] == NUL));
9489 if (!ignore && expr->v_type != VAR_UNKNOWN)
9490 {
9491 int r = readdir_checkitem(expr, p);
9492
9493 if (r < 0)
9494 break;
9495 if (r == 0)
9496 ignore = TRUE;
9497 }
9498
9499 if (!ignore)
9500 {
9501 if (ga_grow(&ga, 1) == OK)
9502 ((char_u**)ga.ga_data)[ga.ga_len++] = vim_strsave(p);
9503 else
9504 {
9505 failed = TRUE;
9506 break;
9507 }
9508 }
9509 }
9510
9511 closedir(dirp);
9512 }
9513#endif
9514
Bram Moolenaar334ad412019-04-19 15:20:46 +02009515 if (!failed && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009516 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009517 sort_strings((char_u **)ga.ga_data, ga.ga_len);
9518 for (i = 0; i < ga.ga_len; i++)
9519 {
9520 p = ((char_u **)ga.ga_data)[i];
9521 list_append_string(rettv->vval.v_list, p, -1);
9522 }
9523 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02009524 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009525}
9526
9527/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009528 * "readfile()" function
9529 */
9530 static void
9531f_readfile(typval_T *argvars, typval_T *rettv)
9532{
9533 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009534 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009535 int failed = FALSE;
9536 char_u *fname;
9537 FILE *fd;
9538 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9539 int io_size = sizeof(buf);
9540 int readlen; /* size of last fread() */
9541 char_u *prev = NULL; /* previously read bytes, if any */
9542 long prevlen = 0; /* length of data in prev */
9543 long prevsize = 0; /* size of prev buffer */
9544 long maxline = MAXLNUM;
9545 long cnt = 0;
9546 char_u *p; /* position in buf */
9547 char_u *start; /* start of current line */
9548
9549 if (argvars[1].v_type != VAR_UNKNOWN)
9550 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009551 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009552 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009553 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9554 blob = TRUE;
9555
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009556 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009557 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009558 }
9559
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009560 if (blob)
9561 {
9562 if (rettv_blob_alloc(rettv) == FAIL)
9563 return;
9564 }
9565 else
9566 {
9567 if (rettv_list_alloc(rettv) == FAIL)
9568 return;
9569 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009570
9571 /* Always open the file in binary mode, library functions have a mind of
9572 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009573 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009574 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9575 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009576 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009577 return;
9578 }
9579
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009580 if (blob)
9581 {
9582 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9583 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009584 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009585 blob_free(rettv->vval.v_blob);
9586 }
9587 fclose(fd);
9588 return;
9589 }
9590
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009591 while (cnt < maxline || maxline < 0)
9592 {
9593 readlen = (int)fread(buf, 1, io_size, fd);
9594
9595 /* This for loop processes what was read, but is also entered at end
9596 * of file so that either:
9597 * - an incomplete line gets written
9598 * - a "binary" file gets an empty line at the end if it ends in a
9599 * newline. */
9600 for (p = buf, start = buf;
9601 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9602 ++p)
9603 {
9604 if (*p == '\n' || readlen <= 0)
9605 {
9606 listitem_T *li;
9607 char_u *s = NULL;
9608 long_u len = p - start;
9609
9610 /* Finished a line. Remove CRs before NL. */
9611 if (readlen > 0 && !binary)
9612 {
9613 while (len > 0 && start[len - 1] == '\r')
9614 --len;
9615 /* removal may cross back to the "prev" string */
9616 if (len == 0)
9617 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9618 --prevlen;
9619 }
9620 if (prevlen == 0)
9621 s = vim_strnsave(start, (int)len);
9622 else
9623 {
9624 /* Change "prev" buffer to be the right size. This way
9625 * the bytes are only copied once, and very long lines are
9626 * allocated only once. */
9627 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9628 {
9629 mch_memmove(s + prevlen, start, len);
9630 s[prevlen + len] = NUL;
9631 prev = NULL; /* the list will own the string */
9632 prevlen = prevsize = 0;
9633 }
9634 }
9635 if (s == NULL)
9636 {
9637 do_outofmem_msg((long_u) prevlen + len + 1);
9638 failed = TRUE;
9639 break;
9640 }
9641
9642 if ((li = listitem_alloc()) == NULL)
9643 {
9644 vim_free(s);
9645 failed = TRUE;
9646 break;
9647 }
9648 li->li_tv.v_type = VAR_STRING;
9649 li->li_tv.v_lock = 0;
9650 li->li_tv.vval.v_string = s;
9651 list_append(rettv->vval.v_list, li);
9652
9653 start = p + 1; /* step over newline */
9654 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9655 break;
9656 }
9657 else if (*p == NUL)
9658 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009659 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9660 * when finding the BF and check the previous two bytes. */
9661 else if (*p == 0xbf && enc_utf8 && !binary)
9662 {
9663 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9664 * + 1, these may be in the "prev" string. */
9665 char_u back1 = p >= buf + 1 ? p[-1]
9666 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9667 char_u back2 = p >= buf + 2 ? p[-2]
9668 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9669 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9670
9671 if (back2 == 0xef && back1 == 0xbb)
9672 {
9673 char_u *dest = p - 2;
9674
9675 /* Usually a BOM is at the beginning of a file, and so at
9676 * the beginning of a line; then we can just step over it.
9677 */
9678 if (start == dest)
9679 start = p + 1;
9680 else
9681 {
9682 /* have to shuffle buf to close gap */
9683 int adjust_prevlen = 0;
9684
9685 if (dest < buf)
9686 {
9687 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9688 dest = buf;
9689 }
9690 if (readlen > p - buf + 1)
9691 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9692 readlen -= 3 - adjust_prevlen;
9693 prevlen -= adjust_prevlen;
9694 p = dest - 1;
9695 }
9696 }
9697 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009698 } /* for */
9699
9700 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9701 break;
9702 if (start < p)
9703 {
9704 /* There's part of a line in buf, store it in "prev". */
9705 if (p - start + prevlen >= prevsize)
9706 {
9707 /* need bigger "prev" buffer */
9708 char_u *newprev;
9709
9710 /* A common use case is ordinary text files and "prev" gets a
9711 * fragment of a line, so the first allocation is made
9712 * small, to avoid repeatedly 'allocing' large and
9713 * 'reallocing' small. */
9714 if (prevsize == 0)
9715 prevsize = (long)(p - start);
9716 else
9717 {
9718 long grow50pc = (prevsize * 3) / 2;
9719 long growmin = (long)((p - start) * 2 + prevlen);
9720 prevsize = grow50pc > growmin ? grow50pc : growmin;
9721 }
9722 newprev = prev == NULL ? alloc(prevsize)
9723 : vim_realloc(prev, prevsize);
9724 if (newprev == NULL)
9725 {
9726 do_outofmem_msg((long_u)prevsize);
9727 failed = TRUE;
9728 break;
9729 }
9730 prev = newprev;
9731 }
9732 /* Add the line part to end of "prev". */
9733 mch_memmove(prev + prevlen, start, p - start);
9734 prevlen += (long)(p - start);
9735 }
9736 } /* while */
9737
9738 /*
9739 * For a negative line count use only the lines at the end of the file,
9740 * free the rest.
9741 */
9742 if (!failed && maxline < 0)
9743 while (cnt > -maxline)
9744 {
9745 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9746 --cnt;
9747 }
9748
9749 if (failed)
9750 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02009751 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009752 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02009753 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009754 }
9755
9756 vim_free(prev);
9757 fclose(fd);
9758}
9759
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009760 static void
9761return_register(int regname, typval_T *rettv)
9762{
9763 char_u buf[2] = {0, 0};
9764
9765 buf[0] = (char_u)regname;
9766 rettv->v_type = VAR_STRING;
9767 rettv->vval.v_string = vim_strsave(buf);
9768}
9769
9770/*
9771 * "reg_executing()" function
9772 */
9773 static void
9774f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9775{
9776 return_register(reg_executing, rettv);
9777}
9778
9779/*
9780 * "reg_recording()" function
9781 */
9782 static void
9783f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9784{
9785 return_register(reg_recording, rettv);
9786}
9787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009788#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009789/*
9790 * Convert a List to proftime_T.
9791 * Return FAIL when there is something wrong.
9792 */
9793 static int
9794list2proftime(typval_T *arg, proftime_T *tm)
9795{
9796 long n1, n2;
9797 int error = FALSE;
9798
9799 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9800 || arg->vval.v_list->lv_len != 2)
9801 return FAIL;
9802 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9803 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009804# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009805 tm->HighPart = n1;
9806 tm->LowPart = n2;
9807# else
9808 tm->tv_sec = n1;
9809 tm->tv_usec = n2;
9810# endif
9811 return error ? FAIL : OK;
9812}
9813#endif /* FEAT_RELTIME */
9814
9815/*
9816 * "reltime()" function
9817 */
9818 static void
9819f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9820{
9821#ifdef FEAT_RELTIME
9822 proftime_T res;
9823 proftime_T start;
9824
9825 if (argvars[0].v_type == VAR_UNKNOWN)
9826 {
9827 /* No arguments: get current time. */
9828 profile_start(&res);
9829 }
9830 else if (argvars[1].v_type == VAR_UNKNOWN)
9831 {
9832 if (list2proftime(&argvars[0], &res) == FAIL)
9833 return;
9834 profile_end(&res);
9835 }
9836 else
9837 {
9838 /* Two arguments: compute the difference. */
9839 if (list2proftime(&argvars[0], &start) == FAIL
9840 || list2proftime(&argvars[1], &res) == FAIL)
9841 return;
9842 profile_sub(&res, &start);
9843 }
9844
9845 if (rettv_list_alloc(rettv) == OK)
9846 {
9847 long n1, n2;
9848
Bram Moolenaar4f974752019-02-17 17:44:42 +01009849# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009850 n1 = res.HighPart;
9851 n2 = res.LowPart;
9852# else
9853 n1 = res.tv_sec;
9854 n2 = res.tv_usec;
9855# endif
9856 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9857 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9858 }
9859#endif
9860}
9861
9862#ifdef FEAT_FLOAT
9863/*
9864 * "reltimefloat()" function
9865 */
9866 static void
9867f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9868{
9869# ifdef FEAT_RELTIME
9870 proftime_T tm;
9871# endif
9872
9873 rettv->v_type = VAR_FLOAT;
9874 rettv->vval.v_float = 0;
9875# ifdef FEAT_RELTIME
9876 if (list2proftime(&argvars[0], &tm) == OK)
9877 rettv->vval.v_float = profile_float(&tm);
9878# endif
9879}
9880#endif
9881
9882/*
9883 * "reltimestr()" function
9884 */
9885 static void
9886f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9887{
9888#ifdef FEAT_RELTIME
9889 proftime_T tm;
9890#endif
9891
9892 rettv->v_type = VAR_STRING;
9893 rettv->vval.v_string = NULL;
9894#ifdef FEAT_RELTIME
9895 if (list2proftime(&argvars[0], &tm) == OK)
9896 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9897#endif
9898}
9899
9900#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009901 static void
9902make_connection(void)
9903{
9904 if (X_DISPLAY == NULL
9905# ifdef FEAT_GUI
9906 && !gui.in_use
9907# endif
9908 )
9909 {
9910 x_force_connect = TRUE;
9911 setup_term_clip();
9912 x_force_connect = FALSE;
9913 }
9914}
9915
9916 static int
9917check_connection(void)
9918{
9919 make_connection();
9920 if (X_DISPLAY == NULL)
9921 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009922 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009923 return FAIL;
9924 }
9925 return OK;
9926}
9927#endif
9928
9929#ifdef FEAT_CLIENTSERVER
9930 static void
9931remote_common(typval_T *argvars, typval_T *rettv, int expr)
9932{
9933 char_u *server_name;
9934 char_u *keys;
9935 char_u *r = NULL;
9936 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009937 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009938# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009939 HWND w;
9940# else
9941 Window w;
9942# endif
9943
9944 if (check_restricted() || check_secure())
9945 return;
9946
9947# ifdef FEAT_X11
9948 if (check_connection() == FAIL)
9949 return;
9950# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009951 if (argvars[2].v_type != VAR_UNKNOWN
9952 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009953 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009954
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009955 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009956 if (server_name == NULL)
9957 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009958 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009959# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009960 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009961# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009962 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9963 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009964# endif
9965 {
9966 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009967 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009968 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009969 vim_free(r);
9970 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009971 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009972 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009973 return;
9974 }
9975
9976 rettv->vval.v_string = r;
9977
9978 if (argvars[2].v_type != VAR_UNKNOWN)
9979 {
9980 dictitem_T v;
9981 char_u str[30];
9982 char_u *idvar;
9983
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009984 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009985 if (idvar != NULL && *idvar != NUL)
9986 {
9987 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9988 v.di_tv.v_type = VAR_STRING;
9989 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009990 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009991 vim_free(v.di_tv.vval.v_string);
9992 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009993 }
9994}
9995#endif
9996
9997/*
9998 * "remote_expr()" function
9999 */
10000 static void
10001f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
10002{
10003 rettv->v_type = VAR_STRING;
10004 rettv->vval.v_string = NULL;
10005#ifdef FEAT_CLIENTSERVER
10006 remote_common(argvars, rettv, TRUE);
10007#endif
10008}
10009
10010/*
10011 * "remote_foreground()" function
10012 */
10013 static void
10014f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10015{
10016#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010017# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010018 /* On Win32 it's done in this application. */
10019 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010020 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010021
10022 if (server_name != NULL)
10023 serverForeground(server_name);
10024 }
10025# else
10026 /* Send a foreground() expression to the server. */
10027 argvars[1].v_type = VAR_STRING;
10028 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
10029 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +020010030 rettv->v_type = VAR_STRING;
10031 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010032 remote_common(argvars, rettv, TRUE);
10033 vim_free(argvars[1].vval.v_string);
10034# endif
10035#endif
10036}
10037
10038 static void
10039f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
10040{
10041#ifdef FEAT_CLIENTSERVER
10042 dictitem_T v;
10043 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +010010044# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010045 long_u n = 0;
10046# endif
10047 char_u *serverid;
10048
10049 if (check_restricted() || check_secure())
10050 {
10051 rettv->vval.v_number = -1;
10052 return;
10053 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010054 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010055 if (serverid == NULL)
10056 {
10057 rettv->vval.v_number = -1;
10058 return; /* type error; errmsg already given */
10059 }
Bram Moolenaar4f974752019-02-17 17:44:42 +010010060# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010061 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
10062 if (n == 0)
10063 rettv->vval.v_number = -1;
10064 else
10065 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010066 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010067 rettv->vval.v_number = (s != NULL);
10068 }
10069# else
10070 if (check_connection() == FAIL)
10071 return;
10072
10073 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
10074 serverStrToWin(serverid), &s);
10075# endif
10076
10077 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
10078 {
10079 char_u *retvar;
10080
10081 v.di_tv.v_type = VAR_STRING;
10082 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010083 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010084 if (retvar != NULL)
10085 set_var(retvar, &v.di_tv, FALSE);
10086 vim_free(v.di_tv.vval.v_string);
10087 }
10088#else
10089 rettv->vval.v_number = -1;
10090#endif
10091}
10092
10093 static void
10094f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
10095{
10096 char_u *r = NULL;
10097
10098#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010099 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010100
10101 if (serverid != NULL && !check_restricted() && !check_secure())
10102 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010103 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +010010104# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +010010105 /* The server's HWND is encoded in the 'id' parameter */
10106 long_u n = 0;
10107# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010108
10109 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010110 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010111
Bram Moolenaar4f974752019-02-17 17:44:42 +010010112# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010113 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
10114 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010115 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010116 if (r == NULL)
10117# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010118 if (check_connection() == FAIL
10119 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
10120 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010121# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010122 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010123 }
10124#endif
10125 rettv->v_type = VAR_STRING;
10126 rettv->vval.v_string = r;
10127}
10128
10129/*
10130 * "remote_send()" function
10131 */
10132 static void
10133f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
10134{
10135 rettv->v_type = VAR_STRING;
10136 rettv->vval.v_string = NULL;
10137#ifdef FEAT_CLIENTSERVER
10138 remote_common(argvars, rettv, FALSE);
10139#endif
10140}
10141
10142/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010143 * "remote_startserver()" function
10144 */
10145 static void
10146f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10147{
10148#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010149 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010150
10151 if (server == NULL)
10152 return; /* type error; errmsg already given */
10153 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010154 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010155 else
10156 {
10157# ifdef FEAT_X11
10158 if (check_connection() == OK)
10159 serverRegisterName(X_DISPLAY, server);
10160# else
10161 serverSetName(server);
10162# endif
10163 }
10164#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010165 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010166#endif
10167}
10168
10169/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010170 * "remove()" function
10171 */
10172 static void
10173f_remove(typval_T *argvars, typval_T *rettv)
10174{
10175 list_T *l;
10176 listitem_T *item, *item2;
10177 listitem_T *li;
10178 long idx;
10179 long end;
10180 char_u *key;
10181 dict_T *d;
10182 dictitem_T *di;
10183 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010184 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010185
10186 if (argvars[0].v_type == VAR_DICT)
10187 {
10188 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010189 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010191 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010192 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010193 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010194 if (key != NULL)
10195 {
10196 di = dict_find(d, key, -1);
10197 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010198 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010199 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
10200 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
10201 {
10202 *rettv = di->di_tv;
10203 init_tv(&di->di_tv);
10204 dictitem_remove(d, di);
10205 }
10206 }
10207 }
10208 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010209 else if (argvars[0].v_type == VAR_BLOB)
10210 {
10211 idx = (long)tv_get_number_chk(&argvars[1], &error);
10212 if (!error)
10213 {
10214 blob_T *b = argvars[0].vval.v_blob;
10215 int len = blob_len(b);
10216 char_u *p;
10217
10218 if (idx < 0)
10219 // count from the end
10220 idx = len + idx;
10221 if (idx < 0 || idx >= len)
10222 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010223 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010224 return;
10225 }
10226 if (argvars[2].v_type == VAR_UNKNOWN)
10227 {
10228 // Remove one item, return its value.
10229 p = (char_u *)b->bv_ga.ga_data;
10230 rettv->vval.v_number = (varnumber_T) *(p + idx);
10231 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
10232 --b->bv_ga.ga_len;
10233 }
10234 else
10235 {
10236 blob_T *blob;
10237
10238 // Remove range of items, return list with values.
10239 end = (long)tv_get_number_chk(&argvars[2], &error);
10240 if (error)
10241 return;
10242 if (end < 0)
10243 // count from the end
10244 end = len + end;
10245 if (end >= len || idx > end)
10246 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010247 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010248 return;
10249 }
10250 blob = blob_alloc();
10251 if (blob == NULL)
10252 return;
10253 blob->bv_ga.ga_len = end - idx + 1;
10254 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
10255 {
10256 vim_free(blob);
10257 return;
10258 }
10259 p = (char_u *)b->bv_ga.ga_data;
10260 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
10261 (size_t)(end - idx + 1));
10262 ++blob->bv_refcount;
10263 rettv->v_type = VAR_BLOB;
10264 rettv->vval.v_blob = blob;
10265
10266 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
10267 b->bv_ga.ga_len -= end - idx + 1;
10268 }
10269 }
10270 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010272 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010273 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010274 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010276 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010277 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010278 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010279 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010280 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010281 else
10282 {
10283 if (argvars[2].v_type == VAR_UNKNOWN)
10284 {
10285 /* Remove one item, return its value. */
10286 vimlist_remove(l, item, item);
10287 *rettv = item->li_tv;
10288 vim_free(item);
10289 }
10290 else
10291 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010292 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010293 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010294 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010295 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010297 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010298 else
10299 {
10300 int cnt = 0;
10301
10302 for (li = item; li != NULL; li = li->li_next)
10303 {
10304 ++cnt;
10305 if (li == item2)
10306 break;
10307 }
10308 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010309 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010310 else
10311 {
10312 vimlist_remove(l, item, item2);
10313 if (rettv_list_alloc(rettv) == OK)
10314 {
10315 l = rettv->vval.v_list;
10316 l->lv_first = item;
10317 l->lv_last = item2;
10318 item->li_prev = NULL;
10319 item2->li_next = NULL;
10320 l->lv_len = cnt;
10321 }
10322 }
10323 }
10324 }
10325 }
10326 }
10327}
10328
10329/*
10330 * "rename({from}, {to})" function
10331 */
10332 static void
10333f_rename(typval_T *argvars, typval_T *rettv)
10334{
10335 char_u buf[NUMBUFLEN];
10336
10337 if (check_restricted() || check_secure())
10338 rettv->vval.v_number = -1;
10339 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010340 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
10341 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010342}
10343
10344/*
10345 * "repeat()" function
10346 */
10347 static void
10348f_repeat(typval_T *argvars, typval_T *rettv)
10349{
10350 char_u *p;
10351 int n;
10352 int slen;
10353 int len;
10354 char_u *r;
10355 int i;
10356
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010357 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010358 if (argvars[0].v_type == VAR_LIST)
10359 {
10360 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
10361 while (n-- > 0)
10362 if (list_extend(rettv->vval.v_list,
10363 argvars[0].vval.v_list, NULL) == FAIL)
10364 break;
10365 }
10366 else
10367 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010368 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010369 rettv->v_type = VAR_STRING;
10370 rettv->vval.v_string = NULL;
10371
10372 slen = (int)STRLEN(p);
10373 len = slen * n;
10374 if (len <= 0)
10375 return;
10376
10377 r = alloc(len + 1);
10378 if (r != NULL)
10379 {
10380 for (i = 0; i < n; i++)
10381 mch_memmove(r + i * slen, p, (size_t)slen);
10382 r[len] = NUL;
10383 }
10384
10385 rettv->vval.v_string = r;
10386 }
10387}
10388
10389/*
10390 * "resolve()" function
10391 */
10392 static void
10393f_resolve(typval_T *argvars, typval_T *rettv)
10394{
10395 char_u *p;
10396#ifdef HAVE_READLINK
10397 char_u *buf = NULL;
10398#endif
10399
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010400 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010401#ifdef FEAT_SHORTCUT
10402 {
10403 char_u *v = NULL;
10404
Bram Moolenaardce1e892019-02-10 23:18:53 +010010405 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010406 if (v != NULL)
10407 rettv->vval.v_string = v;
10408 else
10409 rettv->vval.v_string = vim_strsave(p);
10410 }
10411#else
10412# ifdef HAVE_READLINK
10413 {
10414 char_u *cpy;
10415 int len;
10416 char_u *remain = NULL;
10417 char_u *q;
10418 int is_relative_to_current = FALSE;
10419 int has_trailing_pathsep = FALSE;
10420 int limit = 100;
10421
10422 p = vim_strsave(p);
10423
10424 if (p[0] == '.' && (vim_ispathsep(p[1])
10425 || (p[1] == '.' && (vim_ispathsep(p[2])))))
10426 is_relative_to_current = TRUE;
10427
10428 len = STRLEN(p);
10429 if (len > 0 && after_pathsep(p, p + len))
10430 {
10431 has_trailing_pathsep = TRUE;
10432 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
10433 }
10434
10435 q = getnextcomp(p);
10436 if (*q != NUL)
10437 {
10438 /* Separate the first path component in "p", and keep the
10439 * remainder (beginning with the path separator). */
10440 remain = vim_strsave(q - 1);
10441 q[-1] = NUL;
10442 }
10443
10444 buf = alloc(MAXPATHL + 1);
10445 if (buf == NULL)
10446 goto fail;
10447
10448 for (;;)
10449 {
10450 for (;;)
10451 {
10452 len = readlink((char *)p, (char *)buf, MAXPATHL);
10453 if (len <= 0)
10454 break;
10455 buf[len] = NUL;
10456
10457 if (limit-- == 0)
10458 {
10459 vim_free(p);
10460 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010461 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010462 rettv->vval.v_string = NULL;
10463 goto fail;
10464 }
10465
10466 /* Ensure that the result will have a trailing path separator
10467 * if the argument has one. */
10468 if (remain == NULL && has_trailing_pathsep)
10469 add_pathsep(buf);
10470
10471 /* Separate the first path component in the link value and
10472 * concatenate the remainders. */
10473 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10474 if (*q != NUL)
10475 {
10476 if (remain == NULL)
10477 remain = vim_strsave(q - 1);
10478 else
10479 {
10480 cpy = concat_str(q - 1, remain);
10481 if (cpy != NULL)
10482 {
10483 vim_free(remain);
10484 remain = cpy;
10485 }
10486 }
10487 q[-1] = NUL;
10488 }
10489
10490 q = gettail(p);
10491 if (q > p && *q == NUL)
10492 {
10493 /* Ignore trailing path separator. */
10494 q[-1] = NUL;
10495 q = gettail(p);
10496 }
10497 if (q > p && !mch_isFullName(buf))
10498 {
10499 /* symlink is relative to directory of argument */
10500 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10501 if (cpy != NULL)
10502 {
10503 STRCPY(cpy, p);
10504 STRCPY(gettail(cpy), buf);
10505 vim_free(p);
10506 p = cpy;
10507 }
10508 }
10509 else
10510 {
10511 vim_free(p);
10512 p = vim_strsave(buf);
10513 }
10514 }
10515
10516 if (remain == NULL)
10517 break;
10518
10519 /* Append the first path component of "remain" to "p". */
10520 q = getnextcomp(remain + 1);
10521 len = q - remain - (*q != NUL);
10522 cpy = vim_strnsave(p, STRLEN(p) + len);
10523 if (cpy != NULL)
10524 {
10525 STRNCAT(cpy, remain, len);
10526 vim_free(p);
10527 p = cpy;
10528 }
10529 /* Shorten "remain". */
10530 if (*q != NUL)
10531 STRMOVE(remain, q - 1);
10532 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010533 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010534 }
10535
10536 /* If the result is a relative path name, make it explicitly relative to
10537 * the current directory if and only if the argument had this form. */
10538 if (!vim_ispathsep(*p))
10539 {
10540 if (is_relative_to_current
10541 && *p != NUL
10542 && !(p[0] == '.'
10543 && (p[1] == NUL
10544 || vim_ispathsep(p[1])
10545 || (p[1] == '.'
10546 && (p[2] == NUL
10547 || vim_ispathsep(p[2]))))))
10548 {
10549 /* Prepend "./". */
10550 cpy = concat_str((char_u *)"./", p);
10551 if (cpy != NULL)
10552 {
10553 vim_free(p);
10554 p = cpy;
10555 }
10556 }
10557 else if (!is_relative_to_current)
10558 {
10559 /* Strip leading "./". */
10560 q = p;
10561 while (q[0] == '.' && vim_ispathsep(q[1]))
10562 q += 2;
10563 if (q > p)
10564 STRMOVE(p, p + 2);
10565 }
10566 }
10567
10568 /* Ensure that the result will have no trailing path separator
10569 * if the argument had none. But keep "/" or "//". */
10570 if (!has_trailing_pathsep)
10571 {
10572 q = p + STRLEN(p);
10573 if (after_pathsep(p, q))
10574 *gettail_sep(p) = NUL;
10575 }
10576
10577 rettv->vval.v_string = p;
10578 }
10579# else
10580 rettv->vval.v_string = vim_strsave(p);
10581# endif
10582#endif
10583
10584 simplify_filename(rettv->vval.v_string);
10585
10586#ifdef HAVE_READLINK
10587fail:
10588 vim_free(buf);
10589#endif
10590 rettv->v_type = VAR_STRING;
10591}
10592
10593/*
10594 * "reverse({list})" function
10595 */
10596 static void
10597f_reverse(typval_T *argvars, typval_T *rettv)
10598{
10599 list_T *l;
10600 listitem_T *li, *ni;
10601
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010602 if (argvars[0].v_type == VAR_BLOB)
10603 {
10604 blob_T *b = argvars[0].vval.v_blob;
10605 int i, len = blob_len(b);
10606
10607 for (i = 0; i < len / 2; i++)
10608 {
10609 int tmp = blob_get(b, i);
10610
10611 blob_set(b, i, blob_get(b, len - i - 1));
10612 blob_set(b, len - i - 1, tmp);
10613 }
10614 rettv_blob_set(rettv, b);
10615 return;
10616 }
10617
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010618 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010619 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010620 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010621 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010622 (char_u *)N_("reverse() argument"), TRUE))
10623 {
10624 li = l->lv_last;
10625 l->lv_first = l->lv_last = NULL;
10626 l->lv_len = 0;
10627 while (li != NULL)
10628 {
10629 ni = li->li_prev;
10630 list_append(l, li);
10631 li = ni;
10632 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010633 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010634 l->lv_idx = l->lv_len - l->lv_idx - 1;
10635 }
10636}
10637
10638#define SP_NOMOVE 0x01 /* don't move cursor */
10639#define SP_REPEAT 0x02 /* repeat to find outer pair */
10640#define SP_RETCOUNT 0x04 /* return matchcount */
10641#define SP_SETPCMARK 0x08 /* set previous context mark */
10642#define SP_START 0x10 /* accept match at start position */
10643#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10644#define SP_END 0x40 /* leave cursor at end of match */
10645#define SP_COLUMN 0x80 /* start at cursor column */
10646
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010647/*
10648 * Get flags for a search function.
10649 * Possibly sets "p_ws".
10650 * Returns BACKWARD, FORWARD or zero (for an error).
10651 */
10652 static int
10653get_search_arg(typval_T *varp, int *flagsp)
10654{
10655 int dir = FORWARD;
10656 char_u *flags;
10657 char_u nbuf[NUMBUFLEN];
10658 int mask;
10659
10660 if (varp->v_type != VAR_UNKNOWN)
10661 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010662 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010663 if (flags == NULL)
10664 return 0; /* type error; errmsg already given */
10665 while (*flags != NUL)
10666 {
10667 switch (*flags)
10668 {
10669 case 'b': dir = BACKWARD; break;
10670 case 'w': p_ws = TRUE; break;
10671 case 'W': p_ws = FALSE; break;
10672 default: mask = 0;
10673 if (flagsp != NULL)
10674 switch (*flags)
10675 {
10676 case 'c': mask = SP_START; break;
10677 case 'e': mask = SP_END; break;
10678 case 'm': mask = SP_RETCOUNT; break;
10679 case 'n': mask = SP_NOMOVE; break;
10680 case 'p': mask = SP_SUBPAT; break;
10681 case 'r': mask = SP_REPEAT; break;
10682 case 's': mask = SP_SETPCMARK; break;
10683 case 'z': mask = SP_COLUMN; break;
10684 }
10685 if (mask == 0)
10686 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010687 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010688 dir = 0;
10689 }
10690 else
10691 *flagsp |= mask;
10692 }
10693 if (dir == 0)
10694 break;
10695 ++flags;
10696 }
10697 }
10698 return dir;
10699}
10700
10701/*
10702 * Shared by search() and searchpos() functions.
10703 */
10704 static int
10705search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10706{
10707 int flags;
10708 char_u *pat;
10709 pos_T pos;
10710 pos_T save_cursor;
10711 int save_p_ws = p_ws;
10712 int dir;
10713 int retval = 0; /* default: FAIL */
10714 long lnum_stop = 0;
10715 proftime_T tm;
10716#ifdef FEAT_RELTIME
10717 long time_limit = 0;
10718#endif
10719 int options = SEARCH_KEEP;
10720 int subpatnum;
10721
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010722 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010723 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10724 if (dir == 0)
10725 goto theend;
10726 flags = *flagsp;
10727 if (flags & SP_START)
10728 options |= SEARCH_START;
10729 if (flags & SP_END)
10730 options |= SEARCH_END;
10731 if (flags & SP_COLUMN)
10732 options |= SEARCH_COL;
10733
10734 /* Optional arguments: line number to stop searching and timeout. */
10735 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10736 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010737 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010738 if (lnum_stop < 0)
10739 goto theend;
10740#ifdef FEAT_RELTIME
10741 if (argvars[3].v_type != VAR_UNKNOWN)
10742 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010743 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010744 if (time_limit < 0)
10745 goto theend;
10746 }
10747#endif
10748 }
10749
10750#ifdef FEAT_RELTIME
10751 /* Set the time limit, if there is one. */
10752 profile_setlimit(time_limit, &tm);
10753#endif
10754
10755 /*
10756 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10757 * Check to make sure only those flags are set.
10758 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10759 * flags cannot be set. Check for that condition also.
10760 */
10761 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10762 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10763 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010764 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010765 goto theend;
10766 }
10767
10768 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010769 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010770 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010771 if (subpatnum != FAIL)
10772 {
10773 if (flags & SP_SUBPAT)
10774 retval = subpatnum;
10775 else
10776 retval = pos.lnum;
10777 if (flags & SP_SETPCMARK)
10778 setpcmark();
10779 curwin->w_cursor = pos;
10780 if (match_pos != NULL)
10781 {
10782 /* Store the match cursor position */
10783 match_pos->lnum = pos.lnum;
10784 match_pos->col = pos.col + 1;
10785 }
10786 /* "/$" will put the cursor after the end of the line, may need to
10787 * correct that here */
10788 check_cursor();
10789 }
10790
10791 /* If 'n' flag is used: restore cursor position. */
10792 if (flags & SP_NOMOVE)
10793 curwin->w_cursor = save_cursor;
10794 else
10795 curwin->w_set_curswant = TRUE;
10796theend:
10797 p_ws = save_p_ws;
10798
10799 return retval;
10800}
10801
10802#ifdef FEAT_FLOAT
10803
10804/*
10805 * round() is not in C90, use ceil() or floor() instead.
10806 */
10807 float_T
10808vim_round(float_T f)
10809{
10810 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10811}
10812
10813/*
10814 * "round({float})" function
10815 */
10816 static void
10817f_round(typval_T *argvars, typval_T *rettv)
10818{
10819 float_T f = 0.0;
10820
10821 rettv->v_type = VAR_FLOAT;
10822 if (get_float_arg(argvars, &f) == OK)
10823 rettv->vval.v_float = vim_round(f);
10824 else
10825 rettv->vval.v_float = 0.0;
10826}
10827#endif
10828
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010829#ifdef FEAT_RUBY
10830/*
10831 * "rubyeval()" function
10832 */
10833 static void
10834f_rubyeval(typval_T *argvars, typval_T *rettv)
10835{
10836 char_u *str;
10837 char_u buf[NUMBUFLEN];
10838
10839 str = tv_get_string_buf(&argvars[0], buf);
10840 do_rubyeval(str, rettv);
10841}
10842#endif
10843
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010844/*
10845 * "screenattr()" function
10846 */
10847 static void
10848f_screenattr(typval_T *argvars, typval_T *rettv)
10849{
10850 int row;
10851 int col;
10852 int c;
10853
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010854 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10855 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010856 if (row < 0 || row >= screen_Rows
10857 || col < 0 || col >= screen_Columns)
10858 c = -1;
10859 else
10860 c = ScreenAttrs[LineOffset[row] + col];
10861 rettv->vval.v_number = c;
10862}
10863
10864/*
10865 * "screenchar()" function
10866 */
10867 static void
10868f_screenchar(typval_T *argvars, typval_T *rettv)
10869{
10870 int row;
10871 int col;
10872 int off;
10873 int c;
10874
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010875 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10876 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010877 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010878 c = -1;
10879 else
10880 {
10881 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010882 if (enc_utf8 && ScreenLinesUC[off] != 0)
10883 c = ScreenLinesUC[off];
10884 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010885 c = ScreenLines[off];
10886 }
10887 rettv->vval.v_number = c;
10888}
10889
10890/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010891 * "screenchars()" function
10892 */
10893 static void
10894f_screenchars(typval_T *argvars, typval_T *rettv)
10895{
10896 int row;
10897 int col;
10898 int off;
10899 int c;
10900 int i;
10901
10902 if (rettv_list_alloc(rettv) == FAIL)
10903 return;
10904 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10905 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10906 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10907 return;
10908
10909 off = LineOffset[row] + col;
10910 if (enc_utf8 && ScreenLinesUC[off] != 0)
10911 c = ScreenLinesUC[off];
10912 else
10913 c = ScreenLines[off];
10914 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10915
10916 if (enc_utf8)
10917
10918 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10919 list_append_number(rettv->vval.v_list,
10920 (varnumber_T)ScreenLinesC[i][off]);
10921}
10922
10923/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010924 * "screencol()" function
10925 *
10926 * First column is 1 to be consistent with virtcol().
10927 */
10928 static void
10929f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10930{
10931 rettv->vval.v_number = screen_screencol() + 1;
10932}
10933
10934/*
10935 * "screenrow()" function
10936 */
10937 static void
10938f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10939{
10940 rettv->vval.v_number = screen_screenrow() + 1;
10941}
10942
10943/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010944 * "screenstring()" function
10945 */
10946 static void
10947f_screenstring(typval_T *argvars, typval_T *rettv)
10948{
10949 int row;
10950 int col;
10951 int off;
10952 int c;
10953 int i;
10954 char_u buf[MB_MAXBYTES + 1];
10955 int buflen = 0;
10956
10957 rettv->vval.v_string = NULL;
10958 rettv->v_type = VAR_STRING;
10959
10960 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10961 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10962 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10963 return;
10964
10965 off = LineOffset[row] + col;
10966 if (enc_utf8 && ScreenLinesUC[off] != 0)
10967 c = ScreenLinesUC[off];
10968 else
10969 c = ScreenLines[off];
10970 buflen += mb_char2bytes(c, buf);
10971
10972 if (enc_utf8)
10973 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10974 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10975
10976 buf[buflen] = NUL;
10977 rettv->vval.v_string = vim_strsave(buf);
10978}
10979
10980/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010981 * "search()" function
10982 */
10983 static void
10984f_search(typval_T *argvars, typval_T *rettv)
10985{
10986 int flags = 0;
10987
10988 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10989}
10990
10991/*
10992 * "searchdecl()" function
10993 */
10994 static void
10995f_searchdecl(typval_T *argvars, typval_T *rettv)
10996{
10997 int locally = 1;
10998 int thisblock = 0;
10999 int error = FALSE;
11000 char_u *name;
11001
11002 rettv->vval.v_number = 1; /* default: FAIL */
11003
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011004 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011005 if (argvars[1].v_type != VAR_UNKNOWN)
11006 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011007 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011008 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011009 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011010 }
11011 if (!error && name != NULL)
11012 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
11013 locally, thisblock, SEARCH_KEEP) == FAIL;
11014}
11015
11016/*
11017 * Used by searchpair() and searchpairpos()
11018 */
11019 static int
11020searchpair_cmn(typval_T *argvars, pos_T *match_pos)
11021{
11022 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010011023 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011024 int save_p_ws = p_ws;
11025 int dir;
11026 int flags = 0;
11027 char_u nbuf1[NUMBUFLEN];
11028 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011029 int retval = 0; /* default: FAIL */
11030 long lnum_stop = 0;
11031 long time_limit = 0;
11032
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011033 /* Get the three pattern arguments: start, middle, end. Will result in an
11034 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011035 spat = tv_get_string_chk(&argvars[0]);
11036 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
11037 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 if (spat == NULL || mpat == NULL || epat == NULL)
11039 goto theend; /* type error */
11040
11041 /* Handle the optional fourth argument: flags */
11042 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
11043 if (dir == 0)
11044 goto theend;
11045
11046 /* Don't accept SP_END or SP_SUBPAT.
11047 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
11048 */
11049 if ((flags & (SP_END | SP_SUBPAT)) != 0
11050 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
11051 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011052 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011053 goto theend;
11054 }
11055
11056 /* Using 'r' implies 'W', otherwise it doesn't work. */
11057 if (flags & SP_REPEAT)
11058 p_ws = FALSE;
11059
11060 /* Optional fifth argument: skip expression */
11061 if (argvars[3].v_type == VAR_UNKNOWN
11062 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010011063 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011064 else
11065 {
Bram Moolenaar48570482017-10-30 21:48:41 +010011066 skip = &argvars[4];
11067 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
11068 && skip->v_type != VAR_STRING)
11069 {
11070 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011071 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010011072 goto theend;
11073 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011074 if (argvars[5].v_type != VAR_UNKNOWN)
11075 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011076 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011077 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011078 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011079 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011081 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011082#ifdef FEAT_RELTIME
11083 if (argvars[6].v_type != VAR_UNKNOWN)
11084 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011085 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011086 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011087 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011088 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011089 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011090 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011091 }
11092#endif
11093 }
11094 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011095
11096 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
11097 match_pos, lnum_stop, time_limit);
11098
11099theend:
11100 p_ws = save_p_ws;
11101
11102 return retval;
11103}
11104
11105/*
11106 * "searchpair()" function
11107 */
11108 static void
11109f_searchpair(typval_T *argvars, typval_T *rettv)
11110{
11111 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
11112}
11113
11114/*
11115 * "searchpairpos()" function
11116 */
11117 static void
11118f_searchpairpos(typval_T *argvars, typval_T *rettv)
11119{
11120 pos_T match_pos;
11121 int lnum = 0;
11122 int col = 0;
11123
11124 if (rettv_list_alloc(rettv) == FAIL)
11125 return;
11126
11127 if (searchpair_cmn(argvars, &match_pos) > 0)
11128 {
11129 lnum = match_pos.lnum;
11130 col = match_pos.col;
11131 }
11132
11133 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
11134 list_append_number(rettv->vval.v_list, (varnumber_T)col);
11135}
11136
11137/*
11138 * Search for a start/middle/end thing.
11139 * Used by searchpair(), see its documentation for the details.
11140 * Returns 0 or -1 for no match,
11141 */
11142 long
11143do_searchpair(
11144 char_u *spat, /* start pattern */
11145 char_u *mpat, /* middle pattern */
11146 char_u *epat, /* end pattern */
11147 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010011148 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011149 int flags, /* SP_SETPCMARK and other SP_ values */
11150 pos_T *match_pos,
11151 linenr_T lnum_stop, /* stop at this line if not zero */
11152 long time_limit UNUSED) /* stop after this many msec */
11153{
11154 char_u *save_cpo;
11155 char_u *pat, *pat2 = NULL, *pat3 = NULL;
11156 long retval = 0;
11157 pos_T pos;
11158 pos_T firstpos;
11159 pos_T foundpos;
11160 pos_T save_cursor;
11161 pos_T save_pos;
11162 int n;
11163 int r;
11164 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010011165 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011166 int err;
11167 int options = SEARCH_KEEP;
11168 proftime_T tm;
11169
11170 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11171 save_cpo = p_cpo;
11172 p_cpo = empty_option;
11173
11174#ifdef FEAT_RELTIME
11175 /* Set the time limit, if there is one. */
11176 profile_setlimit(time_limit, &tm);
11177#endif
11178
11179 /* Make two search patterns: start/end (pat2, for in nested pairs) and
11180 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010011181 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
11182 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011183 if (pat2 == NULL || pat3 == NULL)
11184 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010011185 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011186 if (*mpat == NUL)
11187 STRCPY(pat3, pat2);
11188 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010011189 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011190 spat, epat, mpat);
11191 if (flags & SP_START)
11192 options |= SEARCH_START;
11193
Bram Moolenaar48570482017-10-30 21:48:41 +010011194 if (skip != NULL)
11195 {
11196 /* Empty string means to not use the skip expression. */
11197 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
11198 use_skip = skip->vval.v_string != NULL
11199 && *skip->vval.v_string != NUL;
11200 }
11201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011202 save_cursor = curwin->w_cursor;
11203 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010011204 CLEAR_POS(&firstpos);
11205 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011206 pat = pat3;
11207 for (;;)
11208 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010011209 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020011210 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010011211 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011212 /* didn't find it or found the first match again: FAIL */
11213 break;
11214
11215 if (firstpos.lnum == 0)
11216 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010011217 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011218 {
11219 /* Found the same position again. Can happen with a pattern that
11220 * has "\zs" at the end and searching backwards. Advance one
11221 * character and try again. */
11222 if (dir == BACKWARD)
11223 decl(&pos);
11224 else
11225 incl(&pos);
11226 }
11227 foundpos = pos;
11228
11229 /* clear the start flag to avoid getting stuck here */
11230 options &= ~SEARCH_START;
11231
11232 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010011233 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011234 {
11235 save_pos = curwin->w_cursor;
11236 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010011237 err = FALSE;
11238 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011239 curwin->w_cursor = save_pos;
11240 if (err)
11241 {
11242 /* Evaluating {skip} caused an error, break here. */
11243 curwin->w_cursor = save_cursor;
11244 retval = -1;
11245 break;
11246 }
11247 if (r)
11248 continue;
11249 }
11250
11251 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
11252 {
11253 /* Found end when searching backwards or start when searching
11254 * forward: nested pair. */
11255 ++nest;
11256 pat = pat2; /* nested, don't search for middle */
11257 }
11258 else
11259 {
11260 /* Found end when searching forward or start when searching
11261 * backward: end of (nested) pair; or found middle in outer pair. */
11262 if (--nest == 1)
11263 pat = pat3; /* outer level, search for middle */
11264 }
11265
11266 if (nest == 0)
11267 {
11268 /* Found the match: return matchcount or line number. */
11269 if (flags & SP_RETCOUNT)
11270 ++retval;
11271 else
11272 retval = pos.lnum;
11273 if (flags & SP_SETPCMARK)
11274 setpcmark();
11275 curwin->w_cursor = pos;
11276 if (!(flags & SP_REPEAT))
11277 break;
11278 nest = 1; /* search for next unmatched */
11279 }
11280 }
11281
11282 if (match_pos != NULL)
11283 {
11284 /* Store the match cursor position */
11285 match_pos->lnum = curwin->w_cursor.lnum;
11286 match_pos->col = curwin->w_cursor.col + 1;
11287 }
11288
11289 /* If 'n' flag is used or search failed: restore cursor position. */
11290 if ((flags & SP_NOMOVE) || retval == 0)
11291 curwin->w_cursor = save_cursor;
11292
11293theend:
11294 vim_free(pat2);
11295 vim_free(pat3);
11296 if (p_cpo == empty_option)
11297 p_cpo = save_cpo;
11298 else
11299 /* Darn, evaluating the {skip} expression changed the value. */
11300 free_string_option(save_cpo);
11301
11302 return retval;
11303}
11304
11305/*
11306 * "searchpos()" function
11307 */
11308 static void
11309f_searchpos(typval_T *argvars, typval_T *rettv)
11310{
11311 pos_T match_pos;
11312 int lnum = 0;
11313 int col = 0;
11314 int n;
11315 int flags = 0;
11316
11317 if (rettv_list_alloc(rettv) == FAIL)
11318 return;
11319
11320 n = search_cmn(argvars, &match_pos, &flags);
11321 if (n > 0)
11322 {
11323 lnum = match_pos.lnum;
11324 col = match_pos.col;
11325 }
11326
11327 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
11328 list_append_number(rettv->vval.v_list, (varnumber_T)col);
11329 if (flags & SP_SUBPAT)
11330 list_append_number(rettv->vval.v_list, (varnumber_T)n);
11331}
11332
11333 static void
11334f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
11335{
11336#ifdef FEAT_CLIENTSERVER
11337 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011338 char_u *server = tv_get_string_chk(&argvars[0]);
11339 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011340
11341 rettv->vval.v_number = -1;
11342 if (server == NULL || reply == NULL)
11343 return;
11344 if (check_restricted() || check_secure())
11345 return;
11346# ifdef FEAT_X11
11347 if (check_connection() == FAIL)
11348 return;
11349# endif
11350
11351 if (serverSendReply(server, reply) < 0)
11352 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011353 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011354 return;
11355 }
11356 rettv->vval.v_number = 0;
11357#else
11358 rettv->vval.v_number = -1;
11359#endif
11360}
11361
11362 static void
11363f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
11364{
11365 char_u *r = NULL;
11366
11367#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010011368# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011369 r = serverGetVimNames();
11370# else
11371 make_connection();
11372 if (X_DISPLAY != NULL)
11373 r = serverGetVimNames(X_DISPLAY);
11374# endif
11375#endif
11376 rettv->v_type = VAR_STRING;
11377 rettv->vval.v_string = r;
11378}
11379
11380/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011381 * "setbufline()" function
11382 */
11383 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020011384f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011385{
11386 linenr_T lnum;
11387 buf_T *buf;
11388
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011389 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011390 if (buf == NULL)
11391 rettv->vval.v_number = 1; /* FAIL */
11392 else
11393 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011394 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020011395 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011396 }
11397}
11398
11399/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011400 * "setbufvar()" function
11401 */
11402 static void
11403f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
11404{
11405 buf_T *buf;
11406 char_u *varname, *bufvarname;
11407 typval_T *varp;
11408 char_u nbuf[NUMBUFLEN];
11409
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011410 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011411 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011412 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
11413 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011414 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011415 varp = &argvars[2];
11416
11417 if (buf != NULL && varname != NULL && varp != NULL)
11418 {
11419 if (*varname == '&')
11420 {
11421 long numval;
11422 char_u *strval;
11423 int error = FALSE;
11424 aco_save_T aco;
11425
11426 /* set curbuf to be our buf, temporarily */
11427 aucmd_prepbuf(&aco, buf);
11428
11429 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011430 numval = (long)tv_get_number_chk(varp, &error);
11431 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011432 if (!error && strval != NULL)
11433 set_option_value(varname, numval, strval, OPT_LOCAL);
11434
11435 /* reset notion of buffer */
11436 aucmd_restbuf(&aco);
11437 }
11438 else
11439 {
11440 buf_T *save_curbuf = curbuf;
11441
11442 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
11443 if (bufvarname != NULL)
11444 {
11445 curbuf = buf;
11446 STRCPY(bufvarname, "b:");
11447 STRCPY(bufvarname + 2, varname);
11448 set_var(bufvarname, varp, TRUE);
11449 vim_free(bufvarname);
11450 curbuf = save_curbuf;
11451 }
11452 }
11453 }
11454}
11455
11456 static void
11457f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
11458{
11459 dict_T *d;
11460 dictitem_T *di;
11461 char_u *csearch;
11462
11463 if (argvars[0].v_type != VAR_DICT)
11464 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011465 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011466 return;
11467 }
11468
11469 if ((d = argvars[0].vval.v_dict) != NULL)
11470 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011471 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011472 if (csearch != NULL)
11473 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011474 if (enc_utf8)
11475 {
11476 int pcc[MAX_MCO];
11477 int c = utfc_ptr2char(csearch, pcc);
11478
11479 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11480 }
11481 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011482 set_last_csearch(PTR2CHAR(csearch),
11483 csearch, MB_PTR2LEN(csearch));
11484 }
11485
11486 di = dict_find(d, (char_u *)"forward", -1);
11487 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011488 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011489 ? FORWARD : BACKWARD);
11490
11491 di = dict_find(d, (char_u *)"until", -1);
11492 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011493 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011494 }
11495}
11496
11497/*
11498 * "setcmdpos()" function
11499 */
11500 static void
11501f_setcmdpos(typval_T *argvars, typval_T *rettv)
11502{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011503 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011504
11505 if (pos >= 0)
11506 rettv->vval.v_number = set_cmdline_pos(pos);
11507}
11508
11509/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020011510 * "setenv()" function
11511 */
11512 static void
11513f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
11514{
11515 char_u namebuf[NUMBUFLEN];
11516 char_u valbuf[NUMBUFLEN];
11517 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
11518
11519 if (argvars[1].v_type == VAR_SPECIAL
11520 && argvars[1].vval.v_number == VVAL_NULL)
11521 vim_unsetenv(name);
11522 else
11523 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
11524}
11525
11526/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011527 * "setfperm({fname}, {mode})" function
11528 */
11529 static void
11530f_setfperm(typval_T *argvars, typval_T *rettv)
11531{
11532 char_u *fname;
11533 char_u modebuf[NUMBUFLEN];
11534 char_u *mode_str;
11535 int i;
11536 int mask;
11537 int mode = 0;
11538
11539 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011540 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011541 if (fname == NULL)
11542 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011543 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011544 if (mode_str == NULL)
11545 return;
11546 if (STRLEN(mode_str) != 9)
11547 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011548 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011549 return;
11550 }
11551
11552 mask = 1;
11553 for (i = 8; i >= 0; --i)
11554 {
11555 if (mode_str[i] != '-')
11556 mode |= mask;
11557 mask = mask << 1;
11558 }
11559 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11560}
11561
11562/*
11563 * "setline()" function
11564 */
11565 static void
11566f_setline(typval_T *argvars, typval_T *rettv)
11567{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011568 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011569
Bram Moolenaarca851592018-06-06 21:04:07 +020011570 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011571}
11572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011573/*
11574 * Used by "setqflist()" and "setloclist()" functions
11575 */
11576 static void
11577set_qf_ll_list(
11578 win_T *wp UNUSED,
11579 typval_T *list_arg UNUSED,
11580 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011581 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011582 typval_T *rettv)
11583{
11584#ifdef FEAT_QUICKFIX
11585 static char *e_invact = N_("E927: Invalid action: '%s'");
11586 char_u *act;
11587 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011588 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011589#endif
11590
11591 rettv->vval.v_number = -1;
11592
11593#ifdef FEAT_QUICKFIX
11594 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011595 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011596 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011597 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011598 else
11599 {
11600 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011601 dict_T *d = NULL;
11602 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011603
11604 if (action_arg->v_type == VAR_STRING)
11605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011606 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011607 if (act == NULL)
11608 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011609 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11610 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011611 action = *act;
11612 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011613 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011614 }
11615 else if (action_arg->v_type == VAR_UNKNOWN)
11616 action = ' ';
11617 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011618 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011619
Bram Moolenaard823fa92016-08-12 16:29:27 +020011620 if (action_arg->v_type != VAR_UNKNOWN
11621 && what_arg->v_type != VAR_UNKNOWN)
11622 {
11623 if (what_arg->v_type == VAR_DICT)
11624 d = what_arg->vval.v_dict;
11625 else
11626 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011627 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011628 valid_dict = FALSE;
11629 }
11630 }
11631
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011632 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011633 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011634 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11635 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011636 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011637 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011638 }
11639#endif
11640}
11641
11642/*
11643 * "setloclist()" function
11644 */
11645 static void
11646f_setloclist(typval_T *argvars, typval_T *rettv)
11647{
11648 win_T *win;
11649
11650 rettv->vval.v_number = -1;
11651
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011652 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011653 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011654 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011655}
11656
11657/*
11658 * "setmatches()" function
11659 */
11660 static void
11661f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11662{
11663#ifdef FEAT_SEARCH_EXTRA
11664 list_T *l;
11665 listitem_T *li;
11666 dict_T *d;
11667 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010011668 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011669
11670 rettv->vval.v_number = -1;
11671 if (argvars[0].v_type != VAR_LIST)
11672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011673 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011674 return;
11675 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010011676 if (win == NULL)
11677 return;
11678
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011679 if ((l = argvars[0].vval.v_list) != NULL)
11680 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011681 /* To some extent make sure that we are dealing with a list from
11682 * "getmatches()". */
11683 li = l->lv_first;
11684 while (li != NULL)
11685 {
11686 if (li->li_tv.v_type != VAR_DICT
11687 || (d = li->li_tv.vval.v_dict) == NULL)
11688 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011689 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011690 return;
11691 }
11692 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11693 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11694 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11695 && dict_find(d, (char_u *)"priority", -1) != NULL
11696 && dict_find(d, (char_u *)"id", -1) != NULL))
11697 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011698 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011699 return;
11700 }
11701 li = li->li_next;
11702 }
11703
Bram Moolenaaraff74912019-03-30 18:11:49 +010011704 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011705 li = l->lv_first;
11706 while (li != NULL)
11707 {
11708 int i = 0;
Bram Moolenaar54315892019-04-26 22:33:49 +020011709 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011710 dictitem_T *di;
11711 char_u *group;
11712 int priority;
11713 int id;
11714 char_u *conceal;
11715
11716 d = li->li_tv.vval.v_dict;
11717 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11718 {
11719 if (s == NULL)
11720 {
11721 s = list_alloc();
11722 if (s == NULL)
11723 return;
11724 }
11725
11726 /* match from matchaddpos() */
11727 for (i = 1; i < 9; i++)
11728 {
11729 sprintf((char *)buf, (char *)"pos%d", i);
11730 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11731 {
11732 if (di->di_tv.v_type != VAR_LIST)
11733 return;
11734
11735 list_append_tv(s, &di->di_tv);
11736 s->lv_refcount++;
11737 }
11738 else
11739 break;
11740 }
11741 }
11742
Bram Moolenaar8f667172018-12-14 15:38:31 +010011743 group = dict_get_string(d, (char_u *)"group", TRUE);
11744 priority = (int)dict_get_number(d, (char_u *)"priority");
11745 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011746 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011747 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011748 : NULL;
11749 if (i == 0)
11750 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011751 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011752 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011753 priority, id, NULL, conceal);
11754 }
11755 else
11756 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011757 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011758 list_unref(s);
11759 s = NULL;
11760 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011761 vim_free(group);
11762 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011763
11764 li = li->li_next;
11765 }
11766 rettv->vval.v_number = 0;
11767 }
11768#endif
11769}
11770
11771/*
11772 * "setpos()" function
11773 */
11774 static void
11775f_setpos(typval_T *argvars, typval_T *rettv)
11776{
11777 pos_T pos;
11778 int fnum;
11779 char_u *name;
11780 colnr_T curswant = -1;
11781
11782 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011783 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011784 if (name != NULL)
11785 {
11786 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11787 {
11788 if (--pos.col < 0)
11789 pos.col = 0;
11790 if (name[0] == '.' && name[1] == NUL)
11791 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011792 /* set cursor; "fnum" is ignored */
11793 curwin->w_cursor = pos;
11794 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011795 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011796 curwin->w_curswant = curswant - 1;
11797 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011798 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011799 check_cursor();
11800 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011801 }
11802 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11803 {
11804 /* set mark */
11805 if (setmark_pos(name[1], &pos, fnum) == OK)
11806 rettv->vval.v_number = 0;
11807 }
11808 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011809 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011810 }
11811 }
11812}
11813
11814/*
11815 * "setqflist()" function
11816 */
11817 static void
11818f_setqflist(typval_T *argvars, typval_T *rettv)
11819{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011820 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011821}
11822
11823/*
11824 * "setreg()" function
11825 */
11826 static void
11827f_setreg(typval_T *argvars, typval_T *rettv)
11828{
11829 int regname;
11830 char_u *strregname;
11831 char_u *stropt;
11832 char_u *strval;
11833 int append;
11834 char_u yank_type;
11835 long block_len;
11836
11837 block_len = -1;
11838 yank_type = MAUTO;
11839 append = FALSE;
11840
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011841 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011842 rettv->vval.v_number = 1; /* FAIL is default */
11843
11844 if (strregname == NULL)
11845 return; /* type error; errmsg already given */
11846 regname = *strregname;
11847 if (regname == 0 || regname == '@')
11848 regname = '"';
11849
11850 if (argvars[2].v_type != VAR_UNKNOWN)
11851 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011852 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011853 if (stropt == NULL)
11854 return; /* type error */
11855 for (; *stropt != NUL; ++stropt)
11856 switch (*stropt)
11857 {
11858 case 'a': case 'A': /* append */
11859 append = TRUE;
11860 break;
11861 case 'v': case 'c': /* character-wise selection */
11862 yank_type = MCHAR;
11863 break;
11864 case 'V': case 'l': /* line-wise selection */
11865 yank_type = MLINE;
11866 break;
11867 case 'b': case Ctrl_V: /* block-wise selection */
11868 yank_type = MBLOCK;
11869 if (VIM_ISDIGIT(stropt[1]))
11870 {
11871 ++stropt;
11872 block_len = getdigits(&stropt) - 1;
11873 --stropt;
11874 }
11875 break;
11876 }
11877 }
11878
11879 if (argvars[1].v_type == VAR_LIST)
11880 {
11881 char_u **lstval;
11882 char_u **allocval;
11883 char_u buf[NUMBUFLEN];
11884 char_u **curval;
11885 char_u **curallocval;
11886 list_T *ll = argvars[1].vval.v_list;
11887 listitem_T *li;
11888 int len;
11889
11890 /* If the list is NULL handle like an empty list. */
11891 len = ll == NULL ? 0 : ll->lv_len;
11892
11893 /* First half: use for pointers to result lines; second half: use for
11894 * pointers to allocated copies. */
11895 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11896 if (lstval == NULL)
11897 return;
11898 curval = lstval;
11899 allocval = lstval + len + 2;
11900 curallocval = allocval;
11901
11902 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11903 li = li->li_next)
11904 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011905 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011906 if (strval == NULL)
11907 goto free_lstval;
11908 if (strval == buf)
11909 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011910 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011911 * overwrite the string. */
11912 strval = vim_strsave(buf);
11913 if (strval == NULL)
11914 goto free_lstval;
11915 *curallocval++ = strval;
11916 }
11917 *curval++ = strval;
11918 }
11919 *curval++ = NULL;
11920
11921 write_reg_contents_lst(regname, lstval, -1,
11922 append, yank_type, block_len);
11923free_lstval:
11924 while (curallocval > allocval)
11925 vim_free(*--curallocval);
11926 vim_free(lstval);
11927 }
11928 else
11929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011930 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011931 if (strval == NULL)
11932 return;
11933 write_reg_contents_ex(regname, strval, -1,
11934 append, yank_type, block_len);
11935 }
11936 rettv->vval.v_number = 0;
11937}
11938
11939/*
11940 * "settabvar()" function
11941 */
11942 static void
11943f_settabvar(typval_T *argvars, typval_T *rettv)
11944{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011945 tabpage_T *save_curtab;
11946 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011947 char_u *varname, *tabvarname;
11948 typval_T *varp;
11949
11950 rettv->vval.v_number = 0;
11951
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011952 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011953 return;
11954
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011955 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11956 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011957 varp = &argvars[2];
11958
Bram Moolenaar4033c552017-09-16 20:54:51 +020011959 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011960 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011961 save_curtab = curtab;
11962 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011963
11964 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11965 if (tabvarname != NULL)
11966 {
11967 STRCPY(tabvarname, "t:");
11968 STRCPY(tabvarname + 2, varname);
11969 set_var(tabvarname, varp, TRUE);
11970 vim_free(tabvarname);
11971 }
11972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011973 /* Restore current tabpage */
11974 if (valid_tabpage(save_curtab))
11975 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011976 }
11977}
11978
11979/*
11980 * "settabwinvar()" function
11981 */
11982 static void
11983f_settabwinvar(typval_T *argvars, typval_T *rettv)
11984{
11985 setwinvar(argvars, rettv, 1);
11986}
11987
11988/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011989 * "settagstack()" function
11990 */
11991 static void
11992f_settagstack(typval_T *argvars, typval_T *rettv)
11993{
11994 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11995 win_T *wp;
11996 dict_T *d;
11997 int action = 'r';
11998
11999 rettv->vval.v_number = -1;
12000
12001 // first argument: window number or id
12002 wp = find_win_by_nr_or_id(&argvars[0]);
12003 if (wp == NULL)
12004 return;
12005
12006 // second argument: dict with items to set in the tag stack
12007 if (argvars[1].v_type != VAR_DICT)
12008 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012009 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012010 return;
12011 }
12012 d = argvars[1].vval.v_dict;
12013 if (d == NULL)
12014 return;
12015
12016 // third argument: action - 'a' for append and 'r' for replace.
12017 // default is to replace the stack.
12018 if (argvars[2].v_type == VAR_UNKNOWN)
12019 action = 'r';
12020 else if (argvars[2].v_type == VAR_STRING)
12021 {
12022 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012023 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012024 if (actstr == NULL)
12025 return;
12026 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
12027 action = *actstr;
12028 else
12029 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012030 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012031 return;
12032 }
12033 }
12034 else
12035 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012036 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012037 return;
12038 }
12039
12040 if (set_tagstack(wp, d, action) == OK)
12041 rettv->vval.v_number = 0;
12042}
12043
12044/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012045 * "setwinvar()" function
12046 */
12047 static void
12048f_setwinvar(typval_T *argvars, typval_T *rettv)
12049{
12050 setwinvar(argvars, rettv, 0);
12051}
12052
12053#ifdef FEAT_CRYPT
12054/*
12055 * "sha256({string})" function
12056 */
12057 static void
12058f_sha256(typval_T *argvars, typval_T *rettv)
12059{
12060 char_u *p;
12061
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012062 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012063 rettv->vval.v_string = vim_strsave(
12064 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
12065 rettv->v_type = VAR_STRING;
12066}
12067#endif /* FEAT_CRYPT */
12068
12069/*
12070 * "shellescape({string})" function
12071 */
12072 static void
12073f_shellescape(typval_T *argvars, typval_T *rettv)
12074{
Bram Moolenaar20615522017-06-05 18:46:26 +020012075 int do_special = non_zero_arg(&argvars[1]);
12076
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012077 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012078 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079 rettv->v_type = VAR_STRING;
12080}
12081
12082/*
12083 * shiftwidth() function
12084 */
12085 static void
12086f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
12087{
Bram Moolenaarf9514162018-11-22 03:08:29 +010012088 rettv->vval.v_number = 0;
12089
12090 if (argvars[0].v_type != VAR_UNKNOWN)
12091 {
12092 long col;
12093
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012094 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010012095 if (col < 0)
12096 return; // type error; errmsg already given
12097#ifdef FEAT_VARTABS
12098 rettv->vval.v_number = get_sw_value_col(curbuf, col);
12099 return;
12100#endif
12101 }
12102
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012103 rettv->vval.v_number = get_sw_value(curbuf);
12104}
12105
Bram Moolenaar162b7142018-12-21 15:17:36 +010012106#ifdef FEAT_SIGNS
12107/*
12108 * "sign_define()" function
12109 */
12110 static void
12111f_sign_define(typval_T *argvars, typval_T *rettv)
12112{
12113 char_u *name;
12114 dict_T *dict;
12115 char_u *icon = NULL;
12116 char_u *linehl = NULL;
12117 char_u *text = NULL;
12118 char_u *texthl = NULL;
12119
12120 rettv->vval.v_number = -1;
12121
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012122 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012123 if (name == NULL)
12124 return;
12125
12126 if (argvars[1].v_type != VAR_UNKNOWN)
12127 {
12128 if (argvars[1].v_type != VAR_DICT)
12129 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012130 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012131 return;
12132 }
12133
12134 // sign attributes
12135 dict = argvars[1].vval.v_dict;
12136 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
12137 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
12138 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
12139 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
12140 if (dict_find(dict, (char_u *)"text", -1) != NULL)
12141 text = dict_get_string(dict, (char_u *)"text", TRUE);
12142 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
12143 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
12144 }
12145
12146 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
12147 rettv->vval.v_number = 0;
12148
12149 vim_free(icon);
12150 vim_free(linehl);
12151 vim_free(text);
12152 vim_free(texthl);
12153}
12154
12155/*
12156 * "sign_getdefined()" function
12157 */
12158 static void
12159f_sign_getdefined(typval_T *argvars, typval_T *rettv)
12160{
12161 char_u *name = NULL;
12162
12163 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
12164 return;
12165
12166 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012167 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012168
12169 sign_getlist(name, rettv->vval.v_list);
12170}
12171
12172/*
12173 * "sign_getplaced()" function
12174 */
12175 static void
12176f_sign_getplaced(typval_T *argvars, typval_T *rettv)
12177{
12178 buf_T *buf = NULL;
12179 dict_T *dict;
12180 dictitem_T *di;
12181 linenr_T lnum = 0;
12182 int sign_id = 0;
12183 char_u *group = NULL;
12184 int notanum = FALSE;
12185
12186 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
12187 return;
12188
12189 if (argvars[0].v_type != VAR_UNKNOWN)
12190 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012191 // get signs placed in the specified buffer
12192 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012193 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012194 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012195
12196 if (argvars[1].v_type != VAR_UNKNOWN)
12197 {
12198 if (argvars[1].v_type != VAR_DICT ||
12199 ((dict = argvars[1].vval.v_dict) == NULL))
12200 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012201 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012202 return;
12203 }
12204 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
12205 {
12206 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012207 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012208 if (notanum)
12209 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012210 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012211 }
12212 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
12213 {
12214 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012215 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012216 if (notanum)
12217 return;
12218 }
12219 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
12220 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012221 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012222 if (group == NULL)
12223 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010012224 if (*group == '\0') // empty string means global group
12225 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012226 }
12227 }
12228 }
12229
12230 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
12231}
12232
12233/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012234 * "sign_jump()" function
12235 */
12236 static void
12237f_sign_jump(typval_T *argvars, typval_T *rettv)
12238{
12239 int sign_id;
12240 char_u *sign_group = NULL;
12241 buf_T *buf;
12242 int notanum = FALSE;
12243
12244 rettv->vval.v_number = -1;
12245
Bram Moolenaarbdace832019-03-02 10:13:42 +010012246 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012247 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
12248 if (notanum)
12249 return;
12250 if (sign_id <= 0)
12251 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012252 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012253 return;
12254 }
12255
12256 // Sign group
12257 sign_group = tv_get_string_chk(&argvars[1]);
12258 if (sign_group == NULL)
12259 return;
12260 if (sign_group[0] == '\0')
12261 sign_group = NULL; // global sign group
12262 else
12263 {
12264 sign_group = vim_strsave(sign_group);
12265 if (sign_group == NULL)
12266 return;
12267 }
12268
12269 // Buffer to place the sign
12270 buf = get_buf_arg(&argvars[2]);
12271 if (buf == NULL)
12272 goto cleanup;
12273
12274 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
12275
12276cleanup:
12277 vim_free(sign_group);
12278}
12279
12280/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010012281 * "sign_place()" function
12282 */
12283 static void
12284f_sign_place(typval_T *argvars, typval_T *rettv)
12285{
12286 int sign_id;
12287 char_u *group = NULL;
12288 char_u *sign_name;
12289 buf_T *buf;
12290 dict_T *dict;
12291 dictitem_T *di;
12292 linenr_T lnum = 0;
12293 int prio = SIGN_DEF_PRIO;
12294 int notanum = FALSE;
12295
12296 rettv->vval.v_number = -1;
12297
Bram Moolenaarbdace832019-03-02 10:13:42 +010012298 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012299 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012300 if (notanum)
12301 return;
12302 if (sign_id < 0)
12303 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012304 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012305 return;
12306 }
12307
12308 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012309 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012310 if (group == NULL)
12311 return;
12312 if (group[0] == '\0')
12313 group = NULL; // global sign group
12314 else
12315 {
12316 group = vim_strsave(group);
12317 if (group == NULL)
12318 return;
12319 }
12320
12321 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012322 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012323 if (sign_name == NULL)
12324 goto cleanup;
12325
12326 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012327 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012328 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012329 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012330
12331 if (argvars[4].v_type != VAR_UNKNOWN)
12332 {
12333 if (argvars[4].v_type != VAR_DICT ||
12334 ((dict = argvars[4].vval.v_dict) == NULL))
12335 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012336 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012337 goto cleanup;
12338 }
12339
12340 // Line number where the sign is to be placed
12341 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
12342 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012343 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012344 if (notanum)
12345 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012346 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012347 }
12348 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
12349 {
12350 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012351 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012352 if (notanum)
12353 goto cleanup;
12354 }
12355 }
12356
12357 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
12358 rettv->vval.v_number = sign_id;
12359
12360cleanup:
12361 vim_free(group);
12362}
12363
12364/*
12365 * "sign_undefine()" function
12366 */
12367 static void
12368f_sign_undefine(typval_T *argvars, typval_T *rettv)
12369{
12370 char_u *name;
12371
12372 rettv->vval.v_number = -1;
12373
12374 if (argvars[0].v_type == VAR_UNKNOWN)
12375 {
12376 // Free all the signs
12377 free_signs();
12378 rettv->vval.v_number = 0;
12379 }
12380 else
12381 {
12382 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012383 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012384 if (name == NULL)
12385 return;
12386
12387 if (sign_undefine_by_name(name) == OK)
12388 rettv->vval.v_number = 0;
12389 }
12390}
12391
12392/*
12393 * "sign_unplace()" function
12394 */
12395 static void
12396f_sign_unplace(typval_T *argvars, typval_T *rettv)
12397{
12398 dict_T *dict;
12399 dictitem_T *di;
12400 int sign_id = 0;
12401 buf_T *buf = NULL;
12402 char_u *group = NULL;
12403
12404 rettv->vval.v_number = -1;
12405
12406 if (argvars[0].v_type != VAR_STRING)
12407 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012408 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012409 return;
12410 }
12411
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012412 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012413 if (group[0] == '\0')
12414 group = NULL; // global sign group
12415 else
12416 {
12417 group = vim_strsave(group);
12418 if (group == NULL)
12419 return;
12420 }
12421
12422 if (argvars[1].v_type != VAR_UNKNOWN)
12423 {
12424 if (argvars[1].v_type != VAR_DICT)
12425 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012426 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012427 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012428 }
12429 dict = argvars[1].vval.v_dict;
12430
12431 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
12432 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012433 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012434 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012435 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012436 }
12437 if (dict_find(dict, (char_u *)"id", -1) != NULL)
12438 sign_id = dict_get_number(dict, (char_u *)"id");
12439 }
12440
12441 if (buf == NULL)
12442 {
12443 // Delete the sign in all the buffers
12444 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012445 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012446 rettv->vval.v_number = 0;
12447 }
12448 else
12449 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012450 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012451 rettv->vval.v_number = 0;
12452 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012453
12454cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010012455 vim_free(group);
12456}
12457#endif
12458
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012459/*
12460 * "simplify()" function
12461 */
12462 static void
12463f_simplify(typval_T *argvars, typval_T *rettv)
12464{
12465 char_u *p;
12466
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012467 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012468 rettv->vval.v_string = vim_strsave(p);
12469 simplify_filename(rettv->vval.v_string); /* simplify in place */
12470 rettv->v_type = VAR_STRING;
12471}
12472
12473#ifdef FEAT_FLOAT
12474/*
12475 * "sin()" function
12476 */
12477 static void
12478f_sin(typval_T *argvars, typval_T *rettv)
12479{
12480 float_T f = 0.0;
12481
12482 rettv->v_type = VAR_FLOAT;
12483 if (get_float_arg(argvars, &f) == OK)
12484 rettv->vval.v_float = sin(f);
12485 else
12486 rettv->vval.v_float = 0.0;
12487}
12488
12489/*
12490 * "sinh()" function
12491 */
12492 static void
12493f_sinh(typval_T *argvars, typval_T *rettv)
12494{
12495 float_T f = 0.0;
12496
12497 rettv->v_type = VAR_FLOAT;
12498 if (get_float_arg(argvars, &f) == OK)
12499 rettv->vval.v_float = sinh(f);
12500 else
12501 rettv->vval.v_float = 0.0;
12502}
12503#endif
12504
Bram Moolenaareae1b912019-05-09 15:12:55 +020012505static int item_compare(const void *s1, const void *s2);
12506static int item_compare2(const void *s1, const void *s2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012507
12508/* struct used in the array that's given to qsort() */
12509typedef struct
12510{
12511 listitem_T *item;
12512 int idx;
12513} sortItem_T;
12514
12515/* struct storing information about current sort */
12516typedef struct
12517{
12518 int item_compare_ic;
12519 int item_compare_numeric;
12520 int item_compare_numbers;
12521#ifdef FEAT_FLOAT
12522 int item_compare_float;
12523#endif
12524 char_u *item_compare_func;
12525 partial_T *item_compare_partial;
12526 dict_T *item_compare_selfdict;
12527 int item_compare_func_err;
12528 int item_compare_keep_zero;
12529} sortinfo_T;
12530static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012531#define ITEM_COMPARE_FAIL 999
12532
12533/*
12534 * Compare functions for f_sort() and f_uniq() below.
12535 */
12536 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012537item_compare(const void *s1, const void *s2)
12538{
12539 sortItem_T *si1, *si2;
12540 typval_T *tv1, *tv2;
12541 char_u *p1, *p2;
12542 char_u *tofree1 = NULL, *tofree2 = NULL;
12543 int res;
12544 char_u numbuf1[NUMBUFLEN];
12545 char_u numbuf2[NUMBUFLEN];
12546
12547 si1 = (sortItem_T *)s1;
12548 si2 = (sortItem_T *)s2;
12549 tv1 = &si1->item->li_tv;
12550 tv2 = &si2->item->li_tv;
12551
12552 if (sortinfo->item_compare_numbers)
12553 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012554 varnumber_T v1 = tv_get_number(tv1);
12555 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012556
12557 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12558 }
12559
12560#ifdef FEAT_FLOAT
12561 if (sortinfo->item_compare_float)
12562 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012563 float_T v1 = tv_get_float(tv1);
12564 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012565
12566 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12567 }
12568#endif
12569
12570 /* tv2string() puts quotes around a string and allocates memory. Don't do
12571 * that for string variables. Use a single quote when comparing with a
12572 * non-string to do what the docs promise. */
12573 if (tv1->v_type == VAR_STRING)
12574 {
12575 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12576 p1 = (char_u *)"'";
12577 else
12578 p1 = tv1->vval.v_string;
12579 }
12580 else
12581 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12582 if (tv2->v_type == VAR_STRING)
12583 {
12584 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12585 p2 = (char_u *)"'";
12586 else
12587 p2 = tv2->vval.v_string;
12588 }
12589 else
12590 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12591 if (p1 == NULL)
12592 p1 = (char_u *)"";
12593 if (p2 == NULL)
12594 p2 = (char_u *)"";
12595 if (!sortinfo->item_compare_numeric)
12596 {
12597 if (sortinfo->item_compare_ic)
12598 res = STRICMP(p1, p2);
12599 else
12600 res = STRCMP(p1, p2);
12601 }
12602 else
12603 {
12604 double n1, n2;
12605 n1 = strtod((char *)p1, (char **)&p1);
12606 n2 = strtod((char *)p2, (char **)&p2);
12607 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12608 }
12609
12610 /* When the result would be zero, compare the item indexes. Makes the
12611 * sort stable. */
12612 if (res == 0 && !sortinfo->item_compare_keep_zero)
12613 res = si1->idx > si2->idx ? 1 : -1;
12614
12615 vim_free(tofree1);
12616 vim_free(tofree2);
12617 return res;
12618}
12619
12620 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012621item_compare2(const void *s1, const void *s2)
12622{
12623 sortItem_T *si1, *si2;
12624 int res;
12625 typval_T rettv;
12626 typval_T argv[3];
12627 int dummy;
12628 char_u *func_name;
12629 partial_T *partial = sortinfo->item_compare_partial;
12630
12631 /* shortcut after failure in previous call; compare all items equal */
12632 if (sortinfo->item_compare_func_err)
12633 return 0;
12634
12635 si1 = (sortItem_T *)s1;
12636 si2 = (sortItem_T *)s2;
12637
12638 if (partial == NULL)
12639 func_name = sortinfo->item_compare_func;
12640 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012641 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012642
12643 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12644 * in the copy without changing the original list items. */
12645 copy_tv(&si1->item->li_tv, &argv[0]);
12646 copy_tv(&si2->item->li_tv, &argv[1]);
12647
12648 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
Bram Moolenaar6ed88192019-05-11 18:37:44 +020012649 res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012650 partial, sortinfo->item_compare_selfdict);
12651 clear_tv(&argv[0]);
12652 clear_tv(&argv[1]);
12653
12654 if (res == FAIL)
12655 res = ITEM_COMPARE_FAIL;
12656 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012657 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012658 if (sortinfo->item_compare_func_err)
12659 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12660 clear_tv(&rettv);
12661
12662 /* When the result would be zero, compare the pointers themselves. Makes
12663 * the sort stable. */
12664 if (res == 0 && !sortinfo->item_compare_keep_zero)
12665 res = si1->idx > si2->idx ? 1 : -1;
12666
12667 return res;
12668}
12669
12670/*
12671 * "sort({list})" function
12672 */
12673 static void
12674do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12675{
12676 list_T *l;
12677 listitem_T *li;
12678 sortItem_T *ptrs;
12679 sortinfo_T *old_sortinfo;
12680 sortinfo_T info;
12681 long len;
12682 long i;
12683
12684 /* Pointer to current info struct used in compare function. Save and
12685 * restore the current one for nested calls. */
12686 old_sortinfo = sortinfo;
12687 sortinfo = &info;
12688
12689 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012690 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012691 else
12692 {
12693 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012694 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012695 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12696 TRUE))
12697 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012698 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012699
12700 len = list_len(l);
12701 if (len <= 1)
12702 goto theend; /* short list sorts pretty quickly */
12703
12704 info.item_compare_ic = FALSE;
12705 info.item_compare_numeric = FALSE;
12706 info.item_compare_numbers = FALSE;
12707#ifdef FEAT_FLOAT
12708 info.item_compare_float = FALSE;
12709#endif
12710 info.item_compare_func = NULL;
12711 info.item_compare_partial = NULL;
12712 info.item_compare_selfdict = NULL;
12713 if (argvars[1].v_type != VAR_UNKNOWN)
12714 {
12715 /* optional second argument: {func} */
12716 if (argvars[1].v_type == VAR_FUNC)
12717 info.item_compare_func = argvars[1].vval.v_string;
12718 else if (argvars[1].v_type == VAR_PARTIAL)
12719 info.item_compare_partial = argvars[1].vval.v_partial;
12720 else
12721 {
12722 int error = FALSE;
12723
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012724 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012725 if (error)
12726 goto theend; /* type error; errmsg already given */
12727 if (i == 1)
12728 info.item_compare_ic = TRUE;
12729 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012730 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012731 else if (i != 0)
12732 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012733 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012734 goto theend;
12735 }
12736 if (info.item_compare_func != NULL)
12737 {
12738 if (*info.item_compare_func == NUL)
12739 {
12740 /* empty string means default sort */
12741 info.item_compare_func = NULL;
12742 }
12743 else if (STRCMP(info.item_compare_func, "n") == 0)
12744 {
12745 info.item_compare_func = NULL;
12746 info.item_compare_numeric = TRUE;
12747 }
12748 else if (STRCMP(info.item_compare_func, "N") == 0)
12749 {
12750 info.item_compare_func = NULL;
12751 info.item_compare_numbers = TRUE;
12752 }
12753#ifdef FEAT_FLOAT
12754 else if (STRCMP(info.item_compare_func, "f") == 0)
12755 {
12756 info.item_compare_func = NULL;
12757 info.item_compare_float = TRUE;
12758 }
12759#endif
12760 else if (STRCMP(info.item_compare_func, "i") == 0)
12761 {
12762 info.item_compare_func = NULL;
12763 info.item_compare_ic = TRUE;
12764 }
12765 }
12766 }
12767
12768 if (argvars[2].v_type != VAR_UNKNOWN)
12769 {
12770 /* optional third argument: {dict} */
12771 if (argvars[2].v_type != VAR_DICT)
12772 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012773 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012774 goto theend;
12775 }
12776 info.item_compare_selfdict = argvars[2].vval.v_dict;
12777 }
12778 }
12779
12780 /* Make an array with each entry pointing to an item in the List. */
12781 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12782 if (ptrs == NULL)
12783 goto theend;
12784
12785 i = 0;
12786 if (sort)
12787 {
12788 /* sort(): ptrs will be the list to sort */
12789 for (li = l->lv_first; li != NULL; li = li->li_next)
12790 {
12791 ptrs[i].item = li;
12792 ptrs[i].idx = i;
12793 ++i;
12794 }
12795
12796 info.item_compare_func_err = FALSE;
12797 info.item_compare_keep_zero = FALSE;
12798 /* test the compare function */
12799 if ((info.item_compare_func != NULL
12800 || info.item_compare_partial != NULL)
12801 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12802 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012803 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012804 else
12805 {
12806 /* Sort the array with item pointers. */
12807 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12808 info.item_compare_func == NULL
12809 && info.item_compare_partial == NULL
12810 ? item_compare : item_compare2);
12811
12812 if (!info.item_compare_func_err)
12813 {
12814 /* Clear the List and append the items in sorted order. */
12815 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12816 l->lv_len = 0;
12817 for (i = 0; i < len; ++i)
12818 list_append(l, ptrs[i].item);
12819 }
12820 }
12821 }
12822 else
12823 {
12824 int (*item_compare_func_ptr)(const void *, const void *);
12825
12826 /* f_uniq(): ptrs will be a stack of items to remove */
12827 info.item_compare_func_err = FALSE;
12828 info.item_compare_keep_zero = TRUE;
12829 item_compare_func_ptr = info.item_compare_func != NULL
12830 || info.item_compare_partial != NULL
12831 ? item_compare2 : item_compare;
12832
12833 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12834 li = li->li_next)
12835 {
12836 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12837 == 0)
12838 ptrs[i++].item = li;
12839 if (info.item_compare_func_err)
12840 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012841 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012842 break;
12843 }
12844 }
12845
12846 if (!info.item_compare_func_err)
12847 {
12848 while (--i >= 0)
12849 {
12850 li = ptrs[i].item->li_next;
12851 ptrs[i].item->li_next = li->li_next;
12852 if (li->li_next != NULL)
12853 li->li_next->li_prev = ptrs[i].item;
12854 else
12855 l->lv_last = ptrs[i].item;
12856 list_fix_watch(l, li);
12857 listitem_free(li);
12858 l->lv_len--;
12859 }
12860 }
12861 }
12862
12863 vim_free(ptrs);
12864 }
12865theend:
12866 sortinfo = old_sortinfo;
12867}
12868
12869/*
12870 * "sort({list})" function
12871 */
12872 static void
12873f_sort(typval_T *argvars, typval_T *rettv)
12874{
12875 do_sort_uniq(argvars, rettv, TRUE);
12876}
12877
12878/*
12879 * "uniq({list})" function
12880 */
12881 static void
12882f_uniq(typval_T *argvars, typval_T *rettv)
12883{
12884 do_sort_uniq(argvars, rettv, FALSE);
12885}
12886
12887/*
12888 * "soundfold({word})" function
12889 */
12890 static void
12891f_soundfold(typval_T *argvars, typval_T *rettv)
12892{
12893 char_u *s;
12894
12895 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012896 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012897#ifdef FEAT_SPELL
12898 rettv->vval.v_string = eval_soundfold(s);
12899#else
12900 rettv->vval.v_string = vim_strsave(s);
12901#endif
12902}
12903
12904/*
12905 * "spellbadword()" function
12906 */
12907 static void
12908f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12909{
12910 char_u *word = (char_u *)"";
12911 hlf_T attr = HLF_COUNT;
12912 int len = 0;
12913
12914 if (rettv_list_alloc(rettv) == FAIL)
12915 return;
12916
12917#ifdef FEAT_SPELL
12918 if (argvars[0].v_type == VAR_UNKNOWN)
12919 {
12920 /* Find the start and length of the badly spelled word. */
12921 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12922 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012923 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012924 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012925 curwin->w_set_curswant = TRUE;
12926 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012927 }
12928 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012930 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012931 int capcol = -1;
12932
12933 if (str != NULL)
12934 {
12935 /* Check the argument for spelling. */
12936 while (*str != NUL)
12937 {
12938 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12939 if (attr != HLF_COUNT)
12940 {
12941 word = str;
12942 break;
12943 }
12944 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012945 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012946 }
12947 }
12948 }
12949#endif
12950
12951 list_append_string(rettv->vval.v_list, word, len);
12952 list_append_string(rettv->vval.v_list, (char_u *)(
12953 attr == HLF_SPB ? "bad" :
12954 attr == HLF_SPR ? "rare" :
12955 attr == HLF_SPL ? "local" :
12956 attr == HLF_SPC ? "caps" :
12957 ""), -1);
12958}
12959
12960/*
12961 * "spellsuggest()" function
12962 */
12963 static void
12964f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12965{
12966#ifdef FEAT_SPELL
12967 char_u *str;
12968 int typeerr = FALSE;
12969 int maxcount;
12970 garray_T ga;
12971 int i;
12972 listitem_T *li;
12973 int need_capital = FALSE;
12974#endif
12975
12976 if (rettv_list_alloc(rettv) == FAIL)
12977 return;
12978
12979#ifdef FEAT_SPELL
12980 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12981 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012982 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012983 if (argvars[1].v_type != VAR_UNKNOWN)
12984 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012985 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012986 if (maxcount <= 0)
12987 return;
12988 if (argvars[2].v_type != VAR_UNKNOWN)
12989 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012990 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012991 if (typeerr)
12992 return;
12993 }
12994 }
12995 else
12996 maxcount = 25;
12997
12998 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12999
13000 for (i = 0; i < ga.ga_len; ++i)
13001 {
13002 str = ((char_u **)ga.ga_data)[i];
13003
13004 li = listitem_alloc();
13005 if (li == NULL)
13006 vim_free(str);
13007 else
13008 {
13009 li->li_tv.v_type = VAR_STRING;
13010 li->li_tv.v_lock = 0;
13011 li->li_tv.vval.v_string = str;
13012 list_append(rettv->vval.v_list, li);
13013 }
13014 }
13015 ga_clear(&ga);
13016 }
13017#endif
13018}
13019
13020 static void
13021f_split(typval_T *argvars, typval_T *rettv)
13022{
13023 char_u *str;
13024 char_u *end;
13025 char_u *pat = NULL;
13026 regmatch_T regmatch;
13027 char_u patbuf[NUMBUFLEN];
13028 char_u *save_cpo;
13029 int match;
13030 colnr_T col = 0;
13031 int keepempty = FALSE;
13032 int typeerr = FALSE;
13033
13034 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
13035 save_cpo = p_cpo;
13036 p_cpo = (char_u *)"";
13037
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013038 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013039 if (argvars[1].v_type != VAR_UNKNOWN)
13040 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013041 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013042 if (pat == NULL)
13043 typeerr = TRUE;
13044 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013045 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013046 }
13047 if (pat == NULL || *pat == NUL)
13048 pat = (char_u *)"[\\x01- ]\\+";
13049
13050 if (rettv_list_alloc(rettv) == FAIL)
13051 return;
13052 if (typeerr)
13053 return;
13054
13055 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
13056 if (regmatch.regprog != NULL)
13057 {
13058 regmatch.rm_ic = FALSE;
13059 while (*str != NUL || keepempty)
13060 {
13061 if (*str == NUL)
13062 match = FALSE; /* empty item at the end */
13063 else
13064 match = vim_regexec_nl(&regmatch, str, col);
13065 if (match)
13066 end = regmatch.startp[0];
13067 else
13068 end = str + STRLEN(str);
13069 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
13070 && *str != NUL && match && end < regmatch.endp[0]))
13071 {
13072 if (list_append_string(rettv->vval.v_list, str,
13073 (int)(end - str)) == FAIL)
13074 break;
13075 }
13076 if (!match)
13077 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010013078 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013079 if (regmatch.endp[0] > str)
13080 col = 0;
13081 else
Bram Moolenaar13505972019-01-24 15:04:48 +010013082 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013083 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013084 str = regmatch.endp[0];
13085 }
13086
13087 vim_regfree(regmatch.regprog);
13088 }
13089
13090 p_cpo = save_cpo;
13091}
13092
13093#ifdef FEAT_FLOAT
13094/*
13095 * "sqrt()" function
13096 */
13097 static void
13098f_sqrt(typval_T *argvars, typval_T *rettv)
13099{
13100 float_T f = 0.0;
13101
13102 rettv->v_type = VAR_FLOAT;
13103 if (get_float_arg(argvars, &f) == OK)
13104 rettv->vval.v_float = sqrt(f);
13105 else
13106 rettv->vval.v_float = 0.0;
13107}
13108
13109/*
13110 * "str2float()" function
13111 */
13112 static void
13113f_str2float(typval_T *argvars, typval_T *rettv)
13114{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013115 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010013116 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013117
Bram Moolenaar08243d22017-01-10 16:12:29 +010013118 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013119 p = skipwhite(p + 1);
13120 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010013121 if (isneg)
13122 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013123 rettv->v_type = VAR_FLOAT;
13124}
13125#endif
13126
13127/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020013128 * "str2list()" function
13129 */
13130 static void
13131f_str2list(typval_T *argvars, typval_T *rettv)
13132{
13133 char_u *p;
13134 int utf8 = FALSE;
13135
13136 if (rettv_list_alloc(rettv) == FAIL)
13137 return;
13138
13139 if (argvars[1].v_type != VAR_UNKNOWN)
13140 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
13141
13142 p = tv_get_string(&argvars[0]);
13143
13144 if (has_mbyte || utf8)
13145 {
13146 int (*ptr2len)(char_u *);
13147 int (*ptr2char)(char_u *);
13148
13149 if (utf8 || enc_utf8)
13150 {
13151 ptr2len = utf_ptr2len;
13152 ptr2char = utf_ptr2char;
13153 }
13154 else
13155 {
13156 ptr2len = mb_ptr2len;
13157 ptr2char = mb_ptr2char;
13158 }
13159
13160 for ( ; *p != NUL; p += (*ptr2len)(p))
13161 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
13162 }
13163 else
13164 for ( ; *p != NUL; ++p)
13165 list_append_number(rettv->vval.v_list, *p);
13166}
13167
13168/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013169 * "str2nr()" function
13170 */
13171 static void
13172f_str2nr(typval_T *argvars, typval_T *rettv)
13173{
13174 int base = 10;
13175 char_u *p;
13176 varnumber_T n;
13177 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010013178 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013179
13180 if (argvars[1].v_type != VAR_UNKNOWN)
13181 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013182 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013183 if (base != 2 && base != 8 && base != 10 && base != 16)
13184 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013185 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186 return;
13187 }
13188 }
13189
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013190 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010013191 isneg = (*p == '-');
13192 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013193 p = skipwhite(p + 1);
13194 switch (base)
13195 {
13196 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
13197 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
13198 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
13199 default: what = 0;
13200 }
13201 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010013202 if (isneg)
13203 rettv->vval.v_number = -n;
13204 else
13205 rettv->vval.v_number = n;
13206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013207}
13208
13209#ifdef HAVE_STRFTIME
13210/*
13211 * "strftime({format}[, {time}])" function
13212 */
13213 static void
13214f_strftime(typval_T *argvars, typval_T *rettv)
13215{
13216 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020013217# ifdef HAVE_LOCALTIME_R
13218 struct tm tmval;
13219# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013220 struct tm *curtime;
13221 time_t seconds;
13222 char_u *p;
13223
13224 rettv->v_type = VAR_STRING;
13225
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013226 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013227 if (argvars[1].v_type == VAR_UNKNOWN)
13228 seconds = time(NULL);
13229 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013230 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar63d25552019-05-10 21:28:38 +020013231# ifdef HAVE_LOCALTIME_R
13232 curtime = localtime_r(&seconds, &tmval);
13233# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013234 curtime = localtime(&seconds);
Bram Moolenaar63d25552019-05-10 21:28:38 +020013235# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013236 /* MSVC returns NULL for an invalid value of seconds. */
13237 if (curtime == NULL)
13238 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
13239 else
13240 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013241 vimconv_T conv;
13242 char_u *enc;
13243
13244 conv.vc_type = CONV_NONE;
13245 enc = enc_locale();
13246 convert_setup(&conv, p_enc, enc);
13247 if (conv.vc_type != CONV_NONE)
13248 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013249 if (p != NULL)
13250 (void)strftime((char *)result_buf, sizeof(result_buf),
13251 (char *)p, curtime);
13252 else
13253 result_buf[0] = NUL;
13254
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013255 if (conv.vc_type != CONV_NONE)
13256 vim_free(p);
13257 convert_setup(&conv, enc, p_enc);
13258 if (conv.vc_type != CONV_NONE)
13259 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
13260 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013261 rettv->vval.v_string = vim_strsave(result_buf);
13262
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013263 /* Release conversion descriptors */
13264 convert_setup(&conv, NULL, NULL);
13265 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013266 }
13267}
13268#endif
13269
13270/*
13271 * "strgetchar()" function
13272 */
13273 static void
13274f_strgetchar(typval_T *argvars, typval_T *rettv)
13275{
13276 char_u *str;
13277 int len;
13278 int error = FALSE;
13279 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010013280 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013281
13282 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013283 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013284 if (str == NULL)
13285 return;
13286 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013287 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013288 if (error)
13289 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013290
Bram Moolenaar13505972019-01-24 15:04:48 +010013291 while (charidx >= 0 && byteidx < len)
13292 {
13293 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013294 {
Bram Moolenaar13505972019-01-24 15:04:48 +010013295 rettv->vval.v_number = mb_ptr2char(str + byteidx);
13296 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013297 }
Bram Moolenaar13505972019-01-24 15:04:48 +010013298 --charidx;
13299 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013300 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013301}
13302
13303/*
13304 * "stridx()" function
13305 */
13306 static void
13307f_stridx(typval_T *argvars, typval_T *rettv)
13308{
13309 char_u buf[NUMBUFLEN];
13310 char_u *needle;
13311 char_u *haystack;
13312 char_u *save_haystack;
13313 char_u *pos;
13314 int start_idx;
13315
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013316 needle = tv_get_string_chk(&argvars[1]);
13317 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013318 rettv->vval.v_number = -1;
13319 if (needle == NULL || haystack == NULL)
13320 return; /* type error; errmsg already given */
13321
13322 if (argvars[2].v_type != VAR_UNKNOWN)
13323 {
13324 int error = FALSE;
13325
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013326 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013327 if (error || start_idx >= (int)STRLEN(haystack))
13328 return;
13329 if (start_idx >= 0)
13330 haystack += start_idx;
13331 }
13332
13333 pos = (char_u *)strstr((char *)haystack, (char *)needle);
13334 if (pos != NULL)
13335 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
13336}
13337
13338/*
13339 * "string()" function
13340 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010013341 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013342f_string(typval_T *argvars, typval_T *rettv)
13343{
13344 char_u *tofree;
13345 char_u numbuf[NUMBUFLEN];
13346
13347 rettv->v_type = VAR_STRING;
13348 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
13349 get_copyID());
13350 /* Make a copy if we have a value but it's not in allocated memory. */
13351 if (rettv->vval.v_string != NULL && tofree == NULL)
13352 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
13353}
13354
13355/*
13356 * "strlen()" function
13357 */
13358 static void
13359f_strlen(typval_T *argvars, typval_T *rettv)
13360{
13361 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013362 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013363}
13364
13365/*
13366 * "strchars()" function
13367 */
13368 static void
13369f_strchars(typval_T *argvars, typval_T *rettv)
13370{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013371 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013372 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013373 varnumber_T len = 0;
13374 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013375
13376 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013377 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013378 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013379 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013380 else
13381 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013382 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
13383 while (*s != NUL)
13384 {
13385 func_mb_ptr2char_adv(&s);
13386 ++len;
13387 }
13388 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013389 }
13390}
13391
13392/*
13393 * "strdisplaywidth()" function
13394 */
13395 static void
13396f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
13397{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013398 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013399 int col = 0;
13400
13401 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013402 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013403
13404 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
13405}
13406
13407/*
13408 * "strwidth()" function
13409 */
13410 static void
13411f_strwidth(typval_T *argvars, typval_T *rettv)
13412{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013413 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013414
Bram Moolenaar13505972019-01-24 15:04:48 +010013415 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013416}
13417
13418/*
13419 * "strcharpart()" function
13420 */
13421 static void
13422f_strcharpart(typval_T *argvars, typval_T *rettv)
13423{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013424 char_u *p;
13425 int nchar;
13426 int nbyte = 0;
13427 int charlen;
13428 int len = 0;
13429 int slen;
13430 int error = FALSE;
13431
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013432 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013433 slen = (int)STRLEN(p);
13434
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013435 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013436 if (!error)
13437 {
13438 if (nchar > 0)
13439 while (nchar > 0 && nbyte < slen)
13440 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020013441 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013442 --nchar;
13443 }
13444 else
13445 nbyte = nchar;
13446 if (argvars[2].v_type != VAR_UNKNOWN)
13447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013448 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013449 while (charlen > 0 && nbyte + len < slen)
13450 {
13451 int off = nbyte + len;
13452
13453 if (off < 0)
13454 len += 1;
13455 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020013456 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013457 --charlen;
13458 }
13459 }
13460 else
13461 len = slen - nbyte; /* default: all bytes that are available. */
13462 }
13463
13464 /*
13465 * Only return the overlap between the specified part and the actual
13466 * string.
13467 */
13468 if (nbyte < 0)
13469 {
13470 len += nbyte;
13471 nbyte = 0;
13472 }
13473 else if (nbyte > slen)
13474 nbyte = slen;
13475 if (len < 0)
13476 len = 0;
13477 else if (nbyte + len > slen)
13478 len = slen - nbyte;
13479
13480 rettv->v_type = VAR_STRING;
13481 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013482}
13483
13484/*
13485 * "strpart()" function
13486 */
13487 static void
13488f_strpart(typval_T *argvars, typval_T *rettv)
13489{
13490 char_u *p;
13491 int n;
13492 int len;
13493 int slen;
13494 int error = FALSE;
13495
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013496 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013497 slen = (int)STRLEN(p);
13498
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013499 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013500 if (error)
13501 len = 0;
13502 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013503 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013504 else
13505 len = slen - n; /* default len: all bytes that are available. */
13506
13507 /*
13508 * Only return the overlap between the specified part and the actual
13509 * string.
13510 */
13511 if (n < 0)
13512 {
13513 len += n;
13514 n = 0;
13515 }
13516 else if (n > slen)
13517 n = slen;
13518 if (len < 0)
13519 len = 0;
13520 else if (n + len > slen)
13521 len = slen - n;
13522
13523 rettv->v_type = VAR_STRING;
13524 rettv->vval.v_string = vim_strnsave(p + n, len);
13525}
13526
13527/*
13528 * "strridx()" function
13529 */
13530 static void
13531f_strridx(typval_T *argvars, typval_T *rettv)
13532{
13533 char_u buf[NUMBUFLEN];
13534 char_u *needle;
13535 char_u *haystack;
13536 char_u *rest;
13537 char_u *lastmatch = NULL;
13538 int haystack_len, end_idx;
13539
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013540 needle = tv_get_string_chk(&argvars[1]);
13541 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013542
13543 rettv->vval.v_number = -1;
13544 if (needle == NULL || haystack == NULL)
13545 return; /* type error; errmsg already given */
13546
13547 haystack_len = (int)STRLEN(haystack);
13548 if (argvars[2].v_type != VAR_UNKNOWN)
13549 {
13550 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013551 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013552 if (end_idx < 0)
13553 return; /* can never find a match */
13554 }
13555 else
13556 end_idx = haystack_len;
13557
13558 if (*needle == NUL)
13559 {
13560 /* Empty string matches past the end. */
13561 lastmatch = haystack + end_idx;
13562 }
13563 else
13564 {
13565 for (rest = haystack; *rest != '\0'; ++rest)
13566 {
13567 rest = (char_u *)strstr((char *)rest, (char *)needle);
13568 if (rest == NULL || rest > haystack + end_idx)
13569 break;
13570 lastmatch = rest;
13571 }
13572 }
13573
13574 if (lastmatch == NULL)
13575 rettv->vval.v_number = -1;
13576 else
13577 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13578}
13579
13580/*
13581 * "strtrans()" function
13582 */
13583 static void
13584f_strtrans(typval_T *argvars, typval_T *rettv)
13585{
13586 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013587 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013588}
13589
13590/*
13591 * "submatch()" function
13592 */
13593 static void
13594f_submatch(typval_T *argvars, typval_T *rettv)
13595{
13596 int error = FALSE;
13597 int no;
13598 int retList = 0;
13599
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013600 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013601 if (error)
13602 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013603 if (no < 0 || no >= NSUBEXP)
13604 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013605 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013606 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013607 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013608 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013609 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013610 if (error)
13611 return;
13612
13613 if (retList == 0)
13614 {
13615 rettv->v_type = VAR_STRING;
13616 rettv->vval.v_string = reg_submatch(no);
13617 }
13618 else
13619 {
13620 rettv->v_type = VAR_LIST;
13621 rettv->vval.v_list = reg_submatch_list(no);
13622 }
13623}
13624
13625/*
13626 * "substitute()" function
13627 */
13628 static void
13629f_substitute(typval_T *argvars, typval_T *rettv)
13630{
13631 char_u patbuf[NUMBUFLEN];
13632 char_u subbuf[NUMBUFLEN];
13633 char_u flagsbuf[NUMBUFLEN];
13634
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013635 char_u *str = tv_get_string_chk(&argvars[0]);
13636 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013637 char_u *sub = NULL;
13638 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013639 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013640
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013641 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13642 expr = &argvars[2];
13643 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013644 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013646 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013647 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13648 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013649 rettv->vval.v_string = NULL;
13650 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013651 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013652}
13653
13654/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013655 * "swapinfo(swap_filename)" function
13656 */
13657 static void
13658f_swapinfo(typval_T *argvars, typval_T *rettv)
13659{
13660 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013661 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013662}
13663
13664/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013665 * "swapname(expr)" function
13666 */
13667 static void
13668f_swapname(typval_T *argvars, typval_T *rettv)
13669{
13670 buf_T *buf;
13671
13672 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013673 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013674 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13675 || buf->b_ml.ml_mfp->mf_fname == NULL)
13676 rettv->vval.v_string = NULL;
13677 else
13678 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13679}
13680
13681/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013682 * "synID(lnum, col, trans)" function
13683 */
13684 static void
13685f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13686{
13687 int id = 0;
13688#ifdef FEAT_SYN_HL
13689 linenr_T lnum;
13690 colnr_T col;
13691 int trans;
13692 int transerr = FALSE;
13693
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013694 lnum = tv_get_lnum(argvars); /* -1 on type error */
13695 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13696 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013697
13698 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13699 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13700 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13701#endif
13702
13703 rettv->vval.v_number = id;
13704}
13705
13706/*
13707 * "synIDattr(id, what [, mode])" function
13708 */
13709 static void
13710f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13711{
13712 char_u *p = NULL;
13713#ifdef FEAT_SYN_HL
13714 int id;
13715 char_u *what;
13716 char_u *mode;
13717 char_u modebuf[NUMBUFLEN];
13718 int modec;
13719
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013720 id = (int)tv_get_number(&argvars[0]);
13721 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013722 if (argvars[2].v_type != VAR_UNKNOWN)
13723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013724 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013725 modec = TOLOWER_ASC(mode[0]);
13726 if (modec != 't' && modec != 'c' && modec != 'g')
13727 modec = 0; /* replace invalid with current */
13728 }
13729 else
13730 {
13731#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13732 if (USE_24BIT)
13733 modec = 'g';
13734 else
13735#endif
13736 if (t_colors > 1)
13737 modec = 'c';
13738 else
13739 modec = 't';
13740 }
13741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013742 switch (TOLOWER_ASC(what[0]))
13743 {
13744 case 'b':
13745 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13746 p = highlight_color(id, what, modec);
13747 else /* bold */
13748 p = highlight_has_attr(id, HL_BOLD, modec);
13749 break;
13750
13751 case 'f': /* fg[#] or font */
13752 p = highlight_color(id, what, modec);
13753 break;
13754
13755 case 'i':
13756 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13757 p = highlight_has_attr(id, HL_INVERSE, modec);
13758 else /* italic */
13759 p = highlight_has_attr(id, HL_ITALIC, modec);
13760 break;
13761
13762 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013763 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013764 break;
13765
13766 case 'r': /* reverse */
13767 p = highlight_has_attr(id, HL_INVERSE, modec);
13768 break;
13769
13770 case 's':
13771 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13772 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013773 /* strikeout */
13774 else if (TOLOWER_ASC(what[1]) == 't' &&
13775 TOLOWER_ASC(what[2]) == 'r')
13776 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013777 else /* standout */
13778 p = highlight_has_attr(id, HL_STANDOUT, modec);
13779 break;
13780
13781 case 'u':
13782 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13783 /* underline */
13784 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13785 else
13786 /* undercurl */
13787 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13788 break;
13789 }
13790
13791 if (p != NULL)
13792 p = vim_strsave(p);
13793#endif
13794 rettv->v_type = VAR_STRING;
13795 rettv->vval.v_string = p;
13796}
13797
13798/*
13799 * "synIDtrans(id)" function
13800 */
13801 static void
13802f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13803{
13804 int id;
13805
13806#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013807 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013808
13809 if (id > 0)
13810 id = syn_get_final_id(id);
13811 else
13812#endif
13813 id = 0;
13814
13815 rettv->vval.v_number = id;
13816}
13817
13818/*
13819 * "synconcealed(lnum, col)" function
13820 */
13821 static void
13822f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13823{
13824#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13825 linenr_T lnum;
13826 colnr_T col;
13827 int syntax_flags = 0;
13828 int cchar;
13829 int matchid = 0;
13830 char_u str[NUMBUFLEN];
13831#endif
13832
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013833 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013834
13835#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013836 lnum = tv_get_lnum(argvars); /* -1 on type error */
13837 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013838
13839 vim_memset(str, NUL, sizeof(str));
13840
13841 if (rettv_list_alloc(rettv) != FAIL)
13842 {
13843 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13844 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13845 && curwin->w_p_cole > 0)
13846 {
13847 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13848 syntax_flags = get_syntax_info(&matchid);
13849
13850 /* get the conceal character */
13851 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13852 {
13853 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013854 if (cchar == NUL && curwin->w_p_cole == 1)
13855 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013856 if (cchar != NUL)
13857 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013858 if (has_mbyte)
13859 (*mb_char2bytes)(cchar, str);
13860 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013861 str[0] = cchar;
13862 }
13863 }
13864 }
13865
13866 list_append_number(rettv->vval.v_list,
13867 (syntax_flags & HL_CONCEAL) != 0);
13868 /* -1 to auto-determine strlen */
13869 list_append_string(rettv->vval.v_list, str, -1);
13870 list_append_number(rettv->vval.v_list, matchid);
13871 }
13872#endif
13873}
13874
13875/*
13876 * "synstack(lnum, col)" function
13877 */
13878 static void
13879f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13880{
13881#ifdef FEAT_SYN_HL
13882 linenr_T lnum;
13883 colnr_T col;
13884 int i;
13885 int id;
13886#endif
13887
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013888 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013889
13890#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013891 lnum = tv_get_lnum(argvars); /* -1 on type error */
13892 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013893
13894 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13895 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13896 && rettv_list_alloc(rettv) != FAIL)
13897 {
13898 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13899 for (i = 0; ; ++i)
13900 {
13901 id = syn_get_stack_item(i);
13902 if (id < 0)
13903 break;
13904 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13905 break;
13906 }
13907 }
13908#endif
13909}
13910
13911 static void
13912get_cmd_output_as_rettv(
13913 typval_T *argvars,
13914 typval_T *rettv,
13915 int retlist)
13916{
13917 char_u *res = NULL;
13918 char_u *p;
13919 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013920 int err = FALSE;
13921 FILE *fd;
13922 list_T *list = NULL;
13923 int flags = SHELL_SILENT;
13924
13925 rettv->v_type = VAR_STRING;
13926 rettv->vval.v_string = NULL;
13927 if (check_restricted() || check_secure())
13928 goto errret;
13929
13930 if (argvars[1].v_type != VAR_UNKNOWN)
13931 {
13932 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013933 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013934 * command.
13935 */
13936 if ((infile = vim_tempname('i', TRUE)) == NULL)
13937 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013938 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013939 goto errret;
13940 }
13941
13942 fd = mch_fopen((char *)infile, WRITEBIN);
13943 if (fd == NULL)
13944 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013945 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013946 goto errret;
13947 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013948 if (argvars[1].v_type == VAR_NUMBER)
13949 {
13950 linenr_T lnum;
13951 buf_T *buf;
13952
13953 buf = buflist_findnr(argvars[1].vval.v_number);
13954 if (buf == NULL)
13955 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013956 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013957 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013958 goto errret;
13959 }
13960
13961 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13962 {
13963 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13964 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13965 {
13966 err = TRUE;
13967 break;
13968 }
13969 if (putc(NL, fd) == EOF)
13970 {
13971 err = TRUE;
13972 break;
13973 }
13974 }
13975 }
13976 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013977 {
13978 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13979 err = TRUE;
13980 }
13981 else
13982 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013983 size_t len;
13984 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013985
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013986 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013987 if (p == NULL)
13988 {
13989 fclose(fd);
13990 goto errret; /* type error; errmsg already given */
13991 }
13992 len = STRLEN(p);
13993 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13994 err = TRUE;
13995 }
13996 if (fclose(fd) != 0)
13997 err = TRUE;
13998 if (err)
13999 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014000 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014001 goto errret;
14002 }
14003 }
14004
14005 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
14006 * echoes typeahead, that messes up the display. */
14007 if (!msg_silent)
14008 flags += SHELL_COOKED;
14009
14010 if (retlist)
14011 {
14012 int len;
14013 listitem_T *li;
14014 char_u *s = NULL;
14015 char_u *start;
14016 char_u *end;
14017 int i;
14018
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014019 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014020 if (res == NULL)
14021 goto errret;
14022
14023 list = list_alloc();
14024 if (list == NULL)
14025 goto errret;
14026
14027 for (i = 0; i < len; ++i)
14028 {
14029 start = res + i;
14030 while (i < len && res[i] != NL)
14031 ++i;
14032 end = res + i;
14033
14034 s = alloc((unsigned)(end - start + 1));
14035 if (s == NULL)
14036 goto errret;
14037
14038 for (p = s; start < end; ++p, ++start)
14039 *p = *start == NUL ? NL : *start;
14040 *p = NUL;
14041
14042 li = listitem_alloc();
14043 if (li == NULL)
14044 {
14045 vim_free(s);
14046 goto errret;
14047 }
14048 li->li_tv.v_type = VAR_STRING;
14049 li->li_tv.v_lock = 0;
14050 li->li_tv.vval.v_string = s;
14051 list_append(list, li);
14052 }
14053
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014054 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014055 list = NULL;
14056 }
14057 else
14058 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014059 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010014060#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014061 /* translate <CR><NL> into <NL> */
14062 if (res != NULL)
14063 {
14064 char_u *s, *d;
14065
14066 d = res;
14067 for (s = res; *s; ++s)
14068 {
14069 if (s[0] == CAR && s[1] == NL)
14070 ++s;
14071 *d++ = *s;
14072 }
14073 *d = NUL;
14074 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014075#endif
14076 rettv->vval.v_string = res;
14077 res = NULL;
14078 }
14079
14080errret:
14081 if (infile != NULL)
14082 {
14083 mch_remove(infile);
14084 vim_free(infile);
14085 }
14086 if (res != NULL)
14087 vim_free(res);
14088 if (list != NULL)
14089 list_free(list);
14090}
14091
14092/*
14093 * "system()" function
14094 */
14095 static void
14096f_system(typval_T *argvars, typval_T *rettv)
14097{
14098 get_cmd_output_as_rettv(argvars, rettv, FALSE);
14099}
14100
14101/*
14102 * "systemlist()" function
14103 */
14104 static void
14105f_systemlist(typval_T *argvars, typval_T *rettv)
14106{
14107 get_cmd_output_as_rettv(argvars, rettv, TRUE);
14108}
14109
14110/*
14111 * "tabpagebuflist()" function
14112 */
14113 static void
14114f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14115{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014116 tabpage_T *tp;
14117 win_T *wp = NULL;
14118
14119 if (argvars[0].v_type == VAR_UNKNOWN)
14120 wp = firstwin;
14121 else
14122 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014123 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014124 if (tp != NULL)
14125 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
14126 }
14127 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
14128 {
14129 for (; wp != NULL; wp = wp->w_next)
14130 if (list_append_number(rettv->vval.v_list,
14131 wp->w_buffer->b_fnum) == FAIL)
14132 break;
14133 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014134}
14135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014136/*
14137 * "tabpagenr()" function
14138 */
14139 static void
14140f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
14141{
14142 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014143 char_u *arg;
14144
14145 if (argvars[0].v_type != VAR_UNKNOWN)
14146 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014147 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014148 nr = 0;
14149 if (arg != NULL)
14150 {
14151 if (STRCMP(arg, "$") == 0)
14152 nr = tabpage_index(NULL) - 1;
14153 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014154 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014155 }
14156 }
14157 else
14158 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014159 rettv->vval.v_number = nr;
14160}
14161
14162
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014163/*
14164 * Common code for tabpagewinnr() and winnr().
14165 */
14166 static int
14167get_winnr(tabpage_T *tp, typval_T *argvar)
14168{
14169 win_T *twin;
14170 int nr = 1;
14171 win_T *wp;
14172 char_u *arg;
14173
14174 twin = (tp == curtab) ? curwin : tp->tp_curwin;
14175 if (argvar->v_type != VAR_UNKNOWN)
14176 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020014177 int invalid_arg = FALSE;
14178
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014179 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014180 if (arg == NULL)
14181 nr = 0; /* type error; errmsg already given */
14182 else if (STRCMP(arg, "$") == 0)
14183 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
14184 else if (STRCMP(arg, "#") == 0)
14185 {
14186 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
14187 if (twin == NULL)
14188 nr = 0;
14189 }
14190 else
14191 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020014192 long count;
14193 char_u *endp;
14194
14195 // Extract the window count (if specified). e.g. winnr('3j')
14196 count = strtol((char *)arg, (char **)&endp, 10);
14197 if (count <= 0)
14198 count = 1; // if count is not specified, default to 1
14199 if (endp != NULL && *endp != '\0')
14200 {
14201 if (STRCMP(endp, "j") == 0)
14202 twin = win_vert_neighbor(tp, twin, FALSE, count);
14203 else if (STRCMP(endp, "k") == 0)
14204 twin = win_vert_neighbor(tp, twin, TRUE, count);
14205 else if (STRCMP(endp, "h") == 0)
14206 twin = win_horz_neighbor(tp, twin, TRUE, count);
14207 else if (STRCMP(endp, "l") == 0)
14208 twin = win_horz_neighbor(tp, twin, FALSE, count);
14209 else
14210 invalid_arg = TRUE;
14211 }
14212 else
14213 invalid_arg = TRUE;
14214 }
14215
14216 if (invalid_arg)
14217 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014218 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014219 nr = 0;
14220 }
14221 }
14222
14223 if (nr > 0)
14224 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
14225 wp != twin; wp = wp->w_next)
14226 {
14227 if (wp == NULL)
14228 {
14229 /* didn't find it in this tabpage */
14230 nr = 0;
14231 break;
14232 }
14233 ++nr;
14234 }
14235 return nr;
14236}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014237
14238/*
14239 * "tabpagewinnr()" function
14240 */
14241 static void
14242f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
14243{
14244 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014245 tabpage_T *tp;
14246
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014247 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014248 if (tp == NULL)
14249 nr = 0;
14250 else
14251 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014252 rettv->vval.v_number = nr;
14253}
14254
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014255/*
14256 * "tagfiles()" function
14257 */
14258 static void
14259f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
14260{
14261 char_u *fname;
14262 tagname_T tn;
14263 int first;
14264
14265 if (rettv_list_alloc(rettv) == FAIL)
14266 return;
14267 fname = alloc(MAXPATHL);
14268 if (fname == NULL)
14269 return;
14270
14271 for (first = TRUE; ; first = FALSE)
14272 if (get_tagfname(&tn, first, fname) == FAIL
14273 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
14274 break;
14275 tagname_free(&tn);
14276 vim_free(fname);
14277}
14278
14279/*
14280 * "taglist()" function
14281 */
14282 static void
14283f_taglist(typval_T *argvars, typval_T *rettv)
14284{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010014285 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014286 char_u *tag_pattern;
14287
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014288 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014289
14290 rettv->vval.v_number = FALSE;
14291 if (*tag_pattern == NUL)
14292 return;
14293
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010014294 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014295 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014296 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010014297 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014298}
14299
14300/*
14301 * "tempname()" function
14302 */
14303 static void
14304f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
14305{
14306 static int x = 'A';
14307
14308 rettv->v_type = VAR_STRING;
14309 rettv->vval.v_string = vim_tempname(x, FALSE);
14310
14311 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
14312 * names. Skip 'I' and 'O', they are used for shell redirection. */
14313 do
14314 {
14315 if (x == 'Z')
14316 x = '0';
14317 else if (x == '9')
14318 x = 'A';
14319 else
14320 {
14321#ifdef EBCDIC
14322 if (x == 'I')
14323 x = 'J';
14324 else if (x == 'R')
14325 x = 'S';
14326 else
14327#endif
14328 ++x;
14329 }
14330 } while (x == 'I' || x == 'O');
14331}
14332
14333#ifdef FEAT_FLOAT
14334/*
14335 * "tan()" function
14336 */
14337 static void
14338f_tan(typval_T *argvars, typval_T *rettv)
14339{
14340 float_T f = 0.0;
14341
14342 rettv->v_type = VAR_FLOAT;
14343 if (get_float_arg(argvars, &f) == OK)
14344 rettv->vval.v_float = tan(f);
14345 else
14346 rettv->vval.v_float = 0.0;
14347}
14348
14349/*
14350 * "tanh()" function
14351 */
14352 static void
14353f_tanh(typval_T *argvars, typval_T *rettv)
14354{
14355 float_T f = 0.0;
14356
14357 rettv->v_type = VAR_FLOAT;
14358 if (get_float_arg(argvars, &f) == OK)
14359 rettv->vval.v_float = tanh(f);
14360 else
14361 rettv->vval.v_float = 0.0;
14362}
14363#endif
14364
14365/*
14366 * "test_alloc_fail(id, countdown, repeat)" function
14367 */
14368 static void
14369f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
14370{
14371 if (argvars[0].v_type != VAR_NUMBER
14372 || argvars[0].vval.v_number <= 0
14373 || argvars[1].v_type != VAR_NUMBER
14374 || argvars[1].vval.v_number < 0
14375 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014376 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014377 else
14378 {
14379 alloc_fail_id = argvars[0].vval.v_number;
14380 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014381 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014382 alloc_fail_countdown = argvars[1].vval.v_number;
14383 alloc_fail_repeat = argvars[2].vval.v_number;
14384 did_outofmem_msg = FALSE;
14385 }
14386}
14387
14388/*
14389 * "test_autochdir()"
14390 */
14391 static void
14392f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14393{
14394#if defined(FEAT_AUTOCHDIR)
14395 test_autochdir = TRUE;
14396#endif
14397}
14398
14399/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020014400 * "test_feedinput()"
14401 */
14402 static void
14403f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
14404{
14405#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014406 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020014407
14408 if (val != NULL)
14409 {
14410 trash_input_buf();
14411 add_to_input_buf_csi(val, (int)STRLEN(val));
14412 }
14413#endif
14414}
14415
14416/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014417 * "test_option_not_set({name})" function
14418 */
14419 static void
14420f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
14421{
14422 char_u *name = (char_u *)"";
14423
14424 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014425 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014426 else
14427 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014428 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014429 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014430 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014431 }
14432}
14433
14434/*
14435 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014436 */
14437 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014438f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014439{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014440 char_u *name = (char_u *)"";
14441 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020014442 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014443
14444 if (argvars[0].v_type != VAR_STRING
14445 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014446 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014447 else
14448 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010014449 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014450 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014451
14452 if (STRCMP(name, (char_u *)"redraw") == 0)
14453 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020014454 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
14455 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014456 else if (STRCMP(name, (char_u *)"char_avail") == 0)
14457 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020014458 else if (STRCMP(name, (char_u *)"starting") == 0)
14459 {
14460 if (val)
14461 {
14462 if (save_starting < 0)
14463 save_starting = starting;
14464 starting = 0;
14465 }
14466 else
14467 {
14468 starting = save_starting;
14469 save_starting = -1;
14470 }
14471 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020014472 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
14473 nfa_fail_for_testing = val;
Bram Moolenaar92fd5992019-05-02 23:00:22 +020014474 else if (STRCMP(name, (char_u *)"no_query_mouse") == 0)
14475 no_query_mouse_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014476 else if (STRCMP(name, (char_u *)"ALL") == 0)
14477 {
14478 disable_char_avail_for_testing = FALSE;
14479 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020014480 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020014481 nfa_fail_for_testing = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +020014482 no_query_mouse_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020014483 if (save_starting >= 0)
14484 {
14485 starting = save_starting;
14486 save_starting = -1;
14487 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014488 }
14489 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014490 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014491 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014492}
14493
14494/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010014495 * "test_refcount({expr})" function
14496 */
14497 static void
14498f_test_refcount(typval_T *argvars, typval_T *rettv)
14499{
14500 int retval = -1;
14501
14502 switch (argvars[0].v_type)
14503 {
14504 case VAR_UNKNOWN:
14505 case VAR_NUMBER:
14506 case VAR_FLOAT:
14507 case VAR_SPECIAL:
14508 case VAR_STRING:
14509 break;
14510 case VAR_JOB:
14511#ifdef FEAT_JOB_CHANNEL
14512 if (argvars[0].vval.v_job != NULL)
14513 retval = argvars[0].vval.v_job->jv_refcount - 1;
14514#endif
14515 break;
14516 case VAR_CHANNEL:
14517#ifdef FEAT_JOB_CHANNEL
14518 if (argvars[0].vval.v_channel != NULL)
14519 retval = argvars[0].vval.v_channel->ch_refcount - 1;
14520#endif
14521 break;
14522 case VAR_FUNC:
14523 if (argvars[0].vval.v_string != NULL)
14524 {
14525 ufunc_T *fp;
14526
14527 fp = find_func(argvars[0].vval.v_string);
14528 if (fp != NULL)
14529 retval = fp->uf_refcount;
14530 }
14531 break;
14532 case VAR_PARTIAL:
14533 if (argvars[0].vval.v_partial != NULL)
14534 retval = argvars[0].vval.v_partial->pt_refcount - 1;
14535 break;
14536 case VAR_BLOB:
14537 if (argvars[0].vval.v_blob != NULL)
14538 retval = argvars[0].vval.v_blob->bv_refcount - 1;
14539 break;
14540 case VAR_LIST:
14541 if (argvars[0].vval.v_list != NULL)
14542 retval = argvars[0].vval.v_list->lv_refcount - 1;
14543 break;
14544 case VAR_DICT:
14545 if (argvars[0].vval.v_dict != NULL)
14546 retval = argvars[0].vval.v_dict->dv_refcount - 1;
14547 break;
14548 }
14549
14550 rettv->v_type = VAR_NUMBER;
14551 rettv->vval.v_number = retval;
14552
14553}
14554
14555/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014556 * "test_garbagecollect_now()" function
14557 */
14558 static void
14559f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14560{
14561 /* This is dangerous, any Lists and Dicts used internally may be freed
14562 * while still in use. */
14563 garbage_collect(TRUE);
14564}
14565
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014566/*
14567 * "test_ignore_error()" function
14568 */
14569 static void
14570f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
14571{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014572 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014573}
14574
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010014575 static void
14576f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
14577{
14578 rettv->v_type = VAR_BLOB;
14579 rettv->vval.v_blob = NULL;
14580}
14581
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014582#ifdef FEAT_JOB_CHANNEL
14583 static void
14584f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
14585{
14586 rettv->v_type = VAR_CHANNEL;
14587 rettv->vval.v_channel = NULL;
14588}
14589#endif
14590
14591 static void
14592f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
14593{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014594 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014595}
14596
14597#ifdef FEAT_JOB_CHANNEL
14598 static void
14599f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14600{
14601 rettv->v_type = VAR_JOB;
14602 rettv->vval.v_job = NULL;
14603}
14604#endif
14605
14606 static void
14607f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14608{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014609 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014610}
14611
14612 static void
14613f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14614{
14615 rettv->v_type = VAR_PARTIAL;
14616 rettv->vval.v_partial = NULL;
14617}
14618
14619 static void
14620f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14621{
14622 rettv->v_type = VAR_STRING;
14623 rettv->vval.v_string = NULL;
14624}
14625
Bram Moolenaarab186732018-09-14 21:27:06 +020014626#ifdef FEAT_GUI
14627 static void
14628f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14629{
14630 char_u *which;
14631 long value;
14632 int dragging;
14633 scrollbar_T *sb = NULL;
14634
14635 if (argvars[0].v_type != VAR_STRING
14636 || (argvars[1].v_type) != VAR_NUMBER
14637 || (argvars[2].v_type) != VAR_NUMBER)
14638 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014639 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014640 return;
14641 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014642 which = tv_get_string(&argvars[0]);
14643 value = tv_get_number(&argvars[1]);
14644 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014645
14646 if (STRCMP(which, "left") == 0)
14647 sb = &curwin->w_scrollbars[SBAR_LEFT];
14648 else if (STRCMP(which, "right") == 0)
14649 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14650 else if (STRCMP(which, "hor") == 0)
14651 sb = &gui.bottom_sbar;
14652 if (sb == NULL)
14653 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014654 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014655 return;
14656 }
14657 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014658# ifndef USE_ON_FLY_SCROLL
14659 // need to loop through normal_cmd() to handle the scroll events
14660 exec_normal(FALSE, TRUE, FALSE);
14661# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014662}
14663#endif
14664
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +020014665#ifdef FEAT_MOUSE
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014666 static void
Bram Moolenaarbb8476b2019-05-04 15:47:48 +020014667f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
14668{
14669 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
14670 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
14671}
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +020014672#endif
Bram Moolenaarbb8476b2019-05-04 15:47:48 +020014673
14674 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014675f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14676{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014677 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014678}
14679
14680#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14681/*
14682 * Get a callback from "arg". It can be a Funcref or a function name.
14683 * When "arg" is zero return an empty string.
14684 * Return NULL for an invalid argument.
14685 */
14686 char_u *
14687get_callback(typval_T *arg, partial_T **pp)
14688{
14689 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14690 {
14691 *pp = arg->vval.v_partial;
14692 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014693 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014694 }
14695 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014696 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014697 {
14698 func_ref(arg->vval.v_string);
14699 return arg->vval.v_string;
14700 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014701 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14702 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014703 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014704 return NULL;
14705}
14706
14707/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014708 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014709 */
14710 void
14711free_callback(char_u *callback, partial_T *partial)
14712{
14713 if (partial != NULL)
14714 partial_unref(partial);
14715 else if (callback != NULL)
14716 {
14717 func_unref(callback);
14718 vim_free(callback);
14719 }
14720}
14721#endif
14722
14723#ifdef FEAT_TIMERS
14724/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014725 * "timer_info([timer])" function
14726 */
14727 static void
14728f_timer_info(typval_T *argvars, typval_T *rettv)
14729{
14730 timer_T *timer = NULL;
14731
14732 if (rettv_list_alloc(rettv) != OK)
14733 return;
14734 if (argvars[0].v_type != VAR_UNKNOWN)
14735 {
14736 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014737 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014738 else
14739 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014740 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014741 if (timer != NULL)
14742 add_timer_info(rettv, timer);
14743 }
14744 }
14745 else
14746 add_timer_info_all(rettv);
14747}
14748
14749/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014750 * "timer_pause(timer, paused)" function
14751 */
14752 static void
14753f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14754{
14755 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014756 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014757
14758 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014759 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014760 else
14761 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014762 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014763 if (timer != NULL)
14764 timer->tr_paused = paused;
14765 }
14766}
14767
14768/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014769 * "timer_start(time, callback [, options])" function
14770 */
14771 static void
14772f_timer_start(typval_T *argvars, typval_T *rettv)
14773{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014774 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014775 timer_T *timer;
14776 int repeat = 0;
14777 char_u *callback;
14778 dict_T *dict;
14779 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014780
Bram Moolenaar75537a92016-09-05 22:45:28 +020014781 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014782 if (check_secure())
14783 return;
14784 if (argvars[2].v_type != VAR_UNKNOWN)
14785 {
14786 if (argvars[2].v_type != VAR_DICT
14787 || (dict = argvars[2].vval.v_dict) == NULL)
14788 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014789 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014790 return;
14791 }
14792 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014793 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014794 }
14795
Bram Moolenaar75537a92016-09-05 22:45:28 +020014796 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014797 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014798 return;
14799
14800 timer = create_timer(msec, repeat);
14801 if (timer == NULL)
14802 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014803 else
14804 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014805 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014806 timer->tr_callback = vim_strsave(callback);
14807 else
14808 /* pointer into the partial */
14809 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014810 timer->tr_partial = partial;
14811 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014812 }
14813}
14814
14815/*
14816 * "timer_stop(timer)" function
14817 */
14818 static void
14819f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14820{
14821 timer_T *timer;
14822
14823 if (argvars[0].v_type != VAR_NUMBER)
14824 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014825 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014826 return;
14827 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014828 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014829 if (timer != NULL)
14830 stop_timer(timer);
14831}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014832
14833/*
14834 * "timer_stopall()" function
14835 */
14836 static void
14837f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14838{
14839 stop_all_timers();
14840}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014841#endif
14842
14843/*
14844 * "tolower(string)" function
14845 */
14846 static void
14847f_tolower(typval_T *argvars, typval_T *rettv)
14848{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014849 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014850 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014851}
14852
14853/*
14854 * "toupper(string)" function
14855 */
14856 static void
14857f_toupper(typval_T *argvars, typval_T *rettv)
14858{
14859 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014860 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014861}
14862
14863/*
14864 * "tr(string, fromstr, tostr)" function
14865 */
14866 static void
14867f_tr(typval_T *argvars, typval_T *rettv)
14868{
14869 char_u *in_str;
14870 char_u *fromstr;
14871 char_u *tostr;
14872 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014873 int inlen;
14874 int fromlen;
14875 int tolen;
14876 int idx;
14877 char_u *cpstr;
14878 int cplen;
14879 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014880 char_u buf[NUMBUFLEN];
14881 char_u buf2[NUMBUFLEN];
14882 garray_T ga;
14883
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014884 in_str = tv_get_string(&argvars[0]);
14885 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14886 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014887
14888 /* Default return value: empty string. */
14889 rettv->v_type = VAR_STRING;
14890 rettv->vval.v_string = NULL;
14891 if (fromstr == NULL || tostr == NULL)
14892 return; /* type error; errmsg already given */
14893 ga_init2(&ga, (int)sizeof(char), 80);
14894
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014895 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014896 /* not multi-byte: fromstr and tostr must be the same length */
14897 if (STRLEN(fromstr) != STRLEN(tostr))
14898 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014899error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014900 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014901 ga_clear(&ga);
14902 return;
14903 }
14904
14905 /* fromstr and tostr have to contain the same number of chars */
14906 while (*in_str != NUL)
14907 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014908 if (has_mbyte)
14909 {
14910 inlen = (*mb_ptr2len)(in_str);
14911 cpstr = in_str;
14912 cplen = inlen;
14913 idx = 0;
14914 for (p = fromstr; *p != NUL; p += fromlen)
14915 {
14916 fromlen = (*mb_ptr2len)(p);
14917 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14918 {
14919 for (p = tostr; *p != NUL; p += tolen)
14920 {
14921 tolen = (*mb_ptr2len)(p);
14922 if (idx-- == 0)
14923 {
14924 cplen = tolen;
14925 cpstr = p;
14926 break;
14927 }
14928 }
14929 if (*p == NUL) /* tostr is shorter than fromstr */
14930 goto error;
14931 break;
14932 }
14933 ++idx;
14934 }
14935
14936 if (first && cpstr == in_str)
14937 {
14938 /* Check that fromstr and tostr have the same number of
14939 * (multi-byte) characters. Done only once when a character
14940 * of in_str doesn't appear in fromstr. */
14941 first = FALSE;
14942 for (p = tostr; *p != NUL; p += tolen)
14943 {
14944 tolen = (*mb_ptr2len)(p);
14945 --idx;
14946 }
14947 if (idx != 0)
14948 goto error;
14949 }
14950
14951 (void)ga_grow(&ga, cplen);
14952 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14953 ga.ga_len += cplen;
14954
14955 in_str += inlen;
14956 }
14957 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014958 {
14959 /* When not using multi-byte chars we can do it faster. */
14960 p = vim_strchr(fromstr, *in_str);
14961 if (p != NULL)
14962 ga_append(&ga, tostr[p - fromstr]);
14963 else
14964 ga_append(&ga, *in_str);
14965 ++in_str;
14966 }
14967 }
14968
14969 /* add a terminating NUL */
14970 (void)ga_grow(&ga, 1);
14971 ga_append(&ga, NUL);
14972
14973 rettv->vval.v_string = ga.ga_data;
14974}
14975
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014976/*
14977 * "trim({expr})" function
14978 */
14979 static void
14980f_trim(typval_T *argvars, typval_T *rettv)
14981{
14982 char_u buf1[NUMBUFLEN];
14983 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014984 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014985 char_u *mask = NULL;
14986 char_u *tail;
14987 char_u *prev;
14988 char_u *p;
14989 int c1;
14990
14991 rettv->v_type = VAR_STRING;
14992 if (head == NULL)
14993 {
14994 rettv->vval.v_string = NULL;
14995 return;
14996 }
14997
14998 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014999 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010015000
15001 while (*head != NUL)
15002 {
15003 c1 = PTR2CHAR(head);
15004 if (mask == NULL)
15005 {
15006 if (c1 > ' ' && c1 != 0xa0)
15007 break;
15008 }
15009 else
15010 {
15011 for (p = mask; *p != NUL; MB_PTR_ADV(p))
15012 if (c1 == PTR2CHAR(p))
15013 break;
15014 if (*p == NUL)
15015 break;
15016 }
15017 MB_PTR_ADV(head);
15018 }
15019
15020 for (tail = head + STRLEN(head); tail > head; tail = prev)
15021 {
15022 prev = tail;
15023 MB_PTR_BACK(head, prev);
15024 c1 = PTR2CHAR(prev);
15025 if (mask == NULL)
15026 {
15027 if (c1 > ' ' && c1 != 0xa0)
15028 break;
15029 }
15030 else
15031 {
15032 for (p = mask; *p != NUL; MB_PTR_ADV(p))
15033 if (c1 == PTR2CHAR(p))
15034 break;
15035 if (*p == NUL)
15036 break;
15037 }
15038 }
15039 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
15040}
15041
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015042#ifdef FEAT_FLOAT
15043/*
15044 * "trunc({float})" function
15045 */
15046 static void
15047f_trunc(typval_T *argvars, typval_T *rettv)
15048{
15049 float_T f = 0.0;
15050
15051 rettv->v_type = VAR_FLOAT;
15052 if (get_float_arg(argvars, &f) == OK)
15053 /* trunc() is not in C90, use floor() or ceil() instead. */
15054 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
15055 else
15056 rettv->vval.v_float = 0.0;
15057}
15058#endif
15059
15060/*
15061 * "type(expr)" function
15062 */
15063 static void
15064f_type(typval_T *argvars, typval_T *rettv)
15065{
15066 int n = -1;
15067
15068 switch (argvars[0].v_type)
15069 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020015070 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
15071 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015072 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020015073 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
15074 case VAR_LIST: n = VAR_TYPE_LIST; break;
15075 case VAR_DICT: n = VAR_TYPE_DICT; break;
15076 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015077 case VAR_SPECIAL:
15078 if (argvars[0].vval.v_number == VVAL_FALSE
15079 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020015080 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015081 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020015082 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015083 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020015084 case VAR_JOB: n = VAR_TYPE_JOB; break;
15085 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015086 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015087 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010015088 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015089 n = -1;
15090 break;
15091 }
15092 rettv->vval.v_number = n;
15093}
15094
15095/*
15096 * "undofile(name)" function
15097 */
15098 static void
15099f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
15100{
15101 rettv->v_type = VAR_STRING;
15102#ifdef FEAT_PERSISTENT_UNDO
15103 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015104 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015105
15106 if (*fname == NUL)
15107 {
15108 /* If there is no file name there will be no undo file. */
15109 rettv->vval.v_string = NULL;
15110 }
15111 else
15112 {
15113 char_u *ffname = FullName_save(fname, FALSE);
15114
15115 if (ffname != NULL)
15116 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
15117 vim_free(ffname);
15118 }
15119 }
15120#else
15121 rettv->vval.v_string = NULL;
15122#endif
15123}
15124
15125/*
15126 * "undotree()" function
15127 */
15128 static void
15129f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
15130{
15131 if (rettv_dict_alloc(rettv) == OK)
15132 {
15133 dict_T *dict = rettv->vval.v_dict;
15134 list_T *list;
15135
Bram Moolenaare0be1672018-07-08 16:50:37 +020015136 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
15137 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
15138 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
15139 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
15140 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
15141 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015142
15143 list = list_alloc();
15144 if (list != NULL)
15145 {
15146 u_eval_tree(curbuf->b_u_oldhead, list);
15147 dict_add_list(dict, "entries", list);
15148 }
15149 }
15150}
15151
15152/*
15153 * "values(dict)" function
15154 */
15155 static void
15156f_values(typval_T *argvars, typval_T *rettv)
15157{
15158 dict_list(argvars, rettv, 1);
15159}
15160
15161/*
15162 * "virtcol(string)" function
15163 */
15164 static void
15165f_virtcol(typval_T *argvars, typval_T *rettv)
15166{
15167 colnr_T vcol = 0;
15168 pos_T *fp;
15169 int fnum = curbuf->b_fnum;
15170
15171 fp = var2fpos(&argvars[0], FALSE, &fnum);
15172 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
15173 && fnum == curbuf->b_fnum)
15174 {
15175 getvvcol(curwin, fp, NULL, NULL, &vcol);
15176 ++vcol;
15177 }
15178
15179 rettv->vval.v_number = vcol;
15180}
15181
15182/*
15183 * "visualmode()" function
15184 */
15185 static void
15186f_visualmode(typval_T *argvars, typval_T *rettv)
15187{
15188 char_u str[2];
15189
15190 rettv->v_type = VAR_STRING;
15191 str[0] = curbuf->b_visual_mode_eval;
15192 str[1] = NUL;
15193 rettv->vval.v_string = vim_strsave(str);
15194
15195 /* A non-zero number or non-empty string argument: reset mode. */
15196 if (non_zero_arg(&argvars[0]))
15197 curbuf->b_visual_mode_eval = NUL;
15198}
15199
15200/*
15201 * "wildmenumode()" function
15202 */
15203 static void
15204f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
15205{
15206#ifdef FEAT_WILDMENU
15207 if (wild_menu_showing)
15208 rettv->vval.v_number = 1;
15209#endif
15210}
15211
15212/*
15213 * "winbufnr(nr)" function
15214 */
15215 static void
15216f_winbufnr(typval_T *argvars, typval_T *rettv)
15217{
15218 win_T *wp;
15219
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020015220 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015221 if (wp == NULL)
15222 rettv->vval.v_number = -1;
15223 else
15224 rettv->vval.v_number = wp->w_buffer->b_fnum;
15225}
15226
15227/*
15228 * "wincol()" function
15229 */
15230 static void
15231f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
15232{
15233 validate_cursor();
15234 rettv->vval.v_number = curwin->w_wcol + 1;
15235}
15236
15237/*
15238 * "winheight(nr)" function
15239 */
15240 static void
15241f_winheight(typval_T *argvars, typval_T *rettv)
15242{
15243 win_T *wp;
15244
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020015245 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015246 if (wp == NULL)
15247 rettv->vval.v_number = -1;
15248 else
15249 rettv->vval.v_number = wp->w_height;
15250}
15251
15252/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020015253 * "winlayout()" function
15254 */
15255 static void
15256f_winlayout(typval_T *argvars, typval_T *rettv)
15257{
15258 tabpage_T *tp;
15259
15260 if (rettv_list_alloc(rettv) != OK)
15261 return;
15262
15263 if (argvars[0].v_type == VAR_UNKNOWN)
15264 tp = curtab;
15265 else
15266 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015267 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020015268 if (tp == NULL)
15269 return;
15270 }
15271
15272 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
15273}
15274
15275/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015276 * "winline()" function
15277 */
15278 static void
15279f_winline(typval_T *argvars UNUSED, typval_T *rettv)
15280{
15281 validate_cursor();
15282 rettv->vval.v_number = curwin->w_wrow + 1;
15283}
15284
15285/*
15286 * "winnr()" function
15287 */
15288 static void
15289f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
15290{
15291 int nr = 1;
15292
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015293 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015294 rettv->vval.v_number = nr;
15295}
15296
15297/*
15298 * "winrestcmd()" function
15299 */
15300 static void
15301f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
15302{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015303 win_T *wp;
15304 int winnr = 1;
15305 garray_T ga;
15306 char_u buf[50];
15307
15308 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020015309 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015310 {
15311 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
15312 ga_concat(&ga, buf);
15313 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
15314 ga_concat(&ga, buf);
15315 ++winnr;
15316 }
15317 ga_append(&ga, NUL);
15318
15319 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015320 rettv->v_type = VAR_STRING;
15321}
15322
15323/*
15324 * "winrestview()" function
15325 */
15326 static void
15327f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
15328{
15329 dict_T *dict;
15330
15331 if (argvars[0].v_type != VAR_DICT
15332 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010015333 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015334 else
15335 {
15336 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015337 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015338 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015339 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015340 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015341 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015342 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
15343 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010015344 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015345 curwin->w_set_curswant = FALSE;
15346 }
15347
15348 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015349 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015350#ifdef FEAT_DIFF
15351 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015352 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015353#endif
15354 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015355 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015356 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015357 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015358
15359 check_cursor();
15360 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020015361 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015362 changed_window_setting();
15363
15364 if (curwin->w_topline <= 0)
15365 curwin->w_topline = 1;
15366 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
15367 curwin->w_topline = curbuf->b_ml.ml_line_count;
15368#ifdef FEAT_DIFF
15369 check_topfill(curwin, TRUE);
15370#endif
15371 }
15372}
15373
15374/*
15375 * "winsaveview()" function
15376 */
15377 static void
15378f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
15379{
15380 dict_T *dict;
15381
15382 if (rettv_dict_alloc(rettv) == FAIL)
15383 return;
15384 dict = rettv->vval.v_dict;
15385
Bram Moolenaare0be1672018-07-08 16:50:37 +020015386 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
15387 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020015388 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015389 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020015390 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015391
Bram Moolenaare0be1672018-07-08 16:50:37 +020015392 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015393#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020015394 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015395#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020015396 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
15397 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015398}
15399
15400/*
15401 * "winwidth(nr)" function
15402 */
15403 static void
15404f_winwidth(typval_T *argvars, typval_T *rettv)
15405{
15406 win_T *wp;
15407
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020015408 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015409 if (wp == NULL)
15410 rettv->vval.v_number = -1;
15411 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015412 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015413}
15414
15415/*
15416 * "wordcount()" function
15417 */
15418 static void
15419f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
15420{
15421 if (rettv_dict_alloc(rettv) == FAIL)
15422 return;
15423 cursor_pos_info(rettv->vval.v_dict);
15424}
15425
15426/*
15427 * "writefile()" function
15428 */
15429 static void
15430f_writefile(typval_T *argvars, typval_T *rettv)
15431{
15432 int binary = FALSE;
15433 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015434#ifdef HAVE_FSYNC
15435 int do_fsync = p_fs;
15436#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015437 char_u *fname;
15438 FILE *fd;
15439 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015440 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015441 list_T *list = NULL;
15442 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015443
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015444 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010015445 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015446 return;
15447
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015448 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015449 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015450 list = argvars[0].vval.v_list;
15451 if (list == NULL)
15452 return;
15453 for (li = list->lv_first; li != NULL; li = li->li_next)
15454 if (tv_get_string_chk(&li->li_tv) == NULL)
15455 return;
15456 }
15457 else if (argvars[0].v_type == VAR_BLOB)
15458 {
15459 blob = argvars[0].vval.v_blob;
15460 if (blob == NULL)
15461 return;
15462 }
15463 else
15464 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010015465 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015466 return;
15467 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015468
15469 if (argvars[2].v_type != VAR_UNKNOWN)
15470 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015471 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015472
15473 if (arg2 == NULL)
15474 return;
15475 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015476 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015477 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015478 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015479#ifdef HAVE_FSYNC
15480 if (vim_strchr(arg2, 's') != NULL)
15481 do_fsync = TRUE;
15482 else if (vim_strchr(arg2, 'S') != NULL)
15483 do_fsync = FALSE;
15484#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015485 }
15486
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015487 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015488 if (fname == NULL)
15489 return;
15490
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015491 /* Always open the file in binary mode, library functions have a mind of
15492 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015493 if (*fname == NUL || (fd = mch_fopen((char *)fname,
15494 append ? APPENDBIN : WRITEBIN)) == NULL)
15495 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010015496 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015497 ret = -1;
15498 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015499 else if (blob)
15500 {
15501 if (write_blob(fd, blob) == FAIL)
15502 ret = -1;
15503#ifdef HAVE_FSYNC
15504 else if (do_fsync)
15505 // Ignore the error, the user wouldn't know what to do about it.
15506 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010015507 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015508#endif
15509 fclose(fd);
15510 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015511 else
15512 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015513 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015514 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015515#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010015516 else if (do_fsync)
15517 /* Ignore the error, the user wouldn't know what to do about it.
15518 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010015519 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015520#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015521 fclose(fd);
15522 }
15523
15524 rettv->vval.v_number = ret;
15525}
15526
15527/*
15528 * "xor(expr, expr)" function
15529 */
15530 static void
15531f_xor(typval_T *argvars, typval_T *rettv)
15532{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015533 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
15534 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015535}
15536
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015537#endif /* FEAT_EVAL */