blob: 267683268f3697dc8ed5bab7b5ac75b364d728bc [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 Moolenaar73dad1e2016-07-17 22:13:49 +0200770 {"localtime", 0, 0, f_localtime},
771#ifdef FEAT_FLOAT
772 {"log", 1, 1, f_log},
773 {"log10", 1, 1, f_log10},
774#endif
775#ifdef FEAT_LUA
776 {"luaeval", 1, 2, f_luaeval},
777#endif
778 {"map", 2, 2, f_map},
779 {"maparg", 1, 4, f_maparg},
780 {"mapcheck", 1, 3, f_mapcheck},
781 {"match", 2, 4, f_match},
782 {"matchadd", 2, 5, f_matchadd},
783 {"matchaddpos", 2, 5, f_matchaddpos},
784 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100785 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200786 {"matchend", 2, 4, f_matchend},
787 {"matchlist", 2, 4, f_matchlist},
788 {"matchstr", 2, 4, f_matchstr},
789 {"matchstrpos", 2, 4, f_matchstrpos},
790 {"max", 1, 1, f_max},
791 {"min", 1, 1, f_min},
792#ifdef vim_mkdir
793 {"mkdir", 1, 3, f_mkdir},
794#endif
795 {"mode", 0, 1, f_mode},
796#ifdef FEAT_MZSCHEME
797 {"mzeval", 1, 1, f_mzeval},
798#endif
799 {"nextnonblank", 1, 1, f_nextnonblank},
800 {"nr2char", 1, 2, f_nr2char},
801 {"or", 2, 2, f_or},
802 {"pathshorten", 1, 1, f_pathshorten},
803#ifdef FEAT_PERL
804 {"perleval", 1, 1, f_perleval},
805#endif
806#ifdef FEAT_FLOAT
807 {"pow", 2, 2, f_pow},
808#endif
809 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100810 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200811#ifdef FEAT_JOB_CHANNEL
812 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200813 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200814 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
815#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100816#ifdef FEAT_TEXT_PROP
817 {"prop_add", 3, 3, f_prop_add},
818 {"prop_clear", 1, 3, f_prop_clear},
819 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100820 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100821 {"prop_type_add", 2, 2, f_prop_type_add},
822 {"prop_type_change", 2, 2, f_prop_type_change},
823 {"prop_type_delete", 1, 2, f_prop_type_delete},
824 {"prop_type_get", 1, 2, f_prop_type_get},
825 {"prop_type_list", 0, 1, f_prop_type_list},
826#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827 {"pumvisible", 0, 0, f_pumvisible},
828#ifdef FEAT_PYTHON3
829 {"py3eval", 1, 1, f_py3eval},
830#endif
831#ifdef FEAT_PYTHON
832 {"pyeval", 1, 1, f_pyeval},
833#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100834#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
835 {"pyxeval", 1, 1, f_pyxeval},
836#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200837 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200838 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200840 {"reg_executing", 0, 0, f_reg_executing},
841 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842 {"reltime", 0, 2, f_reltime},
843#ifdef FEAT_FLOAT
844 {"reltimefloat", 1, 1, f_reltimefloat},
845#endif
846 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100847 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848 {"remote_foreground", 1, 1, f_remote_foreground},
849 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100850 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100852 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853 {"remove", 2, 3, f_remove},
854 {"rename", 2, 2, f_rename},
855 {"repeat", 2, 2, f_repeat},
856 {"resolve", 1, 1, f_resolve},
857 {"reverse", 1, 1, f_reverse},
858#ifdef FEAT_FLOAT
859 {"round", 1, 1, f_round},
860#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100861#ifdef FEAT_RUBY
862 {"rubyeval", 1, 1, f_rubyeval},
863#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864 {"screenattr", 2, 2, f_screenattr},
865 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100866 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200867 {"screencol", 0, 0, f_screencol},
868 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100869 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870 {"search", 1, 4, f_search},
871 {"searchdecl", 1, 3, f_searchdecl},
872 {"searchpair", 3, 7, f_searchpair},
873 {"searchpairpos", 3, 7, f_searchpairpos},
874 {"searchpos", 1, 4, f_searchpos},
875 {"server2client", 2, 2, f_server2client},
876 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200877 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878 {"setbufvar", 3, 3, f_setbufvar},
879 {"setcharsearch", 1, 1, f_setcharsearch},
880 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200881 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200882 {"setfperm", 2, 2, f_setfperm},
883 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200884 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100885 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200887 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 {"setreg", 2, 3, f_setreg},
889 {"settabvar", 3, 3, f_settabvar},
890 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100891 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200892 {"setwinvar", 3, 3, f_setwinvar},
893#ifdef FEAT_CRYPT
894 {"sha256", 1, 1, f_sha256},
895#endif
896 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100897 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100898#ifdef FEAT_SIGNS
899 {"sign_define", 1, 2, f_sign_define},
900 {"sign_getdefined", 0, 1, f_sign_getdefined},
901 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100902 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100903 {"sign_place", 4, 5, f_sign_place},
904 {"sign_undefine", 0, 1, f_sign_undefine},
905 {"sign_unplace", 1, 2, f_sign_unplace},
906#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200907 {"simplify", 1, 1, f_simplify},
908#ifdef FEAT_FLOAT
909 {"sin", 1, 1, f_sin},
910 {"sinh", 1, 1, f_sinh},
911#endif
912 {"sort", 1, 3, f_sort},
913 {"soundfold", 1, 1, f_soundfold},
914 {"spellbadword", 0, 1, f_spellbadword},
915 {"spellsuggest", 1, 3, f_spellsuggest},
916 {"split", 1, 3, f_split},
917#ifdef FEAT_FLOAT
918 {"sqrt", 1, 1, f_sqrt},
919 {"str2float", 1, 1, f_str2float},
920#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200921 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922 {"str2nr", 1, 2, f_str2nr},
923 {"strcharpart", 2, 3, f_strcharpart},
924 {"strchars", 1, 2, f_strchars},
925 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
926#ifdef HAVE_STRFTIME
927 {"strftime", 1, 2, f_strftime},
928#endif
929 {"strgetchar", 2, 2, f_strgetchar},
930 {"stridx", 2, 3, f_stridx},
931 {"string", 1, 1, f_string},
932 {"strlen", 1, 1, f_strlen},
933 {"strpart", 2, 3, f_strpart},
934 {"strridx", 2, 3, f_strridx},
935 {"strtrans", 1, 1, f_strtrans},
936 {"strwidth", 1, 1, f_strwidth},
937 {"submatch", 1, 2, f_submatch},
938 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200939 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200940 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200941 {"synID", 3, 3, f_synID},
942 {"synIDattr", 2, 3, f_synIDattr},
943 {"synIDtrans", 1, 1, f_synIDtrans},
944 {"synconcealed", 2, 2, f_synconcealed},
945 {"synstack", 2, 2, f_synstack},
946 {"system", 1, 2, f_system},
947 {"systemlist", 1, 2, f_systemlist},
948 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
949 {"tabpagenr", 0, 1, f_tabpagenr},
950 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
951 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100952 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200953#ifdef FEAT_FLOAT
954 {"tan", 1, 1, f_tan},
955 {"tanh", 1, 1, f_tanh},
956#endif
957 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200958#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100959 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
960 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100961 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200962 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200963# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
964 {"term_getansicolors", 1, 1, f_term_getansicolors},
965# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200966 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200967 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200968 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200969 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200970 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200971 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200972 {"term_getstatus", 1, 1, f_term_getstatus},
973 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200974 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200975 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200976 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200977 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200978# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
979 {"term_setansicolors", 2, 2, f_term_setansicolors},
980# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100981 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100982 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200983 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200984 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200985 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200986#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200987 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
988 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200989 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200990 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100991 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100992 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200993#ifdef FEAT_JOB_CHANNEL
994 {"test_null_channel", 0, 0, f_test_null_channel},
995#endif
996 {"test_null_dict", 0, 0, f_test_null_dict},
997#ifdef FEAT_JOB_CHANNEL
998 {"test_null_job", 0, 0, f_test_null_job},
999#endif
1000 {"test_null_list", 0, 0, f_test_null_list},
1001 {"test_null_partial", 0, 0, f_test_null_partial},
1002 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +02001003 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +01001004 {"test_override", 2, 2, f_test_override},
1005 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +02001006#ifdef FEAT_GUI
1007 {"test_scrollbar", 3, 3, f_test_scrollbar},
1008#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +02001009#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +02001010 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +02001011#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012 {"test_settime", 1, 1, f_test_settime},
1013#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001014 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001015 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001016 {"timer_start", 2, 3, f_timer_start},
1017 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001018 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019#endif
1020 {"tolower", 1, 1, f_tolower},
1021 {"toupper", 1, 1, f_toupper},
1022 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01001023 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001024#ifdef FEAT_FLOAT
1025 {"trunc", 1, 1, f_trunc},
1026#endif
1027 {"type", 1, 1, f_type},
1028 {"undofile", 1, 1, f_undofile},
1029 {"undotree", 0, 0, f_undotree},
1030 {"uniq", 1, 3, f_uniq},
1031 {"values", 1, 1, f_values},
1032 {"virtcol", 1, 1, f_virtcol},
1033 {"visualmode", 0, 1, f_visualmode},
1034 {"wildmenumode", 0, 0, f_wildmenumode},
1035 {"win_findbuf", 1, 1, f_win_findbuf},
1036 {"win_getid", 0, 2, f_win_getid},
1037 {"win_gotoid", 1, 1, f_win_gotoid},
1038 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1039 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001040 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001041 {"winbufnr", 1, 1, f_winbufnr},
1042 {"wincol", 0, 0, f_wincol},
1043 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001044 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001045 {"winline", 0, 0, f_winline},
1046 {"winnr", 0, 1, f_winnr},
1047 {"winrestcmd", 0, 0, f_winrestcmd},
1048 {"winrestview", 1, 1, f_winrestview},
1049 {"winsaveview", 0, 0, f_winsaveview},
1050 {"winwidth", 1, 1, f_winwidth},
1051 {"wordcount", 0, 0, f_wordcount},
1052 {"writefile", 2, 3, f_writefile},
1053 {"xor", 2, 2, f_xor},
1054};
1055
1056#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1057
1058/*
1059 * Function given to ExpandGeneric() to obtain the list of internal
1060 * or user defined function names.
1061 */
1062 char_u *
1063get_function_name(expand_T *xp, int idx)
1064{
1065 static int intidx = -1;
1066 char_u *name;
1067
1068 if (idx == 0)
1069 intidx = -1;
1070 if (intidx < 0)
1071 {
1072 name = get_user_func_name(xp, idx);
1073 if (name != NULL)
1074 return name;
1075 }
1076 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1077 {
1078 STRCPY(IObuff, functions[intidx].f_name);
1079 STRCAT(IObuff, "(");
1080 if (functions[intidx].f_max_argc == 0)
1081 STRCAT(IObuff, ")");
1082 return IObuff;
1083 }
1084
1085 return NULL;
1086}
1087
1088/*
1089 * Function given to ExpandGeneric() to obtain the list of internal or
1090 * user defined variable or function names.
1091 */
1092 char_u *
1093get_expr_name(expand_T *xp, int idx)
1094{
1095 static int intidx = -1;
1096 char_u *name;
1097
1098 if (idx == 0)
1099 intidx = -1;
1100 if (intidx < 0)
1101 {
1102 name = get_function_name(xp, idx);
1103 if (name != NULL)
1104 return name;
1105 }
1106 return get_user_var_name(xp, ++intidx);
1107}
1108
1109#endif /* FEAT_CMDL_COMPL */
1110
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001111/*
1112 * Find internal function in table above.
1113 * Return index, or -1 if not found
1114 */
1115 int
1116find_internal_func(
1117 char_u *name) /* name of the function */
1118{
1119 int first = 0;
1120 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1121 int cmp;
1122 int x;
1123
1124 /*
1125 * Find the function name in the table. Binary search.
1126 */
1127 while (first <= last)
1128 {
1129 x = first + ((unsigned)(last - first) >> 1);
1130 cmp = STRCMP(name, functions[x].f_name);
1131 if (cmp < 0)
1132 last = x - 1;
1133 else if (cmp > 0)
1134 first = x + 1;
1135 else
1136 return x;
1137 }
1138 return -1;
1139}
1140
1141 int
1142call_internal_func(
1143 char_u *name,
1144 int argcount,
1145 typval_T *argvars,
1146 typval_T *rettv)
1147{
1148 int i;
1149
1150 i = find_internal_func(name);
1151 if (i < 0)
1152 return ERROR_UNKNOWN;
1153 if (argcount < functions[i].f_min_argc)
1154 return ERROR_TOOFEW;
1155 if (argcount > functions[i].f_max_argc)
1156 return ERROR_TOOMANY;
1157 argvars[argcount].v_type = VAR_UNKNOWN;
1158 functions[i].f_func(argvars, rettv);
1159 return ERROR_NONE;
1160}
1161
1162/*
1163 * Return TRUE for a non-zero Number and a non-empty String.
1164 */
1165 static int
1166non_zero_arg(typval_T *argvars)
1167{
1168 return ((argvars[0].v_type == VAR_NUMBER
1169 && argvars[0].vval.v_number != 0)
1170 || (argvars[0].v_type == VAR_SPECIAL
1171 && argvars[0].vval.v_number == VVAL_TRUE)
1172 || (argvars[0].v_type == VAR_STRING
1173 && argvars[0].vval.v_string != NULL
1174 && *argvars[0].vval.v_string != NUL));
1175}
1176
1177/*
1178 * Get the lnum from the first argument.
1179 * Also accepts ".", "$", etc., but that only works for the current buffer.
1180 * Returns -1 on error.
1181 */
1182 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001183tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001184{
1185 typval_T rettv;
1186 linenr_T lnum;
1187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001188 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001189 if (lnum == 0) /* no valid number, try using line() */
1190 {
1191 rettv.v_type = VAR_NUMBER;
1192 f_line(argvars, &rettv);
1193 lnum = (linenr_T)rettv.vval.v_number;
1194 clear_tv(&rettv);
1195 }
1196 return lnum;
1197}
1198
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001199/*
1200 * Get the lnum from the first argument.
1201 * Also accepts "$", then "buf" is used.
1202 * Returns 0 on error.
1203 */
1204 static linenr_T
1205tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1206{
1207 if (argvars[0].v_type == VAR_STRING
1208 && argvars[0].vval.v_string != NULL
1209 && argvars[0].vval.v_string[0] == '$'
1210 && buf != NULL)
1211 return buf->b_ml.ml_line_count;
1212 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1213}
1214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001215#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001216/*
1217 * Get the float value of "argvars[0]" into "f".
1218 * Returns FAIL when the argument is not a Number or Float.
1219 */
1220 static int
1221get_float_arg(typval_T *argvars, float_T *f)
1222{
1223 if (argvars[0].v_type == VAR_FLOAT)
1224 {
1225 *f = argvars[0].vval.v_float;
1226 return OK;
1227 }
1228 if (argvars[0].v_type == VAR_NUMBER)
1229 {
1230 *f = (float_T)argvars[0].vval.v_number;
1231 return OK;
1232 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001233 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234 return FAIL;
1235}
1236
1237/*
1238 * "abs(expr)" function
1239 */
1240 static void
1241f_abs(typval_T *argvars, typval_T *rettv)
1242{
1243 if (argvars[0].v_type == VAR_FLOAT)
1244 {
1245 rettv->v_type = VAR_FLOAT;
1246 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1247 }
1248 else
1249 {
1250 varnumber_T n;
1251 int error = FALSE;
1252
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001253 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254 if (error)
1255 rettv->vval.v_number = -1;
1256 else if (n > 0)
1257 rettv->vval.v_number = n;
1258 else
1259 rettv->vval.v_number = -n;
1260 }
1261}
1262
1263/*
1264 * "acos()" function
1265 */
1266 static void
1267f_acos(typval_T *argvars, typval_T *rettv)
1268{
1269 float_T f = 0.0;
1270
1271 rettv->v_type = VAR_FLOAT;
1272 if (get_float_arg(argvars, &f) == OK)
1273 rettv->vval.v_float = acos(f);
1274 else
1275 rettv->vval.v_float = 0.0;
1276}
1277#endif
1278
1279/*
1280 * "add(list, item)" function
1281 */
1282 static void
1283f_add(typval_T *argvars, typval_T *rettv)
1284{
1285 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001286 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001287
1288 rettv->vval.v_number = 1; /* Default: Failed */
1289 if (argvars[0].v_type == VAR_LIST)
1290 {
1291 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001292 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 (char_u *)N_("add() argument"), TRUE)
1294 && list_append_tv(l, &argvars[1]) == OK)
1295 copy_tv(&argvars[0], rettv);
1296 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001297 else if (argvars[0].v_type == VAR_BLOB)
1298 {
1299 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001300 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001301 (char_u *)N_("add() argument"), TRUE))
1302 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001303 int error = FALSE;
1304 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1305
1306 if (!error)
1307 {
1308 ga_append(&b->bv_ga, (int)n);
1309 copy_tv(&argvars[0], rettv);
1310 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001311 }
1312 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001314 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001315}
1316
1317/*
1318 * "and(expr, expr)" function
1319 */
1320 static void
1321f_and(typval_T *argvars, typval_T *rettv)
1322{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001323 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1324 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001325}
1326
1327/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001328 * If there is a window for "curbuf", make it the current window.
1329 */
1330 static void
1331find_win_for_curbuf(void)
1332{
1333 wininfo_T *wip;
1334
1335 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1336 {
1337 if (wip->wi_win != NULL)
1338 {
1339 curwin = wip->wi_win;
1340 break;
1341 }
1342 }
1343}
1344
1345/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001346 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 */
1348 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001349set_buffer_lines(
1350 buf_T *buf,
1351 linenr_T lnum_arg,
1352 int append,
1353 typval_T *lines,
1354 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355{
Bram Moolenaarca851592018-06-06 21:04:07 +02001356 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1357 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 list_T *l = NULL;
1359 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001361 linenr_T append_lnum;
1362 buf_T *curbuf_save = NULL;
1363 win_T *curwin_save = NULL;
1364 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365
Bram Moolenaarca851592018-06-06 21:04:07 +02001366 /* When using the current buffer ml_mfp will be set if needed. Useful when
1367 * setline() is used on startup. For other buffers the buffer must be
1368 * loaded. */
1369 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001371 rettv->vval.v_number = 1; /* FAIL */
1372 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001373 }
1374
Bram Moolenaarca851592018-06-06 21:04:07 +02001375 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001377 curbuf_save = curbuf;
1378 curwin_save = curwin;
1379 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001380 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001381 }
1382
1383 if (append)
1384 // appendbufline() uses the line number below which we insert
1385 append_lnum = lnum - 1;
1386 else
1387 // setbufline() uses the line number above which we insert, we only
1388 // append if it's below the last line
1389 append_lnum = curbuf->b_ml.ml_line_count;
1390
1391 if (lines->v_type == VAR_LIST)
1392 {
1393 l = lines->vval.v_list;
1394 li = l->lv_first;
1395 }
1396 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001397 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001398
1399 /* default result is zero == OK */
1400 for (;;)
1401 {
1402 if (l != NULL)
1403 {
1404 /* list argument, get next string */
1405 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001406 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001407 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001408 li = li->li_next;
1409 }
1410
Bram Moolenaarca851592018-06-06 21:04:07 +02001411 rettv->vval.v_number = 1; /* FAIL */
1412 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1413 break;
1414
1415 /* When coming here from Insert mode, sync undo, so that this can be
1416 * undone separately from what was previously inserted. */
1417 if (u_sync_once == 2)
1418 {
1419 u_sync_once = 1; /* notify that u_sync() was called */
1420 u_sync(TRUE);
1421 }
1422
1423 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1424 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001425 // Existing line, replace it.
1426 // Removes any existing text properties.
1427 if (u_savesub(lnum) == OK && ml_replace_len(
1428 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001429 {
1430 changed_bytes(lnum, 0);
1431 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1432 check_cursor_col();
1433 rettv->vval.v_number = 0; /* OK */
1434 }
1435 }
1436 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1437 {
1438 /* append the line */
1439 ++added;
1440 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1441 rettv->vval.v_number = 0; /* OK */
1442 }
1443
1444 if (l == NULL) /* only one string argument */
1445 break;
1446 ++lnum;
1447 }
1448
1449 if (added > 0)
1450 {
1451 win_T *wp;
1452 tabpage_T *tp;
1453
1454 appended_lines_mark(append_lnum, added);
1455 FOR_ALL_TAB_WINDOWS(tp, wp)
1456 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1457 wp->w_cursor.lnum += added;
1458 check_cursor_col();
1459
Bram Moolenaarf2732452018-06-03 14:47:35 +02001460#ifdef FEAT_JOB_CHANNEL
1461 if (bt_prompt(curbuf) && (State & INSERT))
1462 // show the line with the prompt
1463 update_topline();
1464#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001465 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001466
1467 if (!is_curbuf)
1468 {
1469 curbuf = curbuf_save;
1470 curwin = curwin_save;
1471 }
1472}
1473
1474/*
1475 * "append(lnum, string/list)" function
1476 */
1477 static void
1478f_append(typval_T *argvars, typval_T *rettv)
1479{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001480 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001481
1482 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1483}
1484
1485/*
1486 * "appendbufline(buf, lnum, string/list)" function
1487 */
1488 static void
1489f_appendbufline(typval_T *argvars, typval_T *rettv)
1490{
1491 linenr_T lnum;
1492 buf_T *buf;
1493
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001494 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001495 if (buf == NULL)
1496 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001499 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001500 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502}
1503
1504/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001505 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 */
1507 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001508f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001509{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001510 win_T *wp;
1511
1512 if (argvars[0].v_type == VAR_UNKNOWN)
1513 // use the current window
1514 rettv->vval.v_number = ARGCOUNT;
1515 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001516 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001517 // use the global argument list
1518 rettv->vval.v_number = GARGCOUNT;
1519 else
1520 {
1521 // use the argument list of the specified window
1522 wp = find_win_by_nr_or_id(&argvars[0]);
1523 if (wp != NULL)
1524 rettv->vval.v_number = WARGCOUNT(wp);
1525 else
1526 rettv->vval.v_number = -1;
1527 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001528}
1529
1530/*
1531 * "argidx()" function
1532 */
1533 static void
1534f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1535{
1536 rettv->vval.v_number = curwin->w_arg_idx;
1537}
1538
1539/*
1540 * "arglistid()" function
1541 */
1542 static void
1543f_arglistid(typval_T *argvars, typval_T *rettv)
1544{
1545 win_T *wp;
1546
1547 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001548 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549 if (wp != NULL)
1550 rettv->vval.v_number = wp->w_alist->id;
1551}
1552
1553/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001554 * Get the argument list for a given window
1555 */
1556 static void
1557get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1558{
1559 int idx;
1560
1561 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1562 for (idx = 0; idx < argcount; ++idx)
1563 list_append_string(rettv->vval.v_list,
1564 alist_name(&arglist[idx]), -1);
1565}
1566
1567/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 * "argv(nr)" function
1569 */
1570 static void
1571f_argv(typval_T *argvars, typval_T *rettv)
1572{
1573 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001574 aentry_T *arglist = NULL;
1575 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576
1577 if (argvars[0].v_type != VAR_UNKNOWN)
1578 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001579 if (argvars[1].v_type == VAR_UNKNOWN)
1580 {
1581 arglist = ARGLIST;
1582 argcount = ARGCOUNT;
1583 }
1584 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001585 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001586 {
1587 arglist = GARGLIST;
1588 argcount = GARGCOUNT;
1589 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001590 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001591 {
1592 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1593
1594 if (wp != NULL)
1595 {
1596 /* Use the argument list of the specified window */
1597 arglist = WARGLIST(wp);
1598 argcount = WARGCOUNT(wp);
1599 }
1600 }
1601
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001603 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001604 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001605 if (arglist != NULL && idx >= 0 && idx < argcount)
1606 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1607 else if (idx == -1)
1608 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001610 else
1611 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612}
1613
1614/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001615 * "assert_beeps(cmd [, error])" function
1616 */
1617 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001618f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001619{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001620 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001621}
1622
1623/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624 * "assert_equal(expected, actual[, msg])" function
1625 */
1626 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001627f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001628{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001629 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630}
1631
1632/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001633 * "assert_equalfile(fname-one, fname-two)" function
1634 */
1635 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001636f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001637{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001638 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001639}
1640
1641/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001642 * "assert_notequal(expected, actual[, msg])" function
1643 */
1644 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001645f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001647 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648}
1649
1650/*
1651 * "assert_exception(string[, msg])" function
1652 */
1653 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001654f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001655{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001656 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001657}
1658
1659/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001660 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661 */
1662 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001663f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001664{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001665 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001666}
1667
1668/*
1669 * "assert_false(actual[, msg])" function
1670 */
1671 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001672f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001674 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675}
1676
1677/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001678 * "assert_inrange(lower, upper[, msg])" function
1679 */
1680 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001681f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001682{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001683 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001684}
1685
1686/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 * "assert_match(pattern, actual[, msg])" function
1688 */
1689 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001690f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001692 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693}
1694
1695/*
1696 * "assert_notmatch(pattern, actual[, msg])" function
1697 */
1698 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001699f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001700{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001701 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702}
1703
1704/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001705 * "assert_report(msg)" function
1706 */
1707 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001708f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001709{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001710 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001711}
1712
1713/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 * "assert_true(actual[, msg])" function
1715 */
1716 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001717f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001719 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720}
1721
1722#ifdef FEAT_FLOAT
1723/*
1724 * "asin()" function
1725 */
1726 static void
1727f_asin(typval_T *argvars, typval_T *rettv)
1728{
1729 float_T f = 0.0;
1730
1731 rettv->v_type = VAR_FLOAT;
1732 if (get_float_arg(argvars, &f) == OK)
1733 rettv->vval.v_float = asin(f);
1734 else
1735 rettv->vval.v_float = 0.0;
1736}
1737
1738/*
1739 * "atan()" function
1740 */
1741 static void
1742f_atan(typval_T *argvars, typval_T *rettv)
1743{
1744 float_T f = 0.0;
1745
1746 rettv->v_type = VAR_FLOAT;
1747 if (get_float_arg(argvars, &f) == OK)
1748 rettv->vval.v_float = atan(f);
1749 else
1750 rettv->vval.v_float = 0.0;
1751}
1752
1753/*
1754 * "atan2()" function
1755 */
1756 static void
1757f_atan2(typval_T *argvars, typval_T *rettv)
1758{
1759 float_T fx = 0.0, fy = 0.0;
1760
1761 rettv->v_type = VAR_FLOAT;
1762 if (get_float_arg(argvars, &fx) == OK
1763 && get_float_arg(&argvars[1], &fy) == OK)
1764 rettv->vval.v_float = atan2(fx, fy);
1765 else
1766 rettv->vval.v_float = 0.0;
1767}
1768#endif
1769
1770/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001771 * "balloon_show()" function
1772 */
1773#ifdef FEAT_BEVAL
1774 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001775f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1776{
1777 rettv->v_type = VAR_STRING;
1778 if (balloonEval != NULL)
1779 {
1780 if (balloonEval->msg == NULL)
1781 rettv->vval.v_string = NULL;
1782 else
1783 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1784 }
1785}
1786
1787 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001788f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1789{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001790 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001791 {
1792 if (argvars[0].v_type == VAR_LIST
1793# ifdef FEAT_GUI
1794 && !gui.in_use
1795# endif
1796 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001797 {
1798 list_T *l = argvars[0].vval.v_list;
1799
1800 // empty list removes the balloon
1801 post_balloon(balloonEval, NULL,
1802 l == NULL || l->lv_len == 0 ? NULL : l);
1803 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001804 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001805 {
1806 char_u *mesg = tv_get_string_chk(&argvars[0]);
1807
1808 if (mesg != NULL)
1809 // empty string removes the balloon
1810 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1811 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001812 }
1813}
1814
Bram Moolenaar669a8282017-11-19 20:13:05 +01001815# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001816 static void
1817f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1818{
1819 if (rettv_list_alloc(rettv) == OK)
1820 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001821 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001822
1823 if (msg != NULL)
1824 {
1825 pumitem_T *array;
1826 int size = split_message(msg, &array);
1827 int i;
1828
1829 /* Skip the first and last item, they are always empty. */
1830 for (i = 1; i < size - 1; ++i)
1831 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001832 while (size > 0)
1833 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001834 vim_free(array);
1835 }
1836 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001837}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001838# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001839#endif
1840
1841/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 * "browse(save, title, initdir, default)" function
1843 */
1844 static void
1845f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1846{
1847#ifdef FEAT_BROWSE
1848 int save;
1849 char_u *title;
1850 char_u *initdir;
1851 char_u *defname;
1852 char_u buf[NUMBUFLEN];
1853 char_u buf2[NUMBUFLEN];
1854 int error = FALSE;
1855
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001856 save = (int)tv_get_number_chk(&argvars[0], &error);
1857 title = tv_get_string_chk(&argvars[1]);
1858 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1859 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001860
1861 if (error || title == NULL || initdir == NULL || defname == NULL)
1862 rettv->vval.v_string = NULL;
1863 else
1864 rettv->vval.v_string =
1865 do_browse(save ? BROWSE_SAVE : 0,
1866 title, defname, NULL, initdir, NULL, curbuf);
1867#else
1868 rettv->vval.v_string = NULL;
1869#endif
1870 rettv->v_type = VAR_STRING;
1871}
1872
1873/*
1874 * "browsedir(title, initdir)" function
1875 */
1876 static void
1877f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1878{
1879#ifdef FEAT_BROWSE
1880 char_u *title;
1881 char_u *initdir;
1882 char_u buf[NUMBUFLEN];
1883
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001884 title = tv_get_string_chk(&argvars[0]);
1885 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001886
1887 if (title == NULL || initdir == NULL)
1888 rettv->vval.v_string = NULL;
1889 else
1890 rettv->vval.v_string = do_browse(BROWSE_DIR,
1891 title, NULL, NULL, initdir, NULL, curbuf);
1892#else
1893 rettv->vval.v_string = NULL;
1894#endif
1895 rettv->v_type = VAR_STRING;
1896}
1897
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898/*
1899 * Find a buffer by number or exact name.
1900 */
1901 static buf_T *
1902find_buffer(typval_T *avar)
1903{
1904 buf_T *buf = NULL;
1905
1906 if (avar->v_type == VAR_NUMBER)
1907 buf = buflist_findnr((int)avar->vval.v_number);
1908 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1909 {
1910 buf = buflist_findname_exp(avar->vval.v_string);
1911 if (buf == NULL)
1912 {
1913 /* No full path name match, try a match with a URL or a "nofile"
1914 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001915 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916 if (buf->b_fname != NULL
1917 && (path_with_url(buf->b_fname)
1918#ifdef FEAT_QUICKFIX
1919 || bt_nofile(buf)
1920#endif
1921 )
1922 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1923 break;
1924 }
1925 }
1926 return buf;
1927}
1928
1929/*
1930 * "bufexists(expr)" function
1931 */
1932 static void
1933f_bufexists(typval_T *argvars, typval_T *rettv)
1934{
1935 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1936}
1937
1938/*
1939 * "buflisted(expr)" function
1940 */
1941 static void
1942f_buflisted(typval_T *argvars, typval_T *rettv)
1943{
1944 buf_T *buf;
1945
1946 buf = find_buffer(&argvars[0]);
1947 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1948}
1949
1950/*
1951 * "bufloaded(expr)" function
1952 */
1953 static void
1954f_bufloaded(typval_T *argvars, typval_T *rettv)
1955{
1956 buf_T *buf;
1957
1958 buf = find_buffer(&argvars[0]);
1959 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1960}
1961
1962 buf_T *
1963buflist_find_by_name(char_u *name, int curtab_only)
1964{
1965 int save_magic;
1966 char_u *save_cpo;
1967 buf_T *buf;
1968
1969 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1970 save_magic = p_magic;
1971 p_magic = TRUE;
1972 save_cpo = p_cpo;
1973 p_cpo = (char_u *)"";
1974
1975 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1976 TRUE, FALSE, curtab_only));
1977
1978 p_magic = save_magic;
1979 p_cpo = save_cpo;
1980 return buf;
1981}
1982
1983/*
1984 * Get buffer by number or pattern.
1985 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001986 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001987tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988{
1989 char_u *name = tv->vval.v_string;
1990 buf_T *buf;
1991
1992 if (tv->v_type == VAR_NUMBER)
1993 return buflist_findnr((int)tv->vval.v_number);
1994 if (tv->v_type != VAR_STRING)
1995 return NULL;
1996 if (name == NULL || *name == NUL)
1997 return curbuf;
1998 if (name[0] == '$' && name[1] == NUL)
1999 return lastbuf;
2000
2001 buf = buflist_find_by_name(name, curtab_only);
2002
2003 /* If not found, try expanding the name, like done for bufexists(). */
2004 if (buf == NULL)
2005 buf = find_buffer(tv);
2006
2007 return buf;
2008}
2009
Bram Moolenaarec9d3002019-01-12 13:50:31 +01002010#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002012 * Get the buffer from "arg" and give an error and return NULL if it is not
2013 * valid.
2014 */
2015 static buf_T *
2016get_buf_arg(typval_T *arg)
2017{
2018 buf_T *buf;
2019
2020 ++emsg_off;
2021 buf = tv_get_buf(arg, FALSE);
2022 --emsg_off;
2023 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002024 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002025 return buf;
2026}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01002027#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002028
2029/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030 * "bufname(expr)" function
2031 */
2032 static void
2033f_bufname(typval_T *argvars, typval_T *rettv)
2034{
2035 buf_T *buf;
2036
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002037 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002038 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002039 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 rettv->v_type = VAR_STRING;
2041 if (buf != NULL && buf->b_fname != NULL)
2042 rettv->vval.v_string = vim_strsave(buf->b_fname);
2043 else
2044 rettv->vval.v_string = NULL;
2045 --emsg_off;
2046}
2047
2048/*
2049 * "bufnr(expr)" function
2050 */
2051 static void
2052f_bufnr(typval_T *argvars, typval_T *rettv)
2053{
2054 buf_T *buf;
2055 int error = FALSE;
2056 char_u *name;
2057
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002058 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002059 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002060 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 --emsg_off;
2062
2063 /* If the buffer isn't found and the second argument is not zero create a
2064 * new buffer. */
2065 if (buf == NULL
2066 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002067 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002068 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002069 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002070 && !error)
2071 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2072
2073 if (buf != NULL)
2074 rettv->vval.v_number = buf->b_fnum;
2075 else
2076 rettv->vval.v_number = -1;
2077}
2078
2079 static void
2080buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2081{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 win_T *wp;
2083 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002084 buf_T *buf;
2085
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002086 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002087 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002088 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002089 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090 {
2091 ++winnr;
2092 if (wp->w_buffer == buf)
2093 break;
2094 }
2095 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002096 --emsg_off;
2097}
2098
2099/*
2100 * "bufwinid(nr)" function
2101 */
2102 static void
2103f_bufwinid(typval_T *argvars, typval_T *rettv)
2104{
2105 buf_win_common(argvars, rettv, FALSE);
2106}
2107
2108/*
2109 * "bufwinnr(nr)" function
2110 */
2111 static void
2112f_bufwinnr(typval_T *argvars, typval_T *rettv)
2113{
2114 buf_win_common(argvars, rettv, TRUE);
2115}
2116
2117/*
2118 * "byte2line(byte)" function
2119 */
2120 static void
2121f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2122{
2123#ifndef FEAT_BYTEOFF
2124 rettv->vval.v_number = -1;
2125#else
2126 long boff = 0;
2127
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002128 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002129 if (boff < 0)
2130 rettv->vval.v_number = -1;
2131 else
2132 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2133 (linenr_T)0, &boff);
2134#endif
2135}
2136
2137 static void
2138byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2139{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002140 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002141 char_u *str;
2142 varnumber_T idx;
2143
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002144 str = tv_get_string_chk(&argvars[0]);
2145 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146 rettv->vval.v_number = -1;
2147 if (str == NULL || idx < 0)
2148 return;
2149
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002150 t = str;
2151 for ( ; idx > 0; idx--)
2152 {
2153 if (*t == NUL) /* EOL reached */
2154 return;
2155 if (enc_utf8 && comp)
2156 t += utf_ptr2len(t);
2157 else
2158 t += (*mb_ptr2len)(t);
2159 }
2160 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161}
2162
2163/*
2164 * "byteidx()" function
2165 */
2166 static void
2167f_byteidx(typval_T *argvars, typval_T *rettv)
2168{
2169 byteidx(argvars, rettv, FALSE);
2170}
2171
2172/*
2173 * "byteidxcomp()" function
2174 */
2175 static void
2176f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2177{
2178 byteidx(argvars, rettv, TRUE);
2179}
2180
2181/*
2182 * "call(func, arglist [, dict])" function
2183 */
2184 static void
2185f_call(typval_T *argvars, typval_T *rettv)
2186{
2187 char_u *func;
2188 partial_T *partial = NULL;
2189 dict_T *selfdict = NULL;
2190
2191 if (argvars[1].v_type != VAR_LIST)
2192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002193 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002194 return;
2195 }
2196 if (argvars[1].vval.v_list == NULL)
2197 return;
2198
2199 if (argvars[0].v_type == VAR_FUNC)
2200 func = argvars[0].vval.v_string;
2201 else if (argvars[0].v_type == VAR_PARTIAL)
2202 {
2203 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002204 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002205 }
2206 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002207 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002208 if (*func == NUL)
2209 return; /* type error or empty name */
2210
2211 if (argvars[2].v_type != VAR_UNKNOWN)
2212 {
2213 if (argvars[2].v_type != VAR_DICT)
2214 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002215 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 return;
2217 }
2218 selfdict = argvars[2].vval.v_dict;
2219 }
2220
2221 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2222}
2223
2224#ifdef FEAT_FLOAT
2225/*
2226 * "ceil({float})" function
2227 */
2228 static void
2229f_ceil(typval_T *argvars, typval_T *rettv)
2230{
2231 float_T f = 0.0;
2232
2233 rettv->v_type = VAR_FLOAT;
2234 if (get_float_arg(argvars, &f) == OK)
2235 rettv->vval.v_float = ceil(f);
2236 else
2237 rettv->vval.v_float = 0.0;
2238}
2239#endif
2240
2241#ifdef FEAT_JOB_CHANNEL
2242/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002243 * "ch_canread()" function
2244 */
2245 static void
2246f_ch_canread(typval_T *argvars, typval_T *rettv)
2247{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002248 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002249
2250 rettv->vval.v_number = 0;
2251 if (channel != NULL)
2252 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2253 || channel_has_readahead(channel, PART_OUT)
2254 || channel_has_readahead(channel, PART_ERR);
2255}
2256
2257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258 * "ch_close()" function
2259 */
2260 static void
2261f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2262{
2263 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2264
2265 if (channel != NULL)
2266 {
2267 channel_close(channel, FALSE);
2268 channel_clear(channel);
2269 }
2270}
2271
2272/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002273 * "ch_close()" function
2274 */
2275 static void
2276f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2277{
2278 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2279
2280 if (channel != NULL)
2281 channel_close_in(channel);
2282}
2283
2284/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002285 * "ch_getbufnr()" function
2286 */
2287 static void
2288f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2289{
2290 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2291
2292 rettv->vval.v_number = -1;
2293 if (channel != NULL)
2294 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002295 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 int part;
2297
2298 if (STRCMP(what, "err") == 0)
2299 part = PART_ERR;
2300 else if (STRCMP(what, "out") == 0)
2301 part = PART_OUT;
2302 else if (STRCMP(what, "in") == 0)
2303 part = PART_IN;
2304 else
2305 part = PART_SOCK;
2306 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2307 rettv->vval.v_number =
2308 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2309 }
2310}
2311
2312/*
2313 * "ch_getjob()" function
2314 */
2315 static void
2316f_ch_getjob(typval_T *argvars, typval_T *rettv)
2317{
2318 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2319
2320 if (channel != NULL)
2321 {
2322 rettv->v_type = VAR_JOB;
2323 rettv->vval.v_job = channel->ch_job;
2324 if (channel->ch_job != NULL)
2325 ++channel->ch_job->jv_refcount;
2326 }
2327}
2328
2329/*
2330 * "ch_info()" function
2331 */
2332 static void
2333f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2334{
2335 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2336
2337 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2338 channel_info(channel, rettv->vval.v_dict);
2339}
2340
2341/*
2342 * "ch_log()" function
2343 */
2344 static void
2345f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2346{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002347 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002348 channel_T *channel = NULL;
2349
2350 if (argvars[1].v_type != VAR_UNKNOWN)
2351 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2352
Bram Moolenaard5359b22018-04-05 22:44:39 +02002353 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002354}
2355
2356/*
2357 * "ch_logfile()" function
2358 */
2359 static void
2360f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2361{
2362 char_u *fname;
2363 char_u *opt = (char_u *)"";
2364 char_u buf[NUMBUFLEN];
2365
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002366 /* Don't open a file in restricted mode. */
2367 if (check_restricted() || check_secure())
2368 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002369 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002371 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002372 ch_logfile(fname, opt);
2373}
2374
2375/*
2376 * "ch_open()" function
2377 */
2378 static void
2379f_ch_open(typval_T *argvars, typval_T *rettv)
2380{
2381 rettv->v_type = VAR_CHANNEL;
2382 if (check_restricted() || check_secure())
2383 return;
2384 rettv->vval.v_channel = channel_open_func(argvars);
2385}
2386
2387/*
2388 * "ch_read()" function
2389 */
2390 static void
2391f_ch_read(typval_T *argvars, typval_T *rettv)
2392{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002393 common_channel_read(argvars, rettv, FALSE, FALSE);
2394}
2395
2396/*
2397 * "ch_readblob()" function
2398 */
2399 static void
2400f_ch_readblob(typval_T *argvars, typval_T *rettv)
2401{
2402 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002403}
2404
2405/*
2406 * "ch_readraw()" function
2407 */
2408 static void
2409f_ch_readraw(typval_T *argvars, typval_T *rettv)
2410{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002411 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002412}
2413
2414/*
2415 * "ch_evalexpr()" function
2416 */
2417 static void
2418f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2419{
2420 ch_expr_common(argvars, rettv, TRUE);
2421}
2422
2423/*
2424 * "ch_sendexpr()" function
2425 */
2426 static void
2427f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2428{
2429 ch_expr_common(argvars, rettv, FALSE);
2430}
2431
2432/*
2433 * "ch_evalraw()" function
2434 */
2435 static void
2436f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2437{
2438 ch_raw_common(argvars, rettv, TRUE);
2439}
2440
2441/*
2442 * "ch_sendraw()" function
2443 */
2444 static void
2445f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2446{
2447 ch_raw_common(argvars, rettv, FALSE);
2448}
2449
2450/*
2451 * "ch_setoptions()" function
2452 */
2453 static void
2454f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2455{
2456 channel_T *channel;
2457 jobopt_T opt;
2458
2459 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2460 if (channel == NULL)
2461 return;
2462 clear_job_options(&opt);
2463 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002464 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 channel_set_options(channel, &opt);
2466 free_job_options(&opt);
2467}
2468
2469/*
2470 * "ch_status()" function
2471 */
2472 static void
2473f_ch_status(typval_T *argvars, typval_T *rettv)
2474{
2475 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002476 jobopt_T opt;
2477 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002478
2479 /* return an empty string by default */
2480 rettv->v_type = VAR_STRING;
2481 rettv->vval.v_string = NULL;
2482
2483 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002484
2485 if (argvars[1].v_type != VAR_UNKNOWN)
2486 {
2487 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002488 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002489 && (opt.jo_set & JO_PART))
2490 part = opt.jo_part;
2491 }
2492
2493 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002494}
2495#endif
2496
2497/*
2498 * "changenr()" function
2499 */
2500 static void
2501f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2502{
2503 rettv->vval.v_number = curbuf->b_u_seq_cur;
2504}
2505
2506/*
2507 * "char2nr(string)" function
2508 */
2509 static void
2510f_char2nr(typval_T *argvars, typval_T *rettv)
2511{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512 if (has_mbyte)
2513 {
2514 int utf8 = 0;
2515
2516 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002517 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002518
2519 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002520 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002522 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002523 }
2524 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002525 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526}
2527
2528/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002529 * "chdir(dir)" function
2530 */
2531 static void
2532f_chdir(typval_T *argvars, typval_T *rettv)
2533{
2534 char_u *cwd;
2535 cdscope_T scope = CDSCOPE_GLOBAL;
2536
2537 rettv->v_type = VAR_STRING;
2538 rettv->vval.v_string = NULL;
2539
2540 if (argvars[0].v_type != VAR_STRING)
2541 return;
2542
2543 // Return the current directory
2544 cwd = alloc(MAXPATHL);
2545 if (cwd != NULL)
2546 {
2547 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2548 {
2549#ifdef BACKSLASH_IN_FILENAME
2550 slash_adjust(cwd);
2551#endif
2552 rettv->vval.v_string = vim_strsave(cwd);
2553 }
2554 vim_free(cwd);
2555 }
2556
2557 if (curwin->w_localdir != NULL)
2558 scope = CDSCOPE_WINDOW;
2559 else if (curtab->tp_localdir != NULL)
2560 scope = CDSCOPE_TABPAGE;
2561
2562 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2563 // Directory change failed
2564 VIM_CLEAR(rettv->vval.v_string);
2565}
2566
2567/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002568 * "cindent(lnum)" function
2569 */
2570 static void
2571f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2572{
2573#ifdef FEAT_CINDENT
2574 pos_T pos;
2575 linenr_T lnum;
2576
2577 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002578 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002579 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2580 {
2581 curwin->w_cursor.lnum = lnum;
2582 rettv->vval.v_number = get_c_indent();
2583 curwin->w_cursor = pos;
2584 }
2585 else
2586#endif
2587 rettv->vval.v_number = -1;
2588}
2589
Bram Moolenaaraff74912019-03-30 18:11:49 +01002590 static win_T *
2591get_optional_window(typval_T *argvars, int idx)
2592{
2593 win_T *win = curwin;
2594
2595 if (argvars[idx].v_type != VAR_UNKNOWN)
2596 {
2597 win = find_win_by_nr_or_id(&argvars[idx]);
2598 if (win == NULL)
2599 {
2600 emsg(_(e_invalwindow));
2601 return NULL;
2602 }
2603 }
2604 return win;
2605}
2606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607/*
2608 * "clearmatches()" function
2609 */
2610 static void
2611f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2612{
2613#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002614 win_T *win = get_optional_window(argvars, 0);
2615
2616 if (win != NULL)
2617 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618#endif
2619}
2620
2621/*
2622 * "col(string)" function
2623 */
2624 static void
2625f_col(typval_T *argvars, typval_T *rettv)
2626{
2627 colnr_T col = 0;
2628 pos_T *fp;
2629 int fnum = curbuf->b_fnum;
2630
2631 fp = var2fpos(&argvars[0], FALSE, &fnum);
2632 if (fp != NULL && fnum == curbuf->b_fnum)
2633 {
2634 if (fp->col == MAXCOL)
2635 {
2636 /* '> can be MAXCOL, get the length of the line then */
2637 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2638 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2639 else
2640 col = MAXCOL;
2641 }
2642 else
2643 {
2644 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002645 /* col(".") when the cursor is on the NUL at the end of the line
2646 * because of "coladd" can be seen as an extra column. */
2647 if (virtual_active() && fp == &curwin->w_cursor)
2648 {
2649 char_u *p = ml_get_cursor();
2650
2651 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2652 curwin->w_virtcol - curwin->w_cursor.coladd))
2653 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002654 int l;
2655
2656 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2657 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658 }
2659 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002660 }
2661 }
2662 rettv->vval.v_number = col;
2663}
2664
2665#if defined(FEAT_INS_EXPAND)
2666/*
2667 * "complete()" function
2668 */
2669 static void
2670f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2671{
2672 int startcol;
2673
2674 if ((State & INSERT) == 0)
2675 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002676 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 return;
2678 }
2679
2680 /* Check for undo allowed here, because if something was already inserted
2681 * the line was already saved for undo and this check isn't done. */
2682 if (!undo_allowed())
2683 return;
2684
2685 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2686 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002687 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002688 return;
2689 }
2690
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002691 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692 if (startcol <= 0)
2693 return;
2694
2695 set_completion(startcol - 1, argvars[1].vval.v_list);
2696}
2697
2698/*
2699 * "complete_add()" function
2700 */
2701 static void
2702f_complete_add(typval_T *argvars, typval_T *rettv)
2703{
2704 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2705}
2706
2707/*
2708 * "complete_check()" function
2709 */
2710 static void
2711f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2712{
2713 int saved = RedrawingDisabled;
2714
2715 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002716 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002717 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002718 RedrawingDisabled = saved;
2719}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002720
2721/*
2722 * "complete_info()" function
2723 */
2724 static void
2725f_complete_info(typval_T *argvars, typval_T *rettv)
2726{
2727 list_T *what_list = NULL;
2728
2729 if (rettv_dict_alloc(rettv) != OK)
2730 return;
2731
2732 if (argvars[0].v_type != VAR_UNKNOWN)
2733 {
2734 if (argvars[0].v_type != VAR_LIST)
2735 {
2736 emsg(_(e_listreq));
2737 return;
2738 }
2739 what_list = argvars[0].vval.v_list;
2740 }
2741 get_complete_info(what_list, rettv->vval.v_dict);
2742}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743#endif
2744
2745/*
2746 * "confirm(message, buttons[, default [, type]])" function
2747 */
2748 static void
2749f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2750{
2751#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2752 char_u *message;
2753 char_u *buttons = NULL;
2754 char_u buf[NUMBUFLEN];
2755 char_u buf2[NUMBUFLEN];
2756 int def = 1;
2757 int type = VIM_GENERIC;
2758 char_u *typestr;
2759 int error = FALSE;
2760
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002761 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 if (message == NULL)
2763 error = TRUE;
2764 if (argvars[1].v_type != VAR_UNKNOWN)
2765 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002766 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002767 if (buttons == NULL)
2768 error = TRUE;
2769 if (argvars[2].v_type != VAR_UNKNOWN)
2770 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002771 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002772 if (argvars[3].v_type != VAR_UNKNOWN)
2773 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002774 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002775 if (typestr == NULL)
2776 error = TRUE;
2777 else
2778 {
2779 switch (TOUPPER_ASC(*typestr))
2780 {
2781 case 'E': type = VIM_ERROR; break;
2782 case 'Q': type = VIM_QUESTION; break;
2783 case 'I': type = VIM_INFO; break;
2784 case 'W': type = VIM_WARNING; break;
2785 case 'G': type = VIM_GENERIC; break;
2786 }
2787 }
2788 }
2789 }
2790 }
2791
2792 if (buttons == NULL || *buttons == NUL)
2793 buttons = (char_u *)_("&Ok");
2794
2795 if (!error)
2796 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2797 def, NULL, FALSE);
2798#endif
2799}
2800
2801/*
2802 * "copy()" function
2803 */
2804 static void
2805f_copy(typval_T *argvars, typval_T *rettv)
2806{
2807 item_copy(&argvars[0], rettv, FALSE, 0);
2808}
2809
2810#ifdef FEAT_FLOAT
2811/*
2812 * "cos()" function
2813 */
2814 static void
2815f_cos(typval_T *argvars, typval_T *rettv)
2816{
2817 float_T f = 0.0;
2818
2819 rettv->v_type = VAR_FLOAT;
2820 if (get_float_arg(argvars, &f) == OK)
2821 rettv->vval.v_float = cos(f);
2822 else
2823 rettv->vval.v_float = 0.0;
2824}
2825
2826/*
2827 * "cosh()" function
2828 */
2829 static void
2830f_cosh(typval_T *argvars, typval_T *rettv)
2831{
2832 float_T f = 0.0;
2833
2834 rettv->v_type = VAR_FLOAT;
2835 if (get_float_arg(argvars, &f) == OK)
2836 rettv->vval.v_float = cosh(f);
2837 else
2838 rettv->vval.v_float = 0.0;
2839}
2840#endif
2841
2842/*
2843 * "count()" function
2844 */
2845 static void
2846f_count(typval_T *argvars, typval_T *rettv)
2847{
2848 long n = 0;
2849 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002850 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851
Bram Moolenaar9966b212017-07-28 16:46:57 +02002852 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002853 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002854
2855 if (argvars[0].v_type == VAR_STRING)
2856 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002857 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002858 char_u *p = argvars[0].vval.v_string;
2859 char_u *next;
2860
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002861 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002862 {
2863 if (ic)
2864 {
2865 size_t len = STRLEN(expr);
2866
2867 while (*p != NUL)
2868 {
2869 if (MB_STRNICMP(p, expr, len) == 0)
2870 {
2871 ++n;
2872 p += len;
2873 }
2874 else
2875 MB_PTR_ADV(p);
2876 }
2877 }
2878 else
2879 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2880 != NULL)
2881 {
2882 ++n;
2883 p = next + STRLEN(expr);
2884 }
2885 }
2886
2887 }
2888 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002889 {
2890 listitem_T *li;
2891 list_T *l;
2892 long idx;
2893
2894 if ((l = argvars[0].vval.v_list) != NULL)
2895 {
2896 li = l->lv_first;
2897 if (argvars[2].v_type != VAR_UNKNOWN)
2898 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899 if (argvars[3].v_type != VAR_UNKNOWN)
2900 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002901 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002902 if (!error)
2903 {
2904 li = list_find(l, idx);
2905 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002906 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002907 }
2908 }
2909 if (error)
2910 li = NULL;
2911 }
2912
2913 for ( ; li != NULL; li = li->li_next)
2914 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2915 ++n;
2916 }
2917 }
2918 else if (argvars[0].v_type == VAR_DICT)
2919 {
2920 int todo;
2921 dict_T *d;
2922 hashitem_T *hi;
2923
2924 if ((d = argvars[0].vval.v_dict) != NULL)
2925 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926 if (argvars[2].v_type != VAR_UNKNOWN)
2927 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002929 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002930 }
2931
2932 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2933 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2934 {
2935 if (!HASHITEM_EMPTY(hi))
2936 {
2937 --todo;
2938 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2939 ++n;
2940 }
2941 }
2942 }
2943 }
2944 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002945 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946 rettv->vval.v_number = n;
2947}
2948
2949/*
2950 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2951 *
2952 * Checks the existence of a cscope connection.
2953 */
2954 static void
2955f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2956{
2957#ifdef FEAT_CSCOPE
2958 int num = 0;
2959 char_u *dbpath = NULL;
2960 char_u *prepend = NULL;
2961 char_u buf[NUMBUFLEN];
2962
2963 if (argvars[0].v_type != VAR_UNKNOWN
2964 && argvars[1].v_type != VAR_UNKNOWN)
2965 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002966 num = (int)tv_get_number(&argvars[0]);
2967 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002968 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002969 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002970 }
2971
2972 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2973#endif
2974}
2975
2976/*
2977 * "cursor(lnum, col)" function, or
2978 * "cursor(list)"
2979 *
2980 * Moves the cursor to the specified line and column.
2981 * Returns 0 when the position could be set, -1 otherwise.
2982 */
2983 static void
2984f_cursor(typval_T *argvars, typval_T *rettv)
2985{
2986 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002987 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002988 int set_curswant = TRUE;
2989
2990 rettv->vval.v_number = -1;
2991 if (argvars[1].v_type == VAR_UNKNOWN)
2992 {
2993 pos_T pos;
2994 colnr_T curswant = -1;
2995
2996 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2997 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002998 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002999 return;
3000 }
3001 line = pos.lnum;
3002 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003003 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003004 if (curswant >= 0)
3005 {
3006 curwin->w_curswant = curswant - 1;
3007 set_curswant = FALSE;
3008 }
3009 }
3010 else
3011 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003012 line = tv_get_lnum(argvars);
3013 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003015 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003017 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003018 return; /* type error; errmsg already given */
3019 if (line > 0)
3020 curwin->w_cursor.lnum = line;
3021 if (col > 0)
3022 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003023 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003024
3025 /* Make sure the cursor is in a valid position. */
3026 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003027 /* Correct cursor for multi-byte character. */
3028 if (has_mbyte)
3029 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003030
3031 curwin->w_set_curswant = set_curswant;
3032 rettv->vval.v_number = 0;
3033}
3034
Bram Moolenaar4f974752019-02-17 17:44:42 +01003035#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02003036/*
3037 * "debugbreak()" function
3038 */
3039 static void
3040f_debugbreak(typval_T *argvars, typval_T *rettv)
3041{
3042 int pid;
3043
3044 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003045 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02003046 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003047 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02003048 else
3049 {
3050 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
3051
3052 if (hProcess != NULL)
3053 {
3054 DebugBreakProcess(hProcess);
3055 CloseHandle(hProcess);
3056 rettv->vval.v_number = OK;
3057 }
3058 }
3059}
3060#endif
3061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062/*
3063 * "deepcopy()" function
3064 */
3065 static void
3066f_deepcopy(typval_T *argvars, typval_T *rettv)
3067{
3068 int noref = 0;
3069 int copyID;
3070
3071 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003072 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003074 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 else
3076 {
3077 copyID = get_copyID();
3078 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
3079 }
3080}
3081
3082/*
3083 * "delete()" function
3084 */
3085 static void
3086f_delete(typval_T *argvars, typval_T *rettv)
3087{
3088 char_u nbuf[NUMBUFLEN];
3089 char_u *name;
3090 char_u *flags;
3091
3092 rettv->vval.v_number = -1;
3093 if (check_restricted() || check_secure())
3094 return;
3095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003096 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003097 if (name == NULL || *name == NUL)
3098 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003099 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 return;
3101 }
3102
3103 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003104 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003105 else
3106 flags = (char_u *)"";
3107
3108 if (*flags == NUL)
3109 /* delete a file */
3110 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
3111 else if (STRCMP(flags, "d") == 0)
3112 /* delete an empty directory */
3113 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
3114 else if (STRCMP(flags, "rf") == 0)
3115 /* delete a directory recursively */
3116 rettv->vval.v_number = delete_recursive(name);
3117 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003118 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003119}
3120
3121/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02003122 * "deletebufline()" function
3123 */
3124 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02003125f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02003126{
3127 buf_T *buf;
3128 linenr_T first, last;
3129 linenr_T lnum;
3130 long count;
3131 int is_curbuf;
3132 buf_T *curbuf_save = NULL;
3133 win_T *curwin_save = NULL;
3134 tabpage_T *tp;
3135 win_T *wp;
3136
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003137 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003138 if (buf == NULL)
3139 {
3140 rettv->vval.v_number = 1; /* FAIL */
3141 return;
3142 }
3143 is_curbuf = buf == curbuf;
3144
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003145 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003146 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003147 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003148 else
3149 last = first;
3150
3151 if (buf->b_ml.ml_mfp == NULL || first < 1
3152 || first > buf->b_ml.ml_line_count || last < first)
3153 {
3154 rettv->vval.v_number = 1; /* FAIL */
3155 return;
3156 }
3157
3158 if (!is_curbuf)
3159 {
3160 curbuf_save = curbuf;
3161 curwin_save = curwin;
3162 curbuf = buf;
3163 find_win_for_curbuf();
3164 }
3165 if (last > curbuf->b_ml.ml_line_count)
3166 last = curbuf->b_ml.ml_line_count;
3167 count = last - first + 1;
3168
3169 // When coming here from Insert mode, sync undo, so that this can be
3170 // undone separately from what was previously inserted.
3171 if (u_sync_once == 2)
3172 {
3173 u_sync_once = 1; // notify that u_sync() was called
3174 u_sync(TRUE);
3175 }
3176
3177 if (u_save(first - 1, last + 1) == FAIL)
3178 {
3179 rettv->vval.v_number = 1; /* FAIL */
3180 return;
3181 }
3182
3183 for (lnum = first; lnum <= last; ++lnum)
3184 ml_delete(first, TRUE);
3185
3186 FOR_ALL_TAB_WINDOWS(tp, wp)
3187 if (wp->w_buffer == buf)
3188 {
3189 if (wp->w_cursor.lnum > last)
3190 wp->w_cursor.lnum -= count;
3191 else if (wp->w_cursor.lnum> first)
3192 wp->w_cursor.lnum = first;
3193 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3194 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3195 }
3196 check_cursor_col();
3197 deleted_lines_mark(first, count);
3198
3199 if (!is_curbuf)
3200 {
3201 curbuf = curbuf_save;
3202 curwin = curwin_save;
3203 }
3204}
3205
3206/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207 * "did_filetype()" function
3208 */
3209 static void
3210f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3211{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003212 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003213}
3214
3215/*
3216 * "diff_filler()" function
3217 */
3218 static void
3219f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3220{
3221#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003222 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003223#endif
3224}
3225
3226/*
3227 * "diff_hlID()" function
3228 */
3229 static void
3230f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3231{
3232#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003233 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003234 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003235 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003236 static int fnum = 0;
3237 static int change_start = 0;
3238 static int change_end = 0;
3239 static hlf_T hlID = (hlf_T)0;
3240 int filler_lines;
3241 int col;
3242
3243 if (lnum < 0) /* ignore type error in {lnum} arg */
3244 lnum = 0;
3245 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003246 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247 || fnum != curbuf->b_fnum)
3248 {
3249 /* New line, buffer, change: need to get the values. */
3250 filler_lines = diff_check(curwin, lnum);
3251 if (filler_lines < 0)
3252 {
3253 if (filler_lines == -1)
3254 {
3255 change_start = MAXCOL;
3256 change_end = -1;
3257 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3258 hlID = HLF_ADD; /* added line */
3259 else
3260 hlID = HLF_CHD; /* changed line */
3261 }
3262 else
3263 hlID = HLF_ADD; /* added line */
3264 }
3265 else
3266 hlID = (hlf_T)0;
3267 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003268 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003269 fnum = curbuf->b_fnum;
3270 }
3271
3272 if (hlID == HLF_CHD || hlID == HLF_TXD)
3273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003274 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003275 if (col >= change_start && col <= change_end)
3276 hlID = HLF_TXD; /* changed text */
3277 else
3278 hlID = HLF_CHD; /* changed line */
3279 }
3280 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3281#endif
3282}
3283
3284/*
3285 * "empty({expr})" function
3286 */
3287 static void
3288f_empty(typval_T *argvars, typval_T *rettv)
3289{
3290 int n = FALSE;
3291
3292 switch (argvars[0].v_type)
3293 {
3294 case VAR_STRING:
3295 case VAR_FUNC:
3296 n = argvars[0].vval.v_string == NULL
3297 || *argvars[0].vval.v_string == NUL;
3298 break;
3299 case VAR_PARTIAL:
3300 n = FALSE;
3301 break;
3302 case VAR_NUMBER:
3303 n = argvars[0].vval.v_number == 0;
3304 break;
3305 case VAR_FLOAT:
3306#ifdef FEAT_FLOAT
3307 n = argvars[0].vval.v_float == 0.0;
3308 break;
3309#endif
3310 case VAR_LIST:
3311 n = argvars[0].vval.v_list == NULL
3312 || argvars[0].vval.v_list->lv_first == NULL;
3313 break;
3314 case VAR_DICT:
3315 n = argvars[0].vval.v_dict == NULL
3316 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3317 break;
3318 case VAR_SPECIAL:
3319 n = argvars[0].vval.v_number != VVAL_TRUE;
3320 break;
3321
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003322 case VAR_BLOB:
3323 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003324 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3325 break;
3326
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003327 case VAR_JOB:
3328#ifdef FEAT_JOB_CHANNEL
3329 n = argvars[0].vval.v_job == NULL
3330 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3331 break;
3332#endif
3333 case VAR_CHANNEL:
3334#ifdef FEAT_JOB_CHANNEL
3335 n = argvars[0].vval.v_channel == NULL
3336 || !channel_is_open(argvars[0].vval.v_channel);
3337 break;
3338#endif
3339 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003340 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003341 n = TRUE;
3342 break;
3343 }
3344
3345 rettv->vval.v_number = n;
3346}
3347
3348/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003349 * "environ()" function
3350 */
3351 static void
3352f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3353{
3354#if !defined(AMIGA)
3355 int i = 0;
3356 char_u *entry, *value;
3357# ifdef MSWIN
3358 extern wchar_t **_wenviron;
3359# else
3360 extern char **environ;
3361# endif
3362
3363 if (rettv_dict_alloc(rettv) != OK)
3364 return;
3365
3366# ifdef MSWIN
3367 if (*_wenviron == NULL)
3368 return;
3369# else
3370 if (*environ == NULL)
3371 return;
3372# endif
3373
3374 for (i = 0; ; ++i)
3375 {
3376# ifdef MSWIN
3377 short_u *p;
3378
3379 if ((p = (short_u *)_wenviron[i]) == NULL)
3380 return;
3381 entry = utf16_to_enc(p, NULL);
3382# else
3383 if ((entry = (char_u *)environ[i]) == NULL)
3384 return;
3385 entry = vim_strsave(entry);
3386# endif
3387 if (entry == NULL) // out of memory
3388 return;
3389 if ((value = vim_strchr(entry, '=')) == NULL)
3390 {
3391 vim_free(entry);
3392 continue;
3393 }
3394 *value++ = NUL;
3395 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3396 vim_free(entry);
3397 }
3398#endif
3399}
3400
3401/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003402 * "escape({string}, {chars})" function
3403 */
3404 static void
3405f_escape(typval_T *argvars, typval_T *rettv)
3406{
3407 char_u buf[NUMBUFLEN];
3408
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003409 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3410 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003411 rettv->v_type = VAR_STRING;
3412}
3413
3414/*
3415 * "eval()" function
3416 */
3417 static void
3418f_eval(typval_T *argvars, typval_T *rettv)
3419{
3420 char_u *s, *p;
3421
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003422 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003423 if (s != NULL)
3424 s = skipwhite(s);
3425
3426 p = s;
3427 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3428 {
3429 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003430 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003431 need_clr_eos = FALSE;
3432 rettv->v_type = VAR_NUMBER;
3433 rettv->vval.v_number = 0;
3434 }
3435 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003436 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003437}
3438
3439/*
3440 * "eventhandler()" function
3441 */
3442 static void
3443f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3444{
3445 rettv->vval.v_number = vgetc_busy;
3446}
3447
3448/*
3449 * "executable()" function
3450 */
3451 static void
3452f_executable(typval_T *argvars, typval_T *rettv)
3453{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003454 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003455
3456 /* Check in $PATH and also check directly if there is a directory name. */
3457 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3458 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3459}
3460
3461static garray_T redir_execute_ga;
3462
3463/*
3464 * Append "value[value_len]" to the execute() output.
3465 */
3466 void
3467execute_redir_str(char_u *value, int value_len)
3468{
3469 int len;
3470
3471 if (value_len == -1)
3472 len = (int)STRLEN(value); /* Append the entire string */
3473 else
3474 len = value_len; /* Append only "value_len" characters */
3475 if (ga_grow(&redir_execute_ga, len) == OK)
3476 {
3477 mch_memmove((char *)redir_execute_ga.ga_data
3478 + redir_execute_ga.ga_len, value, len);
3479 redir_execute_ga.ga_len += len;
3480 }
3481}
3482
3483/*
3484 * Get next line from a list.
3485 * Called by do_cmdline() to get the next line.
3486 * Returns allocated string, or NULL for end of function.
3487 */
3488
3489 static char_u *
3490get_list_line(
3491 int c UNUSED,
3492 void *cookie,
3493 int indent UNUSED)
3494{
3495 listitem_T **p = (listitem_T **)cookie;
3496 listitem_T *item = *p;
3497 char_u buf[NUMBUFLEN];
3498 char_u *s;
3499
3500 if (item == NULL)
3501 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003502 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503 *p = item->li_next;
3504 return s == NULL ? NULL : vim_strsave(s);
3505}
3506
3507/*
3508 * "execute()" function
3509 */
3510 static void
3511f_execute(typval_T *argvars, typval_T *rettv)
3512{
3513 char_u *cmd = NULL;
3514 list_T *list = NULL;
3515 int save_msg_silent = msg_silent;
3516 int save_emsg_silent = emsg_silent;
3517 int save_emsg_noredir = emsg_noredir;
3518 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003519 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003521 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003522 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523
3524 rettv->vval.v_string = NULL;
3525 rettv->v_type = VAR_STRING;
3526
3527 if (argvars[0].v_type == VAR_LIST)
3528 {
3529 list = argvars[0].vval.v_list;
3530 if (list == NULL || list->lv_first == NULL)
3531 /* empty list, no commands, empty output */
3532 return;
3533 ++list->lv_refcount;
3534 }
3535 else
3536 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003537 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003538 if (cmd == NULL)
3539 return;
3540 }
3541
3542 if (argvars[1].v_type != VAR_UNKNOWN)
3543 {
3544 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003545 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546
3547 if (s == NULL)
3548 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003549 if (*s == NUL)
3550 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003551 if (STRNCMP(s, "silent", 6) == 0)
3552 ++msg_silent;
3553 if (STRCMP(s, "silent!") == 0)
3554 {
3555 emsg_silent = TRUE;
3556 emsg_noredir = TRUE;
3557 }
3558 }
3559 else
3560 ++msg_silent;
3561
3562 if (redir_execute)
3563 save_ga = redir_execute_ga;
3564 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3565 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003566 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003567 if (!echo_output)
3568 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569
3570 if (cmd != NULL)
3571 do_cmdline_cmd(cmd);
3572 else
3573 {
3574 listitem_T *item = list->lv_first;
3575
3576 do_cmdline(NULL, get_list_line, (void *)&item,
3577 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3578 --list->lv_refcount;
3579 }
3580
Bram Moolenaard297f352017-01-29 20:31:21 +01003581 /* Need to append a NUL to the result. */
3582 if (ga_grow(&redir_execute_ga, 1) == OK)
3583 {
3584 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3585 rettv->vval.v_string = redir_execute_ga.ga_data;
3586 }
3587 else
3588 {
3589 ga_clear(&redir_execute_ga);
3590 rettv->vval.v_string = NULL;
3591 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003592 msg_silent = save_msg_silent;
3593 emsg_silent = save_emsg_silent;
3594 emsg_noredir = save_emsg_noredir;
3595
3596 redir_execute = save_redir_execute;
3597 if (redir_execute)
3598 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003599 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003601 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003602 if (echo_output)
3603 // When not working silently: put it in column zero. A following
3604 // "echon" will overwrite the message, unavoidably.
3605 msg_col = 0;
3606 else
3607 // When working silently: Put it back where it was, since nothing
3608 // should have been written.
3609 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003610}
3611
3612/*
3613 * "exepath()" function
3614 */
3615 static void
3616f_exepath(typval_T *argvars, typval_T *rettv)
3617{
3618 char_u *p = NULL;
3619
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003620 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621 rettv->v_type = VAR_STRING;
3622 rettv->vval.v_string = p;
3623}
3624
3625/*
3626 * "exists()" function
3627 */
3628 static void
3629f_exists(typval_T *argvars, typval_T *rettv)
3630{
3631 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003632 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003634 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 if (*p == '$') /* environment variable */
3636 {
3637 /* first try "normal" environment variables (fast) */
3638 if (mch_getenv(p + 1) != NULL)
3639 n = TRUE;
3640 else
3641 {
3642 /* try expanding things like $VIM and ${HOME} */
3643 p = expand_env_save(p);
3644 if (p != NULL && *p != '$')
3645 n = TRUE;
3646 vim_free(p);
3647 }
3648 }
3649 else if (*p == '&' || *p == '+') /* option */
3650 {
3651 n = (get_option_tv(&p, NULL, TRUE) == OK);
3652 if (*skipwhite(p) != NUL)
3653 n = FALSE; /* trailing garbage */
3654 }
3655 else if (*p == '*') /* internal or user defined function */
3656 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003657 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658 }
3659 else if (*p == ':')
3660 {
3661 n = cmd_exists(p + 1);
3662 }
3663 else if (*p == '#')
3664 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003665 if (p[1] == '#')
3666 n = autocmd_supported(p + 2);
3667 else
3668 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003669 }
3670 else /* internal variable */
3671 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003672 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003673 }
3674
3675 rettv->vval.v_number = n;
3676}
3677
3678#ifdef FEAT_FLOAT
3679/*
3680 * "exp()" function
3681 */
3682 static void
3683f_exp(typval_T *argvars, typval_T *rettv)
3684{
3685 float_T f = 0.0;
3686
3687 rettv->v_type = VAR_FLOAT;
3688 if (get_float_arg(argvars, &f) == OK)
3689 rettv->vval.v_float = exp(f);
3690 else
3691 rettv->vval.v_float = 0.0;
3692}
3693#endif
3694
3695/*
3696 * "expand()" function
3697 */
3698 static void
3699f_expand(typval_T *argvars, typval_T *rettv)
3700{
3701 char_u *s;
3702 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003703 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003704 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3705 expand_T xpc;
3706 int error = FALSE;
3707 char_u *result;
3708
3709 rettv->v_type = VAR_STRING;
3710 if (argvars[1].v_type != VAR_UNKNOWN
3711 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003712 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003714 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003716 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003717 if (*s == '%' || *s == '#' || *s == '<')
3718 {
3719 ++emsg_off;
3720 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3721 --emsg_off;
3722 if (rettv->v_type == VAR_LIST)
3723 {
3724 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3725 list_append_string(rettv->vval.v_list, result, -1);
3726 else
3727 vim_free(result);
3728 }
3729 else
3730 rettv->vval.v_string = result;
3731 }
3732 else
3733 {
3734 /* When the optional second argument is non-zero, don't remove matches
3735 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3736 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003737 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003738 options |= WILD_KEEP_ALL;
3739 if (!error)
3740 {
3741 ExpandInit(&xpc);
3742 xpc.xp_context = EXPAND_FILES;
3743 if (p_wic)
3744 options += WILD_ICASE;
3745 if (rettv->v_type == VAR_STRING)
3746 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3747 options, WILD_ALL);
3748 else if (rettv_list_alloc(rettv) != FAIL)
3749 {
3750 int i;
3751
3752 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3753 for (i = 0; i < xpc.xp_numfiles; i++)
3754 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3755 ExpandCleanup(&xpc);
3756 }
3757 }
3758 else
3759 rettv->vval.v_string = NULL;
3760 }
3761}
3762
3763/*
3764 * "extend(list, list [, idx])" function
3765 * "extend(dict, dict [, action])" function
3766 */
3767 static void
3768f_extend(typval_T *argvars, typval_T *rettv)
3769{
3770 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3771
3772 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3773 {
3774 list_T *l1, *l2;
3775 listitem_T *item;
3776 long before;
3777 int error = FALSE;
3778
3779 l1 = argvars[0].vval.v_list;
3780 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003781 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003782 && l2 != NULL)
3783 {
3784 if (argvars[2].v_type != VAR_UNKNOWN)
3785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003786 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787 if (error)
3788 return; /* type error; errmsg already given */
3789
3790 if (before == l1->lv_len)
3791 item = NULL;
3792 else
3793 {
3794 item = list_find(l1, before);
3795 if (item == NULL)
3796 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003797 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003798 return;
3799 }
3800 }
3801 }
3802 else
3803 item = NULL;
3804 list_extend(l1, l2, item);
3805
3806 copy_tv(&argvars[0], rettv);
3807 }
3808 }
3809 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3810 {
3811 dict_T *d1, *d2;
3812 char_u *action;
3813 int i;
3814
3815 d1 = argvars[0].vval.v_dict;
3816 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003817 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003818 && d2 != NULL)
3819 {
3820 /* Check the third argument. */
3821 if (argvars[2].v_type != VAR_UNKNOWN)
3822 {
3823 static char *(av[]) = {"keep", "force", "error"};
3824
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003825 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826 if (action == NULL)
3827 return; /* type error; errmsg already given */
3828 for (i = 0; i < 3; ++i)
3829 if (STRCMP(action, av[i]) == 0)
3830 break;
3831 if (i == 3)
3832 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003833 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834 return;
3835 }
3836 }
3837 else
3838 action = (char_u *)"force";
3839
3840 dict_extend(d1, d2, action);
3841
3842 copy_tv(&argvars[0], rettv);
3843 }
3844 }
3845 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003846 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847}
3848
3849/*
3850 * "feedkeys()" function
3851 */
3852 static void
3853f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3854{
3855 int remap = TRUE;
3856 int insert = FALSE;
3857 char_u *keys, *flags;
3858 char_u nbuf[NUMBUFLEN];
3859 int typed = FALSE;
3860 int execute = FALSE;
3861 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003862 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003863 char_u *keys_esc;
3864
3865 /* This is not allowed in the sandbox. If the commands would still be
3866 * executed in the sandbox it would be OK, but it probably happens later,
3867 * when "sandbox" is no longer set. */
3868 if (check_secure())
3869 return;
3870
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003871 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003872
3873 if (argvars[1].v_type != VAR_UNKNOWN)
3874 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003875 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003876 for ( ; *flags != NUL; ++flags)
3877 {
3878 switch (*flags)
3879 {
3880 case 'n': remap = FALSE; break;
3881 case 'm': remap = TRUE; break;
3882 case 't': typed = TRUE; break;
3883 case 'i': insert = TRUE; break;
3884 case 'x': execute = TRUE; break;
3885 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003886 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003887 }
3888 }
3889 }
3890
3891 if (*keys != NUL || execute)
3892 {
3893 /* Need to escape K_SPECIAL and CSI before putting the string in the
3894 * typeahead buffer. */
3895 keys_esc = vim_strsave_escape_csi(keys);
3896 if (keys_esc != NULL)
3897 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003898 if (lowlevel)
3899 {
3900#ifdef USE_INPUT_BUF
3901 add_to_input_buf(keys, (int)STRLEN(keys));
3902#else
3903 emsg(_("E980: lowlevel input not supported"));
3904#endif
3905 }
3906 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003907 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003908 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003910 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003911#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003912 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003913#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003914 )
3915 typebuf_was_filled = TRUE;
3916 }
3917 vim_free(keys_esc);
3918
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003919 if (execute)
3920 {
3921 int save_msg_scroll = msg_scroll;
3922
3923 /* Avoid a 1 second delay when the keys start Insert mode. */
3924 msg_scroll = FALSE;
3925
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003926 if (!dangerous)
3927 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003928 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003929 if (!dangerous)
3930 --ex_normal_busy;
3931
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 msg_scroll |= save_msg_scroll;
3933 }
3934 }
3935 }
3936}
3937
3938/*
3939 * "filereadable()" function
3940 */
3941 static void
3942f_filereadable(typval_T *argvars, typval_T *rettv)
3943{
3944 int fd;
3945 char_u *p;
3946 int n;
3947
3948#ifndef O_NONBLOCK
3949# define O_NONBLOCK 0
3950#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003951 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003952 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3953 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3954 {
3955 n = TRUE;
3956 close(fd);
3957 }
3958 else
3959 n = FALSE;
3960
3961 rettv->vval.v_number = n;
3962}
3963
3964/*
3965 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3966 * rights to write into.
3967 */
3968 static void
3969f_filewritable(typval_T *argvars, typval_T *rettv)
3970{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003971 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003972}
3973
3974 static void
3975findfilendir(
3976 typval_T *argvars UNUSED,
3977 typval_T *rettv,
3978 int find_what UNUSED)
3979{
3980#ifdef FEAT_SEARCHPATH
3981 char_u *fname;
3982 char_u *fresult = NULL;
3983 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3984 char_u *p;
3985 char_u pathbuf[NUMBUFLEN];
3986 int count = 1;
3987 int first = TRUE;
3988 int error = FALSE;
3989#endif
3990
3991 rettv->vval.v_string = NULL;
3992 rettv->v_type = VAR_STRING;
3993
3994#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003995 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003996
3997 if (argvars[1].v_type != VAR_UNKNOWN)
3998 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003999 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000 if (p == NULL)
4001 error = TRUE;
4002 else
4003 {
4004 if (*p != NUL)
4005 path = p;
4006
4007 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004008 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004009 }
4010 }
4011
4012 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
4013 error = TRUE;
4014
4015 if (*fname != NUL && !error)
4016 {
4017 do
4018 {
4019 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
4020 vim_free(fresult);
4021 fresult = find_file_in_path_option(first ? fname : NULL,
4022 first ? (int)STRLEN(fname) : 0,
4023 0, first, path,
4024 find_what,
4025 curbuf->b_ffname,
4026 find_what == FINDFILE_DIR
4027 ? (char_u *)"" : curbuf->b_p_sua);
4028 first = FALSE;
4029
4030 if (fresult != NULL && rettv->v_type == VAR_LIST)
4031 list_append_string(rettv->vval.v_list, fresult, -1);
4032
4033 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
4034 }
4035
4036 if (rettv->v_type == VAR_STRING)
4037 rettv->vval.v_string = fresult;
4038#endif
4039}
4040
4041/*
4042 * "filter()" function
4043 */
4044 static void
4045f_filter(typval_T *argvars, typval_T *rettv)
4046{
4047 filter_map(argvars, rettv, FALSE);
4048}
4049
4050/*
4051 * "finddir({fname}[, {path}[, {count}]])" function
4052 */
4053 static void
4054f_finddir(typval_T *argvars, typval_T *rettv)
4055{
4056 findfilendir(argvars, rettv, FINDFILE_DIR);
4057}
4058
4059/*
4060 * "findfile({fname}[, {path}[, {count}]])" function
4061 */
4062 static void
4063f_findfile(typval_T *argvars, typval_T *rettv)
4064{
4065 findfilendir(argvars, rettv, FINDFILE_FILE);
4066}
4067
4068#ifdef FEAT_FLOAT
4069/*
4070 * "float2nr({float})" function
4071 */
4072 static void
4073f_float2nr(typval_T *argvars, typval_T *rettv)
4074{
4075 float_T f = 0.0;
4076
4077 if (get_float_arg(argvars, &f) == OK)
4078 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02004079 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01004080 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02004081 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01004082 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004083 else
4084 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004085 }
4086}
4087
4088/*
4089 * "floor({float})" function
4090 */
4091 static void
4092f_floor(typval_T *argvars, typval_T *rettv)
4093{
4094 float_T f = 0.0;
4095
4096 rettv->v_type = VAR_FLOAT;
4097 if (get_float_arg(argvars, &f) == OK)
4098 rettv->vval.v_float = floor(f);
4099 else
4100 rettv->vval.v_float = 0.0;
4101}
4102
4103/*
4104 * "fmod()" function
4105 */
4106 static void
4107f_fmod(typval_T *argvars, typval_T *rettv)
4108{
4109 float_T fx = 0.0, fy = 0.0;
4110
4111 rettv->v_type = VAR_FLOAT;
4112 if (get_float_arg(argvars, &fx) == OK
4113 && get_float_arg(&argvars[1], &fy) == OK)
4114 rettv->vval.v_float = fmod(fx, fy);
4115 else
4116 rettv->vval.v_float = 0.0;
4117}
4118#endif
4119
4120/*
4121 * "fnameescape({string})" function
4122 */
4123 static void
4124f_fnameescape(typval_T *argvars, typval_T *rettv)
4125{
4126 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004127 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004128 rettv->v_type = VAR_STRING;
4129}
4130
4131/*
4132 * "fnamemodify({fname}, {mods})" function
4133 */
4134 static void
4135f_fnamemodify(typval_T *argvars, typval_T *rettv)
4136{
4137 char_u *fname;
4138 char_u *mods;
4139 int usedlen = 0;
4140 int len;
4141 char_u *fbuf = NULL;
4142 char_u buf[NUMBUFLEN];
4143
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004144 fname = tv_get_string_chk(&argvars[0]);
4145 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 if (fname == NULL || mods == NULL)
4147 fname = NULL;
4148 else
4149 {
4150 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02004151 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004152 }
4153
4154 rettv->v_type = VAR_STRING;
4155 if (fname == NULL)
4156 rettv->vval.v_string = NULL;
4157 else
4158 rettv->vval.v_string = vim_strnsave(fname, len);
4159 vim_free(fbuf);
4160}
4161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004162/*
4163 * "foldclosed()" function
4164 */
4165 static void
4166foldclosed_both(
4167 typval_T *argvars UNUSED,
4168 typval_T *rettv,
4169 int end UNUSED)
4170{
4171#ifdef FEAT_FOLDING
4172 linenr_T lnum;
4173 linenr_T first, last;
4174
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004175 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004176 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4177 {
4178 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4179 {
4180 if (end)
4181 rettv->vval.v_number = (varnumber_T)last;
4182 else
4183 rettv->vval.v_number = (varnumber_T)first;
4184 return;
4185 }
4186 }
4187#endif
4188 rettv->vval.v_number = -1;
4189}
4190
4191/*
4192 * "foldclosed()" function
4193 */
4194 static void
4195f_foldclosed(typval_T *argvars, typval_T *rettv)
4196{
4197 foldclosed_both(argvars, rettv, FALSE);
4198}
4199
4200/*
4201 * "foldclosedend()" function
4202 */
4203 static void
4204f_foldclosedend(typval_T *argvars, typval_T *rettv)
4205{
4206 foldclosed_both(argvars, rettv, TRUE);
4207}
4208
4209/*
4210 * "foldlevel()" function
4211 */
4212 static void
4213f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4214{
4215#ifdef FEAT_FOLDING
4216 linenr_T lnum;
4217
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004218 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004219 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4220 rettv->vval.v_number = foldLevel(lnum);
4221#endif
4222}
4223
4224/*
4225 * "foldtext()" function
4226 */
4227 static void
4228f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4229{
4230#ifdef FEAT_FOLDING
4231 linenr_T foldstart;
4232 linenr_T foldend;
4233 char_u *dashes;
4234 linenr_T lnum;
4235 char_u *s;
4236 char_u *r;
4237 int len;
4238 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004239 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004240#endif
4241
4242 rettv->v_type = VAR_STRING;
4243 rettv->vval.v_string = NULL;
4244#ifdef FEAT_FOLDING
4245 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4246 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4247 dashes = get_vim_var_str(VV_FOLDDASHES);
4248 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4249 && dashes != NULL)
4250 {
4251 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004252 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004253 if (!linewhite(lnum))
4254 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255
4256 /* Find interesting text in this line. */
4257 s = skipwhite(ml_get(lnum));
4258 /* skip C comment-start */
4259 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4260 {
4261 s = skipwhite(s + 2);
4262 if (*skipwhite(s) == NUL
4263 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4264 {
4265 s = skipwhite(ml_get(lnum + 1));
4266 if (*s == '*')
4267 s = skipwhite(s + 1);
4268 }
4269 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004270 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004271 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004272 r = alloc((unsigned)(STRLEN(txt)
4273 + STRLEN(dashes) /* for %s */
4274 + 20 /* for %3ld */
4275 + STRLEN(s))); /* concatenated */
4276 if (r != NULL)
4277 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004278 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004279 len = (int)STRLEN(r);
4280 STRCAT(r, s);
4281 /* remove 'foldmarker' and 'commentstring' */
4282 foldtext_cleanup(r + len);
4283 rettv->vval.v_string = r;
4284 }
4285 }
4286#endif
4287}
4288
4289/*
4290 * "foldtextresult(lnum)" function
4291 */
4292 static void
4293f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4294{
4295#ifdef FEAT_FOLDING
4296 linenr_T lnum;
4297 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004298 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299 foldinfo_T foldinfo;
4300 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004301 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004302#endif
4303
4304 rettv->v_type = VAR_STRING;
4305 rettv->vval.v_string = NULL;
4306#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004307 if (entered)
4308 return; /* reject recursive use */
4309 entered = TRUE;
4310
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004311 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004312 /* treat illegal types and illegal string values for {lnum} the same */
4313 if (lnum < 0)
4314 lnum = 0;
4315 fold_count = foldedCount(curwin, lnum, &foldinfo);
4316 if (fold_count > 0)
4317 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004318 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4319 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004320 if (text == buf)
4321 text = vim_strsave(text);
4322 rettv->vval.v_string = text;
4323 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004324
4325 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004326#endif
4327}
4328
4329/*
4330 * "foreground()" function
4331 */
4332 static void
4333f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4334{
4335#ifdef FEAT_GUI
4336 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004337 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004338 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004339 return;
4340 }
4341#endif
4342#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004343 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004344#endif
4345}
4346
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004347 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004348common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004349{
4350 char_u *s;
4351 char_u *name;
4352 int use_string = FALSE;
4353 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004354 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004355
4356 if (argvars[0].v_type == VAR_FUNC)
4357 {
4358 /* function(MyFunc, [arg], dict) */
4359 s = argvars[0].vval.v_string;
4360 }
4361 else if (argvars[0].v_type == VAR_PARTIAL
4362 && argvars[0].vval.v_partial != NULL)
4363 {
4364 /* function(dict.MyFunc, [arg]) */
4365 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004366 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004367 }
4368 else
4369 {
4370 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004371 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004372 use_string = TRUE;
4373 }
4374
Bram Moolenaar843b8842016-08-21 14:36:15 +02004375 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004376 {
4377 name = s;
4378 trans_name = trans_function_name(&name, FALSE,
4379 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4380 if (*name != NUL)
4381 s = NULL;
4382 }
4383
Bram Moolenaar843b8842016-08-21 14:36:15 +02004384 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4385 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004386 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004387 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004388 else if (trans_name != NULL && (is_funcref
4389 ? find_func(trans_name) == NULL
4390 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004391 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004392 else
4393 {
4394 int dict_idx = 0;
4395 int arg_idx = 0;
4396 list_T *list = NULL;
4397
4398 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4399 {
4400 char sid_buf[25];
4401 int off = *s == 's' ? 2 : 5;
4402
4403 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4404 * also be called from another script. Using trans_function_name()
4405 * would also work, but some plugins depend on the name being
4406 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004407 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004408 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4409 if (name != NULL)
4410 {
4411 STRCPY(name, sid_buf);
4412 STRCAT(name, s + off);
4413 }
4414 }
4415 else
4416 name = vim_strsave(s);
4417
4418 if (argvars[1].v_type != VAR_UNKNOWN)
4419 {
4420 if (argvars[2].v_type != VAR_UNKNOWN)
4421 {
4422 /* function(name, [args], dict) */
4423 arg_idx = 1;
4424 dict_idx = 2;
4425 }
4426 else if (argvars[1].v_type == VAR_DICT)
4427 /* function(name, dict) */
4428 dict_idx = 1;
4429 else
4430 /* function(name, [args]) */
4431 arg_idx = 1;
4432 if (dict_idx > 0)
4433 {
4434 if (argvars[dict_idx].v_type != VAR_DICT)
4435 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004436 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004438 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004439 }
4440 if (argvars[dict_idx].vval.v_dict == NULL)
4441 dict_idx = 0;
4442 }
4443 if (arg_idx > 0)
4444 {
4445 if (argvars[arg_idx].v_type != VAR_LIST)
4446 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004447 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004449 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004450 }
4451 list = argvars[arg_idx].vval.v_list;
4452 if (list == NULL || list->lv_len == 0)
4453 arg_idx = 0;
4454 }
4455 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004456 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457 {
4458 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4459
4460 /* result is a VAR_PARTIAL */
4461 if (pt == NULL)
4462 vim_free(name);
4463 else
4464 {
4465 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4466 {
4467 listitem_T *li;
4468 int i = 0;
4469 int arg_len = 0;
4470 int lv_len = 0;
4471
4472 if (arg_pt != NULL)
4473 arg_len = arg_pt->pt_argc;
4474 if (list != NULL)
4475 lv_len = list->lv_len;
4476 pt->pt_argc = arg_len + lv_len;
4477 pt->pt_argv = (typval_T *)alloc(
4478 sizeof(typval_T) * pt->pt_argc);
4479 if (pt->pt_argv == NULL)
4480 {
4481 vim_free(pt);
4482 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004483 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004484 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004485 for (i = 0; i < arg_len; i++)
4486 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4487 if (lv_len > 0)
4488 for (li = list->lv_first; li != NULL;
4489 li = li->li_next)
4490 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004491 }
4492
4493 /* For "function(dict.func, [], dict)" and "func" is a partial
4494 * use "dict". That is backwards compatible. */
4495 if (dict_idx > 0)
4496 {
4497 /* The dict is bound explicitly, pt_auto is FALSE. */
4498 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4499 ++pt->pt_dict->dv_refcount;
4500 }
4501 else if (arg_pt != NULL)
4502 {
4503 /* If the dict was bound automatically the result is also
4504 * bound automatically. */
4505 pt->pt_dict = arg_pt->pt_dict;
4506 pt->pt_auto = arg_pt->pt_auto;
4507 if (pt->pt_dict != NULL)
4508 ++pt->pt_dict->dv_refcount;
4509 }
4510
4511 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004512 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4513 {
4514 pt->pt_func = arg_pt->pt_func;
4515 func_ptr_ref(pt->pt_func);
4516 vim_free(name);
4517 }
4518 else if (is_funcref)
4519 {
4520 pt->pt_func = find_func(trans_name);
4521 func_ptr_ref(pt->pt_func);
4522 vim_free(name);
4523 }
4524 else
4525 {
4526 pt->pt_name = name;
4527 func_ref(name);
4528 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004529 }
4530 rettv->v_type = VAR_PARTIAL;
4531 rettv->vval.v_partial = pt;
4532 }
4533 else
4534 {
4535 /* result is a VAR_FUNC */
4536 rettv->v_type = VAR_FUNC;
4537 rettv->vval.v_string = name;
4538 func_ref(name);
4539 }
4540 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004541theend:
4542 vim_free(trans_name);
4543}
4544
4545/*
4546 * "funcref()" function
4547 */
4548 static void
4549f_funcref(typval_T *argvars, typval_T *rettv)
4550{
4551 common_function(argvars, rettv, TRUE);
4552}
4553
4554/*
4555 * "function()" function
4556 */
4557 static void
4558f_function(typval_T *argvars, typval_T *rettv)
4559{
4560 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004561}
4562
4563/*
4564 * "garbagecollect()" function
4565 */
4566 static void
4567f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4568{
4569 /* This is postponed until we are back at the toplevel, because we may be
4570 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4571 want_garbage_collect = TRUE;
4572
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004573 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574 garbage_collect_at_exit = TRUE;
4575}
4576
4577/*
4578 * "get()" function
4579 */
4580 static void
4581f_get(typval_T *argvars, typval_T *rettv)
4582{
4583 listitem_T *li;
4584 list_T *l;
4585 dictitem_T *di;
4586 dict_T *d;
4587 typval_T *tv = NULL;
4588
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004589 if (argvars[0].v_type == VAR_BLOB)
4590 {
4591 int error = FALSE;
4592 int idx = tv_get_number_chk(&argvars[1], &error);
4593
4594 if (!error)
4595 {
4596 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004597 if (idx < 0)
4598 idx = blob_len(argvars[0].vval.v_blob) + idx;
4599 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4600 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004601 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004602 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004603 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004604 tv = rettv;
4605 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004606 }
4607 }
4608 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004609 {
4610 if ((l = argvars[0].vval.v_list) != NULL)
4611 {
4612 int error = FALSE;
4613
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004614 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004615 if (!error && li != NULL)
4616 tv = &li->li_tv;
4617 }
4618 }
4619 else if (argvars[0].v_type == VAR_DICT)
4620 {
4621 if ((d = argvars[0].vval.v_dict) != NULL)
4622 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004623 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004624 if (di != NULL)
4625 tv = &di->di_tv;
4626 }
4627 }
4628 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4629 {
4630 partial_T *pt;
4631 partial_T fref_pt;
4632
4633 if (argvars[0].v_type == VAR_PARTIAL)
4634 pt = argvars[0].vval.v_partial;
4635 else
4636 {
4637 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4638 fref_pt.pt_name = argvars[0].vval.v_string;
4639 pt = &fref_pt;
4640 }
4641
4642 if (pt != NULL)
4643 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004644 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004645 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004646
4647 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4648 {
4649 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004650 n = partial_name(pt);
4651 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004652 rettv->vval.v_string = NULL;
4653 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004654 {
4655 rettv->vval.v_string = vim_strsave(n);
4656 if (rettv->v_type == VAR_FUNC)
4657 func_ref(rettv->vval.v_string);
4658 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659 }
4660 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004661 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004662 else if (STRCMP(what, "args") == 0)
4663 {
4664 rettv->v_type = VAR_LIST;
4665 if (rettv_list_alloc(rettv) == OK)
4666 {
4667 int i;
4668
4669 for (i = 0; i < pt->pt_argc; ++i)
4670 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4671 }
4672 }
4673 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004674 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 return;
4676 }
4677 }
4678 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004679 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680
4681 if (tv == NULL)
4682 {
4683 if (argvars[2].v_type != VAR_UNKNOWN)
4684 copy_tv(&argvars[2], rettv);
4685 }
4686 else
4687 copy_tv(tv, rettv);
4688}
4689
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004690/*
4691 * Returns buffer options, variables and other attributes in a dictionary.
4692 */
4693 static dict_T *
4694get_buffer_info(buf_T *buf)
4695{
4696 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004697 tabpage_T *tp;
4698 win_T *wp;
4699 list_T *windows;
4700
4701 dict = dict_alloc();
4702 if (dict == NULL)
4703 return NULL;
4704
Bram Moolenaare0be1672018-07-08 16:50:37 +02004705 dict_add_number(dict, "bufnr", buf->b_fnum);
4706 dict_add_string(dict, "name", buf->b_ffname);
4707 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4708 : buflist_findlnum(buf));
4709 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4710 dict_add_number(dict, "listed", buf->b_p_bl);
4711 dict_add_number(dict, "changed", bufIsChanged(buf));
4712 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4713 dict_add_number(dict, "hidden",
4714 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004715
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004716 /* Get a reference to buffer variables */
4717 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004718
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004719 /* List of windows displaying this buffer */
4720 windows = list_alloc();
4721 if (windows != NULL)
4722 {
4723 FOR_ALL_TAB_WINDOWS(tp, wp)
4724 if (wp->w_buffer == buf)
4725 list_append_number(windows, (varnumber_T)wp->w_id);
4726 dict_add_list(dict, "windows", windows);
4727 }
4728
4729#ifdef FEAT_SIGNS
4730 if (buf->b_signlist != NULL)
4731 {
4732 /* List of signs placed in this buffer */
4733 list_T *signs = list_alloc();
4734 if (signs != NULL)
4735 {
4736 get_buffer_signs(buf, signs);
4737 dict_add_list(dict, "signs", signs);
4738 }
4739 }
4740#endif
4741
4742 return dict;
4743}
4744
4745/*
4746 * "getbufinfo()" function
4747 */
4748 static void
4749f_getbufinfo(typval_T *argvars, typval_T *rettv)
4750{
4751 buf_T *buf = NULL;
4752 buf_T *argbuf = NULL;
4753 dict_T *d;
4754 int filtered = FALSE;
4755 int sel_buflisted = FALSE;
4756 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004757 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004758
4759 if (rettv_list_alloc(rettv) != OK)
4760 return;
4761
4762 /* List of all the buffers or selected buffers */
4763 if (argvars[0].v_type == VAR_DICT)
4764 {
4765 dict_T *sel_d = argvars[0].vval.v_dict;
4766
4767 if (sel_d != NULL)
4768 {
4769 dictitem_T *di;
4770
4771 filtered = TRUE;
4772
4773 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004774 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004775 sel_buflisted = TRUE;
4776
4777 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004778 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004779 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004780
4781 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004782 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004783 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004784 }
4785 }
4786 else if (argvars[0].v_type != VAR_UNKNOWN)
4787 {
4788 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004789 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004790 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004791 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004792 --emsg_off;
4793 if (argbuf == NULL)
4794 return;
4795 }
4796
4797 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004798 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004799 {
4800 if (argbuf != NULL && argbuf != buf)
4801 continue;
4802 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004803 || (sel_buflisted && !buf->b_p_bl)
4804 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004805 continue;
4806
4807 d = get_buffer_info(buf);
4808 if (d != NULL)
4809 list_append_dict(rettv->vval.v_list, d);
4810 if (argbuf != NULL)
4811 return;
4812 }
4813}
4814
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815/*
4816 * Get line or list of lines from buffer "buf" into "rettv".
4817 * Return a range (from start to end) of lines in rettv from the specified
4818 * buffer.
4819 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4820 */
4821 static void
4822get_buffer_lines(
4823 buf_T *buf,
4824 linenr_T start,
4825 linenr_T end,
4826 int retlist,
4827 typval_T *rettv)
4828{
4829 char_u *p;
4830
4831 rettv->v_type = VAR_STRING;
4832 rettv->vval.v_string = NULL;
4833 if (retlist && rettv_list_alloc(rettv) == FAIL)
4834 return;
4835
4836 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4837 return;
4838
4839 if (!retlist)
4840 {
4841 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4842 p = ml_get_buf(buf, start, FALSE);
4843 else
4844 p = (char_u *)"";
4845 rettv->vval.v_string = vim_strsave(p);
4846 }
4847 else
4848 {
4849 if (end < start)
4850 return;
4851
4852 if (start < 1)
4853 start = 1;
4854 if (end > buf->b_ml.ml_line_count)
4855 end = buf->b_ml.ml_line_count;
4856 while (start <= end)
4857 if (list_append_string(rettv->vval.v_list,
4858 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4859 break;
4860 }
4861}
4862
4863/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004864 * "getbufline()" function
4865 */
4866 static void
4867f_getbufline(typval_T *argvars, typval_T *rettv)
4868{
4869 linenr_T lnum;
4870 linenr_T end;
4871 buf_T *buf;
4872
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004873 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004874 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004875 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004876 --emsg_off;
4877
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004878 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004879 if (argvars[2].v_type == VAR_UNKNOWN)
4880 end = lnum;
4881 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004882 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004883
4884 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4885}
4886
4887/*
4888 * "getbufvar()" function
4889 */
4890 static void
4891f_getbufvar(typval_T *argvars, typval_T *rettv)
4892{
4893 buf_T *buf;
4894 buf_T *save_curbuf;
4895 char_u *varname;
4896 dictitem_T *v;
4897 int done = FALSE;
4898
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004899 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4900 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004901 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004902 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903
4904 rettv->v_type = VAR_STRING;
4905 rettv->vval.v_string = NULL;
4906
4907 if (buf != NULL && varname != NULL)
4908 {
4909 /* set curbuf to be our buf, temporarily */
4910 save_curbuf = curbuf;
4911 curbuf = buf;
4912
Bram Moolenaar30567352016-08-27 21:25:44 +02004913 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004914 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004915 if (varname[1] == NUL)
4916 {
4917 /* get all buffer-local options in a dict */
4918 dict_T *opts = get_winbuf_options(TRUE);
4919
4920 if (opts != NULL)
4921 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004922 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004923 done = TRUE;
4924 }
4925 }
4926 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4927 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928 done = TRUE;
4929 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 else
4931 {
4932 /* Look up the variable. */
4933 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4934 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4935 'b', varname, FALSE);
4936 if (v != NULL)
4937 {
4938 copy_tv(&v->di_tv, rettv);
4939 done = TRUE;
4940 }
4941 }
4942
4943 /* restore previous notion of curbuf */
4944 curbuf = save_curbuf;
4945 }
4946
4947 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4948 /* use the default value */
4949 copy_tv(&argvars[2], rettv);
4950
4951 --emsg_off;
4952}
4953
4954/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004955 * "getchangelist()" function
4956 */
4957 static void
4958f_getchangelist(typval_T *argvars, typval_T *rettv)
4959{
4960#ifdef FEAT_JUMPLIST
4961 buf_T *buf;
4962 int i;
4963 list_T *l;
4964 dict_T *d;
4965#endif
4966
4967 if (rettv_list_alloc(rettv) != OK)
4968 return;
4969
4970#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004971 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004972 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004973 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004974 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004975 if (buf == NULL)
4976 return;
4977
4978 l = list_alloc();
4979 if (l == NULL)
4980 return;
4981
4982 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4983 return;
4984 /*
4985 * The current window change list index tracks only the position in the
4986 * current buffer change list. For other buffers, use the change list
4987 * length as the current index.
4988 */
4989 list_append_number(rettv->vval.v_list,
4990 (varnumber_T)((buf == curwin->w_buffer)
4991 ? curwin->w_changelistidx : buf->b_changelistlen));
4992
4993 for (i = 0; i < buf->b_changelistlen; ++i)
4994 {
4995 if (buf->b_changelist[i].lnum == 0)
4996 continue;
4997 if ((d = dict_alloc()) == NULL)
4998 return;
4999 if (list_append_dict(l, d) == FAIL)
5000 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005001 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
5002 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005003 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01005004 }
5005#endif
5006}
5007/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005008 * "getchar()" function
5009 */
5010 static void
5011f_getchar(typval_T *argvars, typval_T *rettv)
5012{
5013 varnumber_T n;
5014 int error = FALSE;
5015
Bram Moolenaar84d93902018-09-11 20:10:20 +02005016#ifdef MESSAGE_QUEUE
5017 // vpeekc() used to check for messages, but that caused problems, invoking
5018 // a callback where it was not expected. Some plugins use getchar(1) in a
5019 // loop to await a message, therefore make sure we check for messages here.
5020 parse_queued_messages();
5021#endif
5022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005023 /* Position the cursor. Needed after a message that ends in a space. */
5024 windgoto(msg_row, msg_col);
5025
5026 ++no_mapping;
5027 ++allow_keys;
5028 for (;;)
5029 {
5030 if (argvars[0].v_type == VAR_UNKNOWN)
5031 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01005032 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005033 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 /* getchar(1): only check if char avail */
5035 n = vpeekc_any();
5036 else if (error || vpeekc_any() == NUL)
5037 /* illegal argument or getchar(0) and no char avail: return zero */
5038 n = 0;
5039 else
5040 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01005041 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042
5043 if (n == K_IGNORE)
5044 continue;
5045 break;
5046 }
5047 --no_mapping;
5048 --allow_keys;
5049
5050 set_vim_var_nr(VV_MOUSE_WIN, 0);
5051 set_vim_var_nr(VV_MOUSE_WINID, 0);
5052 set_vim_var_nr(VV_MOUSE_LNUM, 0);
5053 set_vim_var_nr(VV_MOUSE_COL, 0);
5054
5055 rettv->vval.v_number = n;
5056 if (IS_SPECIAL(n) || mod_mask != 0)
5057 {
5058 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
5059 int i = 0;
5060
5061 /* Turn a special key into three bytes, plus modifier. */
5062 if (mod_mask != 0)
5063 {
5064 temp[i++] = K_SPECIAL;
5065 temp[i++] = KS_MODIFIER;
5066 temp[i++] = mod_mask;
5067 }
5068 if (IS_SPECIAL(n))
5069 {
5070 temp[i++] = K_SPECIAL;
5071 temp[i++] = K_SECOND(n);
5072 temp[i++] = K_THIRD(n);
5073 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074 else if (has_mbyte)
5075 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076 else
5077 temp[i++] = n;
5078 temp[i++] = NUL;
5079 rettv->v_type = VAR_STRING;
5080 rettv->vval.v_string = vim_strsave(temp);
5081
5082#ifdef FEAT_MOUSE
5083 if (is_mouse_key(n))
5084 {
5085 int row = mouse_row;
5086 int col = mouse_col;
5087 win_T *win;
5088 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005090 int winnr = 1;
5091
5092 if (row >= 0 && col >= 0)
5093 {
5094 /* Find the window at the mouse coordinates and compute the
5095 * text position. */
5096 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02005097 if (win == NULL)
5098 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005100 for (wp = firstwin; wp != win; wp = wp->w_next)
5101 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 set_vim_var_nr(VV_MOUSE_WIN, winnr);
5103 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
5104 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
5105 set_vim_var_nr(VV_MOUSE_COL, col + 1);
5106 }
5107 }
5108#endif
5109 }
5110}
5111
5112/*
5113 * "getcharmod()" function
5114 */
5115 static void
5116f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
5117{
5118 rettv->vval.v_number = mod_mask;
5119}
5120
5121/*
5122 * "getcharsearch()" function
5123 */
5124 static void
5125f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
5126{
5127 if (rettv_dict_alloc(rettv) != FAIL)
5128 {
5129 dict_T *dict = rettv->vval.v_dict;
5130
Bram Moolenaare0be1672018-07-08 16:50:37 +02005131 dict_add_string(dict, "char", last_csearch());
5132 dict_add_number(dict, "forward", last_csearch_forward());
5133 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005134 }
5135}
5136
5137/*
5138 * "getcmdline()" function
5139 */
5140 static void
5141f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
5142{
5143 rettv->v_type = VAR_STRING;
5144 rettv->vval.v_string = get_cmdline_str();
5145}
5146
5147/*
5148 * "getcmdpos()" function
5149 */
5150 static void
5151f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
5152{
5153 rettv->vval.v_number = get_cmdline_pos() + 1;
5154}
5155
5156/*
5157 * "getcmdtype()" function
5158 */
5159 static void
5160f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
5161{
5162 rettv->v_type = VAR_STRING;
5163 rettv->vval.v_string = alloc(2);
5164 if (rettv->vval.v_string != NULL)
5165 {
5166 rettv->vval.v_string[0] = get_cmdline_type();
5167 rettv->vval.v_string[1] = NUL;
5168 }
5169}
5170
5171/*
5172 * "getcmdwintype()" function
5173 */
5174 static void
5175f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5176{
5177 rettv->v_type = VAR_STRING;
5178 rettv->vval.v_string = NULL;
5179#ifdef FEAT_CMDWIN
5180 rettv->vval.v_string = alloc(2);
5181 if (rettv->vval.v_string != NULL)
5182 {
5183 rettv->vval.v_string[0] = cmdwin_type;
5184 rettv->vval.v_string[1] = NUL;
5185 }
5186#endif
5187}
5188
5189#if defined(FEAT_CMDL_COMPL)
5190/*
5191 * "getcompletion()" function
5192 */
5193 static void
5194f_getcompletion(typval_T *argvars, typval_T *rettv)
5195{
5196 char_u *pat;
5197 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005198 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005199 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5200 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005202 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005203 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005204
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005205 if (p_wic)
5206 options |= WILD_ICASE;
5207
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005208 /* For filtered results, 'wildignore' is used */
5209 if (!filtered)
5210 options |= WILD_KEEP_ALL;
5211
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005212 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005213 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005214 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005215 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005216 if (xpc.xp_context == EXPAND_NOTHING)
5217 {
5218 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005219 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005220 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005221 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005222 return;
5223 }
5224
5225# if defined(FEAT_MENU)
5226 if (xpc.xp_context == EXPAND_MENUS)
5227 {
5228 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5229 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5230 }
5231# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005232#ifdef FEAT_CSCOPE
5233 if (xpc.xp_context == EXPAND_CSCOPE)
5234 {
5235 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5236 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5237 }
5238#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005239#ifdef FEAT_SIGNS
5240 if (xpc.xp_context == EXPAND_SIGN)
5241 {
5242 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5243 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5244 }
5245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246
5247 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5248 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5249 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005250 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005251
5252 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5253
5254 for (i = 0; i < xpc.xp_numfiles; i++)
5255 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5256 }
5257 vim_free(pat);
5258 ExpandCleanup(&xpc);
5259}
5260#endif
5261
5262/*
5263 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005264 *
5265 * Return the current working directory of a window in a tab page.
5266 * First optional argument 'winnr' is the window number or -1 and the second
5267 * optional argument 'tabnr' is the tab page number.
5268 *
5269 * If no arguments are supplied, then return the directory of the current
5270 * window.
5271 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
5272 * the specified window.
5273 * If 'winnr' is 0 then return the directory of the current window.
5274 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
5275 * directory of the specified tab page. Otherwise return the directory of the
5276 * specified window in the specified tab page.
5277 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278 */
5279 static void
5280f_getcwd(typval_T *argvars, typval_T *rettv)
5281{
5282 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005283 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005284 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005285 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286
5287 rettv->v_type = VAR_STRING;
5288 rettv->vval.v_string = NULL;
5289
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005290 if (argvars[0].v_type == VAR_NUMBER
5291 && argvars[0].vval.v_number == -1
5292 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01005293 global = TRUE;
5294 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005295 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01005296
5297 if (wp != NULL && wp->w_localdir != NULL)
5298 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005299 else if (tp != NULL && tp->tp_localdir != NULL)
5300 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
5301 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005302 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005303 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005304 rettv->vval.v_string = vim_strsave(globaldir);
5305 else
5306 {
5307 cwd = alloc(MAXPATHL);
5308 if (cwd != NULL)
5309 {
5310 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5311 rettv->vval.v_string = vim_strsave(cwd);
5312 vim_free(cwd);
5313 }
5314 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005315 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005316#ifdef BACKSLASH_IN_FILENAME
5317 if (rettv->vval.v_string != NULL)
5318 slash_adjust(rettv->vval.v_string);
5319#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005320}
5321
5322/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02005323 * "getenv()" function
5324 */
5325 static void
5326f_getenv(typval_T *argvars, typval_T *rettv)
5327{
5328 int mustfree = FALSE;
5329 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
5330
5331 if (p == NULL)
5332 {
5333 rettv->v_type = VAR_SPECIAL;
5334 rettv->vval.v_number = VVAL_NULL;
5335 return;
5336 }
5337 if (!mustfree)
5338 p = vim_strsave(p);
5339 rettv->vval.v_string = p;
5340 rettv->v_type = VAR_STRING;
5341}
5342
5343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005344 * "getfontname()" function
5345 */
5346 static void
5347f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5348{
5349 rettv->v_type = VAR_STRING;
5350 rettv->vval.v_string = NULL;
5351#ifdef FEAT_GUI
5352 if (gui.in_use)
5353 {
5354 GuiFont font;
5355 char_u *name = NULL;
5356
5357 if (argvars[0].v_type == VAR_UNKNOWN)
5358 {
5359 /* Get the "Normal" font. Either the name saved by
5360 * hl_set_font_name() or from the font ID. */
5361 font = gui.norm_font;
5362 name = hl_get_font_name();
5363 }
5364 else
5365 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005366 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005367 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5368 return;
5369 font = gui_mch_get_font(name, FALSE);
5370 if (font == NOFONT)
5371 return; /* Invalid font name, return empty string. */
5372 }
5373 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5374 if (argvars[0].v_type != VAR_UNKNOWN)
5375 gui_mch_free_font(font);
5376 }
5377#endif
5378}
5379
5380/*
5381 * "getfperm({fname})" function
5382 */
5383 static void
5384f_getfperm(typval_T *argvars, typval_T *rettv)
5385{
5386 char_u *fname;
5387 stat_T st;
5388 char_u *perm = NULL;
5389 char_u flags[] = "rwx";
5390 int i;
5391
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005392 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005393
5394 rettv->v_type = VAR_STRING;
5395 if (mch_stat((char *)fname, &st) >= 0)
5396 {
5397 perm = vim_strsave((char_u *)"---------");
5398 if (perm != NULL)
5399 {
5400 for (i = 0; i < 9; i++)
5401 {
5402 if (st.st_mode & (1 << (8 - i)))
5403 perm[i] = flags[i % 3];
5404 }
5405 }
5406 }
5407 rettv->vval.v_string = perm;
5408}
5409
5410/*
5411 * "getfsize({fname})" function
5412 */
5413 static void
5414f_getfsize(typval_T *argvars, typval_T *rettv)
5415{
5416 char_u *fname;
5417 stat_T st;
5418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005419 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005420
5421 rettv->v_type = VAR_NUMBER;
5422
5423 if (mch_stat((char *)fname, &st) >= 0)
5424 {
5425 if (mch_isdir(fname))
5426 rettv->vval.v_number = 0;
5427 else
5428 {
5429 rettv->vval.v_number = (varnumber_T)st.st_size;
5430
5431 /* non-perfect check for overflow */
5432 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5433 rettv->vval.v_number = -2;
5434 }
5435 }
5436 else
5437 rettv->vval.v_number = -1;
5438}
5439
5440/*
5441 * "getftime({fname})" function
5442 */
5443 static void
5444f_getftime(typval_T *argvars, typval_T *rettv)
5445{
5446 char_u *fname;
5447 stat_T st;
5448
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005449 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450
5451 if (mch_stat((char *)fname, &st) >= 0)
5452 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5453 else
5454 rettv->vval.v_number = -1;
5455}
5456
5457/*
5458 * "getftype({fname})" function
5459 */
5460 static void
5461f_getftype(typval_T *argvars, typval_T *rettv)
5462{
5463 char_u *fname;
5464 stat_T st;
5465 char_u *type = NULL;
5466 char *t;
5467
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005468 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005469
5470 rettv->v_type = VAR_STRING;
5471 if (mch_lstat((char *)fname, &st) >= 0)
5472 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 if (S_ISREG(st.st_mode))
5474 t = "file";
5475 else if (S_ISDIR(st.st_mode))
5476 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005477 else if (S_ISLNK(st.st_mode))
5478 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 else if (S_ISBLK(st.st_mode))
5480 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005481 else if (S_ISCHR(st.st_mode))
5482 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005483 else if (S_ISFIFO(st.st_mode))
5484 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005485 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005486 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005487 else
5488 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 type = vim_strsave((char_u *)t);
5490 }
5491 rettv->vval.v_string = type;
5492}
5493
5494/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005495 * "getjumplist()" function
5496 */
5497 static void
5498f_getjumplist(typval_T *argvars, typval_T *rettv)
5499{
5500#ifdef FEAT_JUMPLIST
5501 win_T *wp;
5502 int i;
5503 list_T *l;
5504 dict_T *d;
5505#endif
5506
5507 if (rettv_list_alloc(rettv) != OK)
5508 return;
5509
5510#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005511 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005512 if (wp == NULL)
5513 return;
5514
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005515 cleanup_jumplist(wp, TRUE);
5516
Bram Moolenaar4f505882018-02-10 21:06:32 +01005517 l = list_alloc();
5518 if (l == NULL)
5519 return;
5520
5521 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5522 return;
5523 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5524
5525 for (i = 0; i < wp->w_jumplistlen; ++i)
5526 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005527 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5528 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005529 if ((d = dict_alloc()) == NULL)
5530 return;
5531 if (list_append_dict(l, d) == FAIL)
5532 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005533 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5534 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005535 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005536 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005537 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005538 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005539 }
5540#endif
5541}
5542
5543/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544 * "getline(lnum, [end])" function
5545 */
5546 static void
5547f_getline(typval_T *argvars, typval_T *rettv)
5548{
5549 linenr_T lnum;
5550 linenr_T end;
5551 int retlist;
5552
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005553 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 if (argvars[1].v_type == VAR_UNKNOWN)
5555 {
5556 end = 0;
5557 retlist = FALSE;
5558 }
5559 else
5560 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005561 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005562 retlist = TRUE;
5563 }
5564
5565 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5566}
5567
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005568#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005569 static void
5570get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5571{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005572 if (what_arg->v_type == VAR_UNKNOWN)
5573 {
5574 if (rettv_list_alloc(rettv) == OK)
5575 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005576 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005577 }
5578 else
5579 {
5580 if (rettv_dict_alloc(rettv) == OK)
5581 if (is_qf || (wp != NULL))
5582 {
5583 if (what_arg->v_type == VAR_DICT)
5584 {
5585 dict_T *d = what_arg->vval.v_dict;
5586
5587 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005588 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005589 }
5590 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005591 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005592 }
5593 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005594}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005595#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005596
5597/*
5598 * "getloclist()" function
5599 */
5600 static void
5601f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5602{
5603#ifdef FEAT_QUICKFIX
5604 win_T *wp;
5605
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005606 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005607 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5608#endif
5609}
5610
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005611/*
5612 * "getmatches()" function
5613 */
5614 static void
5615f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5616{
5617#ifdef FEAT_SEARCH_EXTRA
5618 dict_T *dict;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005619 matchitem_T *cur;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620 int i;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005621 win_T *win = get_optional_window(argvars, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622
Bram Moolenaaraff74912019-03-30 18:11:49 +01005623 if (rettv_list_alloc(rettv) == FAIL || win == NULL)
5624 return;
5625
5626 cur = win->w_match_head;
5627 while (cur != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005628 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005629 dict = dict_alloc();
5630 if (dict == NULL)
5631 return;
5632 if (cur->match.regprog == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005633 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005634 /* match added with matchaddpos() */
5635 for (i = 0; i < MAXPOSMATCH; ++i)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005636 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005637 llpos_T *llpos;
Bram Moolenaar54315892019-04-26 22:33:49 +02005638 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaaraff74912019-03-30 18:11:49 +01005639 list_T *l;
5640
5641 llpos = &cur->pos.pos[i];
5642 if (llpos->lnum == 0)
5643 break;
5644 l = list_alloc();
5645 if (l == NULL)
5646 break;
5647 list_append_number(l, (varnumber_T)llpos->lnum);
5648 if (llpos->col > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005649 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005650 list_append_number(l, (varnumber_T)llpos->col);
5651 list_append_number(l, (varnumber_T)llpos->len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005652 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005653 sprintf(buf, "pos%d", i + 1);
5654 dict_add_list(dict, buf, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005656 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005657 else
5658 {
5659 dict_add_string(dict, "pattern", cur->pattern);
5660 }
5661 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5662 dict_add_number(dict, "priority", (long)cur->priority);
5663 dict_add_number(dict, "id", (long)cur->id);
5664# if defined(FEAT_CONCEAL)
5665 if (cur->conceal_char)
5666 {
5667 char_u buf[MB_MAXBYTES + 1];
5668
5669 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5670 dict_add_string(dict, "conceal", (char_u *)&buf);
5671 }
5672# endif
5673 list_append_dict(rettv->vval.v_list, dict);
5674 cur = cur->next;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005675 }
5676#endif
5677}
5678
5679/*
5680 * "getpid()" function
5681 */
5682 static void
5683f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5684{
5685 rettv->vval.v_number = mch_get_pid();
5686}
5687
5688 static void
5689getpos_both(
5690 typval_T *argvars,
5691 typval_T *rettv,
5692 int getcurpos)
5693{
5694 pos_T *fp;
5695 list_T *l;
5696 int fnum = -1;
5697
5698 if (rettv_list_alloc(rettv) == OK)
5699 {
5700 l = rettv->vval.v_list;
5701 if (getcurpos)
5702 fp = &curwin->w_cursor;
5703 else
5704 fp = var2fpos(&argvars[0], TRUE, &fnum);
5705 if (fnum != -1)
5706 list_append_number(l, (varnumber_T)fnum);
5707 else
5708 list_append_number(l, (varnumber_T)0);
5709 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5710 : (varnumber_T)0);
5711 list_append_number(l, (fp != NULL)
5712 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5713 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005714 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005715 (varnumber_T)0);
5716 if (getcurpos)
5717 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005718 int save_set_curswant = curwin->w_set_curswant;
5719 colnr_T save_curswant = curwin->w_curswant;
5720 colnr_T save_virtcol = curwin->w_virtcol;
5721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005722 update_curswant();
5723 list_append_number(l, curwin->w_curswant == MAXCOL ?
5724 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005725
5726 // Do not change "curswant", as it is unexpected that a get
5727 // function has a side effect.
5728 if (save_set_curswant)
5729 {
5730 curwin->w_set_curswant = save_set_curswant;
5731 curwin->w_curswant = save_curswant;
5732 curwin->w_virtcol = save_virtcol;
5733 curwin->w_valid &= ~VALID_VIRTCOL;
5734 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005735 }
5736 }
5737 else
5738 rettv->vval.v_number = FALSE;
5739}
5740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005741/*
5742 * "getcurpos()" function
5743 */
5744 static void
5745f_getcurpos(typval_T *argvars, typval_T *rettv)
5746{
5747 getpos_both(argvars, rettv, TRUE);
5748}
5749
5750/*
5751 * "getpos(string)" function
5752 */
5753 static void
5754f_getpos(typval_T *argvars, typval_T *rettv)
5755{
5756 getpos_both(argvars, rettv, FALSE);
5757}
5758
5759/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005760 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005761 */
5762 static void
5763f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5764{
5765#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005766 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005767#endif
5768}
5769
5770/*
5771 * "getreg()" function
5772 */
5773 static void
5774f_getreg(typval_T *argvars, typval_T *rettv)
5775{
5776 char_u *strregname;
5777 int regname;
5778 int arg2 = FALSE;
5779 int return_list = FALSE;
5780 int error = FALSE;
5781
5782 if (argvars[0].v_type != VAR_UNKNOWN)
5783 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005784 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005785 error = strregname == NULL;
5786 if (argvars[1].v_type != VAR_UNKNOWN)
5787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005788 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005790 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 }
5792 }
5793 else
5794 strregname = get_vim_var_str(VV_REG);
5795
5796 if (error)
5797 return;
5798
5799 regname = (strregname == NULL ? '"' : *strregname);
5800 if (regname == 0)
5801 regname = '"';
5802
5803 if (return_list)
5804 {
5805 rettv->v_type = VAR_LIST;
5806 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5807 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5808 if (rettv->vval.v_list == NULL)
5809 (void)rettv_list_alloc(rettv);
5810 else
5811 ++rettv->vval.v_list->lv_refcount;
5812 }
5813 else
5814 {
5815 rettv->v_type = VAR_STRING;
5816 rettv->vval.v_string = get_reg_contents(regname,
5817 arg2 ? GREG_EXPR_SRC : 0);
5818 }
5819}
5820
5821/*
5822 * "getregtype()" function
5823 */
5824 static void
5825f_getregtype(typval_T *argvars, typval_T *rettv)
5826{
5827 char_u *strregname;
5828 int regname;
5829 char_u buf[NUMBUFLEN + 2];
5830 long reglen = 0;
5831
5832 if (argvars[0].v_type != VAR_UNKNOWN)
5833 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005834 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005835 if (strregname == NULL) /* type error; errmsg already given */
5836 {
5837 rettv->v_type = VAR_STRING;
5838 rettv->vval.v_string = NULL;
5839 return;
5840 }
5841 }
5842 else
5843 /* Default to v:register */
5844 strregname = get_vim_var_str(VV_REG);
5845
5846 regname = (strregname == NULL ? '"' : *strregname);
5847 if (regname == 0)
5848 regname = '"';
5849
5850 buf[0] = NUL;
5851 buf[1] = NUL;
5852 switch (get_reg_type(regname, &reglen))
5853 {
5854 case MLINE: buf[0] = 'V'; break;
5855 case MCHAR: buf[0] = 'v'; break;
5856 case MBLOCK:
5857 buf[0] = Ctrl_V;
5858 sprintf((char *)buf + 1, "%ld", reglen + 1);
5859 break;
5860 }
5861 rettv->v_type = VAR_STRING;
5862 rettv->vval.v_string = vim_strsave(buf);
5863}
5864
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005865/*
5866 * Returns information (variables, options, etc.) about a tab page
5867 * as a dictionary.
5868 */
5869 static dict_T *
5870get_tabpage_info(tabpage_T *tp, int tp_idx)
5871{
5872 win_T *wp;
5873 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005874 list_T *l;
5875
5876 dict = dict_alloc();
5877 if (dict == NULL)
5878 return NULL;
5879
Bram Moolenaare0be1672018-07-08 16:50:37 +02005880 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005881
5882 l = list_alloc();
5883 if (l != NULL)
5884 {
5885 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5886 wp; wp = wp->w_next)
5887 list_append_number(l, (varnumber_T)wp->w_id);
5888 dict_add_list(dict, "windows", l);
5889 }
5890
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005891 /* Make a reference to tabpage variables */
5892 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005893
5894 return dict;
5895}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005896
5897/*
5898 * "gettabinfo()" function
5899 */
5900 static void
5901f_gettabinfo(typval_T *argvars, typval_T *rettv)
5902{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005903 tabpage_T *tp, *tparg = NULL;
5904 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005905 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005906
5907 if (rettv_list_alloc(rettv) != OK)
5908 return;
5909
5910 if (argvars[0].v_type != VAR_UNKNOWN)
5911 {
5912 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005913 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005914 if (tparg == NULL)
5915 return;
5916 }
5917
5918 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005919 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005920 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005921 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005922 if (tparg != NULL && tp != tparg)
5923 continue;
5924 d = get_tabpage_info(tp, tpnr);
5925 if (d != NULL)
5926 list_append_dict(rettv->vval.v_list, d);
5927 if (tparg != NULL)
5928 return;
5929 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005930}
5931
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005932/*
5933 * "gettabvar()" function
5934 */
5935 static void
5936f_gettabvar(typval_T *argvars, typval_T *rettv)
5937{
5938 win_T *oldcurwin;
5939 tabpage_T *tp, *oldtabpage;
5940 dictitem_T *v;
5941 char_u *varname;
5942 int done = FALSE;
5943
5944 rettv->v_type = VAR_STRING;
5945 rettv->vval.v_string = NULL;
5946
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005947 varname = tv_get_string_chk(&argvars[1]);
5948 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 if (tp != NULL && varname != NULL)
5950 {
5951 /* Set tp to be our tabpage, temporarily. Also set the window to the
5952 * first window in the tabpage, otherwise the window is not valid. */
5953 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005954 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5955 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005956 {
5957 /* look up the variable */
5958 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5959 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5960 if (v != NULL)
5961 {
5962 copy_tv(&v->di_tv, rettv);
5963 done = TRUE;
5964 }
5965 }
5966
5967 /* restore previous notion of curwin */
5968 restore_win(oldcurwin, oldtabpage, TRUE);
5969 }
5970
5971 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5972 copy_tv(&argvars[2], rettv);
5973}
5974
5975/*
5976 * "gettabwinvar()" function
5977 */
5978 static void
5979f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5980{
5981 getwinvar(argvars, rettv, 1);
5982}
5983
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005984/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005985 * "gettagstack()" function
5986 */
5987 static void
5988f_gettagstack(typval_T *argvars, typval_T *rettv)
5989{
5990 win_T *wp = curwin; // default is current window
5991
5992 if (rettv_dict_alloc(rettv) != OK)
5993 return;
5994
5995 if (argvars[0].v_type != VAR_UNKNOWN)
5996 {
5997 wp = find_win_by_nr_or_id(&argvars[0]);
5998 if (wp == NULL)
5999 return;
6000 }
6001
6002 get_tagstack(wp, rettv->vval.v_dict);
6003}
6004
6005/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006006 * Returns information about a window as a dictionary.
6007 */
6008 static dict_T *
6009get_win_info(win_T *wp, short tpnr, short winnr)
6010{
6011 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006012
6013 dict = dict_alloc();
6014 if (dict == NULL)
6015 return NULL;
6016
Bram Moolenaare0be1672018-07-08 16:50:37 +02006017 dict_add_number(dict, "tabnr", tpnr);
6018 dict_add_number(dict, "winnr", winnr);
6019 dict_add_number(dict, "winid", wp->w_id);
6020 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02006021 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01006022 dict_add_number(dict, "topline", wp->w_topline);
6023 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02006024#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02006025 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02006026#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02006027 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02006028 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02006029 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006030
Bram Moolenaar69905d12017-08-13 18:14:47 +02006031#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02006032 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02006033#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02006034#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02006035 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
6036 dict_add_number(dict, "loclist",
6037 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02006038#endif
6039
Bram Moolenaar30567352016-08-27 21:25:44 +02006040 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02006041 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006042
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006043 return dict;
6044}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006045
6046/*
6047 * "getwininfo()" function
6048 */
6049 static void
6050f_getwininfo(typval_T *argvars, typval_T *rettv)
6051{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006052 tabpage_T *tp;
6053 win_T *wp = NULL, *wparg = NULL;
6054 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02006055 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006056
6057 if (rettv_list_alloc(rettv) != OK)
6058 return;
6059
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006060 if (argvars[0].v_type != VAR_UNKNOWN)
6061 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01006062 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006063 if (wparg == NULL)
6064 return;
6065 }
6066
6067 /* Collect information about either all the windows across all the tab
6068 * pages or one particular window.
6069 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02006070 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006071 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02006072 tabnr++;
6073 winnr = 0;
6074 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006075 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02006076 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006077 if (wparg != NULL && wp != wparg)
6078 continue;
6079 d = get_win_info(wp, tabnr, winnr);
6080 if (d != NULL)
6081 list_append_dict(rettv->vval.v_list, d);
6082 if (wparg != NULL)
6083 /* found information about a specific window */
6084 return;
6085 }
6086 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02006087}
6088
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090 * "win_findbuf()" function
6091 */
6092 static void
6093f_win_findbuf(typval_T *argvars, typval_T *rettv)
6094{
6095 if (rettv_list_alloc(rettv) != FAIL)
6096 win_findbuf(argvars, rettv->vval.v_list);
6097}
6098
6099/*
6100 * "win_getid()" function
6101 */
6102 static void
6103f_win_getid(typval_T *argvars, typval_T *rettv)
6104{
6105 rettv->vval.v_number = win_getid(argvars);
6106}
6107
6108/*
6109 * "win_gotoid()" function
6110 */
6111 static void
6112f_win_gotoid(typval_T *argvars, typval_T *rettv)
6113{
6114 rettv->vval.v_number = win_gotoid(argvars);
6115}
6116
6117/*
6118 * "win_id2tabwin()" function
6119 */
6120 static void
6121f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
6122{
6123 if (rettv_list_alloc(rettv) != FAIL)
6124 win_id2tabwin(argvars, rettv->vval.v_list);
6125}
6126
6127/*
6128 * "win_id2win()" function
6129 */
6130 static void
6131f_win_id2win(typval_T *argvars, typval_T *rettv)
6132{
6133 rettv->vval.v_number = win_id2win(argvars);
6134}
6135
6136/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01006137 * "win_screenpos()" function
6138 */
6139 static void
6140f_win_screenpos(typval_T *argvars, typval_T *rettv)
6141{
6142 win_T *wp;
6143
6144 if (rettv_list_alloc(rettv) == FAIL)
6145 return;
6146
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02006147 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01006148 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
6149 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
6150}
6151
6152/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006153 * "getwinpos({timeout})" function
6154 */
6155 static void
6156f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
6157{
6158 int x = -1;
6159 int y = -1;
6160
6161 if (rettv_list_alloc(rettv) == FAIL)
6162 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006163#if defined(FEAT_GUI) \
6164 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6165 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006166 {
6167 varnumber_T timeout = 100;
6168
6169 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006170 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006171
6172 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006173 }
6174#endif
6175 list_append_number(rettv->vval.v_list, (varnumber_T)x);
6176 list_append_number(rettv->vval.v_list, (varnumber_T)y);
6177}
6178
6179
6180/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006181 * "getwinposx()" function
6182 */
6183 static void
6184f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
6185{
6186 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006187#if defined(FEAT_GUI) \
6188 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6189 || defined(MSWIN)
6190
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006191 {
6192 int x, y;
6193
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006194 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006195 rettv->vval.v_number = x;
6196 }
6197#endif
6198}
6199
6200/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006201 * "getwinposy()" function
6202 */
6203 static void
6204f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6205{
6206 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006207#if defined(FEAT_GUI) \
6208 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6209 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006210 {
6211 int x, y;
6212
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006213 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006214 rettv->vval.v_number = y;
6215 }
6216#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006217}
6218
6219/*
6220 * "getwinvar()" function
6221 */
6222 static void
6223f_getwinvar(typval_T *argvars, typval_T *rettv)
6224{
6225 getwinvar(argvars, rettv, 0);
6226}
6227
6228/*
6229 * "glob()" function
6230 */
6231 static void
6232f_glob(typval_T *argvars, typval_T *rettv)
6233{
6234 int options = WILD_SILENT|WILD_USE_NL;
6235 expand_T xpc;
6236 int error = FALSE;
6237
6238 /* When the optional second argument is non-zero, don't remove matches
6239 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6240 rettv->v_type = VAR_STRING;
6241 if (argvars[1].v_type != VAR_UNKNOWN)
6242 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006243 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006244 options |= WILD_KEEP_ALL;
6245 if (argvars[2].v_type != VAR_UNKNOWN)
6246 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006247 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006248 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006249 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006250 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006251 options |= WILD_ALLLINKS;
6252 }
6253 }
6254 if (!error)
6255 {
6256 ExpandInit(&xpc);
6257 xpc.xp_context = EXPAND_FILES;
6258 if (p_wic)
6259 options += WILD_ICASE;
6260 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006261 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006262 NULL, options, WILD_ALL);
6263 else if (rettv_list_alloc(rettv) != FAIL)
6264 {
6265 int i;
6266
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006267 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268 NULL, options, WILD_ALL_KEEP);
6269 for (i = 0; i < xpc.xp_numfiles; i++)
6270 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6271
6272 ExpandCleanup(&xpc);
6273 }
6274 }
6275 else
6276 rettv->vval.v_string = NULL;
6277}
6278
6279/*
6280 * "globpath()" function
6281 */
6282 static void
6283f_globpath(typval_T *argvars, typval_T *rettv)
6284{
6285 int flags = 0;
6286 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006287 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288 int error = FALSE;
6289 garray_T ga;
6290 int i;
6291
6292 /* When the optional second argument is non-zero, don't remove matches
6293 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6294 rettv->v_type = VAR_STRING;
6295 if (argvars[2].v_type != VAR_UNKNOWN)
6296 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006297 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298 flags |= WILD_KEEP_ALL;
6299 if (argvars[3].v_type != VAR_UNKNOWN)
6300 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006301 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006302 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006303 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006304 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006305 flags |= WILD_ALLLINKS;
6306 }
6307 }
6308 if (file != NULL && !error)
6309 {
6310 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006311 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006312 if (rettv->v_type == VAR_STRING)
6313 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6314 else if (rettv_list_alloc(rettv) != FAIL)
6315 for (i = 0; i < ga.ga_len; ++i)
6316 list_append_string(rettv->vval.v_list,
6317 ((char_u **)(ga.ga_data))[i], -1);
6318 ga_clear_strings(&ga);
6319 }
6320 else
6321 rettv->vval.v_string = NULL;
6322}
6323
6324/*
6325 * "glob2regpat()" function
6326 */
6327 static void
6328f_glob2regpat(typval_T *argvars, typval_T *rettv)
6329{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006330 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006331
6332 rettv->v_type = VAR_STRING;
6333 rettv->vval.v_string = (pat == NULL)
6334 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6335}
6336
6337/* for VIM_VERSION_ defines */
6338#include "version.h"
6339
6340/*
6341 * "has()" function
6342 */
6343 static void
6344f_has(typval_T *argvars, typval_T *rettv)
6345{
6346 int i;
6347 char_u *name;
6348 int n = FALSE;
6349 static char *(has_list[]) =
6350 {
6351#ifdef AMIGA
6352 "amiga",
6353# ifdef FEAT_ARP
6354 "arp",
6355# endif
6356#endif
6357#ifdef __BEOS__
6358 "beos",
6359#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006360#if defined(BSD) && !defined(MACOS_X)
6361 "bsd",
6362#endif
6363#ifdef hpux
6364 "hpux",
6365#endif
6366#ifdef __linux__
6367 "linux",
6368#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006369#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006370 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6371 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006372# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006373 "macunix", /* Mac OS X, with the darwin feature */
6374 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006375# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376#endif
6377#ifdef __QNX__
6378 "qnx",
6379#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006380#ifdef SUN_SYSTEM
6381 "sun",
6382#else
6383 "moon",
6384#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385#ifdef UNIX
6386 "unix",
6387#endif
6388#ifdef VMS
6389 "vms",
6390#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006391#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392 "win32",
6393#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006394#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006395 "win32unix",
6396#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006397#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006398 "win64",
6399#endif
6400#ifdef EBCDIC
6401 "ebcdic",
6402#endif
6403#ifndef CASE_INSENSITIVE_FILENAME
6404 "fname_case",
6405#endif
6406#ifdef HAVE_ACL
6407 "acl",
6408#endif
6409#ifdef FEAT_ARABIC
6410 "arabic",
6411#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006413#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006414 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006415#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006416#ifdef FEAT_AUTOSERVERNAME
6417 "autoservername",
6418#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006419#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006421# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422 "balloon_multiline",
6423# endif
6424#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006425#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006426 "balloon_eval_term",
6427#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006428#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6429 "builtin_terms",
6430# ifdef ALL_BUILTIN_TCAPS
6431 "all_builtin_terms",
6432# endif
6433#endif
6434#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006435 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436 || defined(FEAT_GUI_MOTIF))
6437 "browsefilter",
6438#endif
6439#ifdef FEAT_BYTEOFF
6440 "byte_offset",
6441#endif
6442#ifdef FEAT_JOB_CHANNEL
6443 "channel",
6444#endif
6445#ifdef FEAT_CINDENT
6446 "cindent",
6447#endif
6448#ifdef FEAT_CLIENTSERVER
6449 "clientserver",
6450#endif
6451#ifdef FEAT_CLIPBOARD
6452 "clipboard",
6453#endif
6454#ifdef FEAT_CMDL_COMPL
6455 "cmdline_compl",
6456#endif
6457#ifdef FEAT_CMDHIST
6458 "cmdline_hist",
6459#endif
6460#ifdef FEAT_COMMENTS
6461 "comments",
6462#endif
6463#ifdef FEAT_CONCEAL
6464 "conceal",
6465#endif
6466#ifdef FEAT_CRYPT
6467 "cryptv",
6468 "crypt-blowfish",
6469 "crypt-blowfish2",
6470#endif
6471#ifdef FEAT_CSCOPE
6472 "cscope",
6473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475#ifdef CURSOR_SHAPE
6476 "cursorshape",
6477#endif
6478#ifdef DEBUG
6479 "debug",
6480#endif
6481#ifdef FEAT_CON_DIALOG
6482 "dialog_con",
6483#endif
6484#ifdef FEAT_GUI_DIALOG
6485 "dialog_gui",
6486#endif
6487#ifdef FEAT_DIFF
6488 "diff",
6489#endif
6490#ifdef FEAT_DIGRAPHS
6491 "digraphs",
6492#endif
6493#ifdef FEAT_DIRECTX
6494 "directx",
6495#endif
6496#ifdef FEAT_DND
6497 "dnd",
6498#endif
6499#ifdef FEAT_EMACS_TAGS
6500 "emacs_tags",
6501#endif
6502 "eval", /* always present, of course! */
6503 "ex_extra", /* graduated feature */
6504#ifdef FEAT_SEARCH_EXTRA
6505 "extra_search",
6506#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507#ifdef FEAT_SEARCHPATH
6508 "file_in_path",
6509#endif
6510#ifdef FEAT_FILTERPIPE
6511 "filterpipe",
6512#endif
6513#ifdef FEAT_FIND_ID
6514 "find_in_path",
6515#endif
6516#ifdef FEAT_FLOAT
6517 "float",
6518#endif
6519#ifdef FEAT_FOLDING
6520 "folding",
6521#endif
6522#ifdef FEAT_FOOTER
6523 "footer",
6524#endif
6525#if !defined(USE_SYSTEM) && defined(UNIX)
6526 "fork",
6527#endif
6528#ifdef FEAT_GETTEXT
6529 "gettext",
6530#endif
6531#ifdef FEAT_GUI
6532 "gui",
6533#endif
6534#ifdef FEAT_GUI_ATHENA
6535# ifdef FEAT_GUI_NEXTAW
6536 "gui_neXtaw",
6537# else
6538 "gui_athena",
6539# endif
6540#endif
6541#ifdef FEAT_GUI_GTK
6542 "gui_gtk",
6543# ifdef USE_GTK3
6544 "gui_gtk3",
6545# else
6546 "gui_gtk2",
6547# endif
6548#endif
6549#ifdef FEAT_GUI_GNOME
6550 "gui_gnome",
6551#endif
6552#ifdef FEAT_GUI_MAC
6553 "gui_mac",
6554#endif
6555#ifdef FEAT_GUI_MOTIF
6556 "gui_motif",
6557#endif
6558#ifdef FEAT_GUI_PHOTON
6559 "gui_photon",
6560#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006561#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562 "gui_win32",
6563#endif
6564#ifdef FEAT_HANGULIN
6565 "hangul_input",
6566#endif
6567#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6568 "iconv",
6569#endif
6570#ifdef FEAT_INS_EXPAND
6571 "insert_expand",
6572#endif
6573#ifdef FEAT_JOB_CHANNEL
6574 "job",
6575#endif
6576#ifdef FEAT_JUMPLIST
6577 "jumplist",
6578#endif
6579#ifdef FEAT_KEYMAP
6580 "keymap",
6581#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006582 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583#ifdef FEAT_LANGMAP
6584 "langmap",
6585#endif
6586#ifdef FEAT_LIBCALL
6587 "libcall",
6588#endif
6589#ifdef FEAT_LINEBREAK
6590 "linebreak",
6591#endif
6592#ifdef FEAT_LISP
6593 "lispindent",
6594#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006595 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006596#ifdef FEAT_LOCALMAP
6597 "localmap",
6598#endif
6599#ifdef FEAT_LUA
6600# ifndef DYNAMIC_LUA
6601 "lua",
6602# endif
6603#endif
6604#ifdef FEAT_MENU
6605 "menu",
6606#endif
6607#ifdef FEAT_SESSION
6608 "mksession",
6609#endif
6610#ifdef FEAT_MODIFY_FNAME
6611 "modify_fname",
6612#endif
6613#ifdef FEAT_MOUSE
6614 "mouse",
6615#endif
6616#ifdef FEAT_MOUSESHAPE
6617 "mouseshape",
6618#endif
6619#if defined(UNIX) || defined(VMS)
6620# ifdef FEAT_MOUSE_DEC
6621 "mouse_dec",
6622# endif
6623# ifdef FEAT_MOUSE_GPM
6624 "mouse_gpm",
6625# endif
6626# ifdef FEAT_MOUSE_JSB
6627 "mouse_jsbterm",
6628# endif
6629# ifdef FEAT_MOUSE_NET
6630 "mouse_netterm",
6631# endif
6632# ifdef FEAT_MOUSE_PTERM
6633 "mouse_pterm",
6634# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006635# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006636 "mouse_sgr",
6637# endif
6638# ifdef FEAT_SYSMOUSE
6639 "mouse_sysmouse",
6640# endif
6641# ifdef FEAT_MOUSE_URXVT
6642 "mouse_urxvt",
6643# endif
6644# ifdef FEAT_MOUSE_XTERM
6645 "mouse_xterm",
6646# endif
6647#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006648 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006649#ifdef FEAT_MBYTE_IME
6650 "multi_byte_ime",
6651#endif
6652#ifdef FEAT_MULTI_LANG
6653 "multi_lang",
6654#endif
6655#ifdef FEAT_MZSCHEME
6656#ifndef DYNAMIC_MZSCHEME
6657 "mzscheme",
6658#endif
6659#endif
6660#ifdef FEAT_NUM64
6661 "num64",
6662#endif
6663#ifdef FEAT_OLE
6664 "ole",
6665#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006666#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006667 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006668#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006669#ifdef FEAT_PATH_EXTRA
6670 "path_extra",
6671#endif
6672#ifdef FEAT_PERL
6673#ifndef DYNAMIC_PERL
6674 "perl",
6675#endif
6676#endif
6677#ifdef FEAT_PERSISTENT_UNDO
6678 "persistent_undo",
6679#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006680#if defined(FEAT_PYTHON)
6681 "python_compiled",
6682# if defined(DYNAMIC_PYTHON)
6683 "python_dynamic",
6684# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006686 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006687# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006689#if defined(FEAT_PYTHON3)
6690 "python3_compiled",
6691# if defined(DYNAMIC_PYTHON3)
6692 "python3_dynamic",
6693# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006694 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006695 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006696# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006697#endif
6698#ifdef FEAT_POSTSCRIPT
6699 "postscript",
6700#endif
6701#ifdef FEAT_PRINTER
6702 "printer",
6703#endif
6704#ifdef FEAT_PROFILE
6705 "profile",
6706#endif
6707#ifdef FEAT_RELTIME
6708 "reltime",
6709#endif
6710#ifdef FEAT_QUICKFIX
6711 "quickfix",
6712#endif
6713#ifdef FEAT_RIGHTLEFT
6714 "rightleft",
6715#endif
6716#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6717 "ruby",
6718#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006719 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006720#ifdef FEAT_CMDL_INFO
6721 "showcmd",
6722 "cmdline_info",
6723#endif
6724#ifdef FEAT_SIGNS
6725 "signs",
6726#endif
6727#ifdef FEAT_SMARTINDENT
6728 "smartindent",
6729#endif
6730#ifdef STARTUPTIME
6731 "startuptime",
6732#endif
6733#ifdef FEAT_STL_OPT
6734 "statusline",
6735#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006736#ifdef FEAT_NETBEANS_INTG
6737 "netbeans_intg",
6738#endif
6739#ifdef FEAT_SPELL
6740 "spell",
6741#endif
6742#ifdef FEAT_SYN_HL
6743 "syntax",
6744#endif
6745#if defined(USE_SYSTEM) || !defined(UNIX)
6746 "system",
6747#endif
6748#ifdef FEAT_TAG_BINS
6749 "tag_binary",
6750#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006751#ifdef FEAT_TCL
6752# ifndef DYNAMIC_TCL
6753 "tcl",
6754# endif
6755#endif
6756#ifdef FEAT_TERMGUICOLORS
6757 "termguicolors",
6758#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006759#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006760 "terminal",
6761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006762#ifdef TERMINFO
6763 "terminfo",
6764#endif
6765#ifdef FEAT_TERMRESPONSE
6766 "termresponse",
6767#endif
6768#ifdef FEAT_TEXTOBJ
6769 "textobjects",
6770#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006771#ifdef FEAT_TEXT_PROP
6772 "textprop",
6773#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774#ifdef HAVE_TGETENT
6775 "tgetent",
6776#endif
6777#ifdef FEAT_TIMERS
6778 "timers",
6779#endif
6780#ifdef FEAT_TITLE
6781 "title",
6782#endif
6783#ifdef FEAT_TOOLBAR
6784 "toolbar",
6785#endif
6786#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6787 "unnamedplus",
6788#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006789 "user-commands", /* was accidentally included in 5.4 */
6790 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006791#ifdef FEAT_VARTABS
6792 "vartabs",
6793#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006794 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006795#ifdef FEAT_VIMINFO
6796 "viminfo",
6797#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006798 "vimscript-1",
6799 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006800 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006803 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006805#ifdef FEAT_VTP
6806 "vtp",
6807#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006808#ifdef FEAT_WILDIGN
6809 "wildignore",
6810#endif
6811#ifdef FEAT_WILDMENU
6812 "wildmenu",
6813#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006815#ifdef FEAT_WAK
6816 "winaltkeys",
6817#endif
6818#ifdef FEAT_WRITEBACKUP
6819 "writebackup",
6820#endif
6821#ifdef FEAT_XIM
6822 "xim",
6823#endif
6824#ifdef FEAT_XFONTSET
6825 "xfontset",
6826#endif
6827#ifdef FEAT_XPM_W32
6828 "xpm",
6829 "xpm_w32", /* for backward compatibility */
6830#else
6831# if defined(HAVE_XPM)
6832 "xpm",
6833# endif
6834#endif
6835#ifdef USE_XSMP
6836 "xsmp",
6837#endif
6838#ifdef USE_XSMP_INTERACT
6839 "xsmp_interact",
6840#endif
6841#ifdef FEAT_XCLIPBOARD
6842 "xterm_clipboard",
6843#endif
6844#ifdef FEAT_XTERM_SAVE
6845 "xterm_save",
6846#endif
6847#if defined(UNIX) && defined(FEAT_X11)
6848 "X11",
6849#endif
6850 NULL
6851 };
6852
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006853 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006854 for (i = 0; has_list[i] != NULL; ++i)
6855 if (STRICMP(name, has_list[i]) == 0)
6856 {
6857 n = TRUE;
6858 break;
6859 }
6860
6861 if (n == FALSE)
6862 {
6863 if (STRNICMP(name, "patch", 5) == 0)
6864 {
6865 if (name[5] == '-'
6866 && STRLEN(name) >= 11
6867 && vim_isdigit(name[6])
6868 && vim_isdigit(name[8])
6869 && vim_isdigit(name[10]))
6870 {
6871 int major = atoi((char *)name + 6);
6872 int minor = atoi((char *)name + 8);
6873
6874 /* Expect "patch-9.9.01234". */
6875 n = (major < VIM_VERSION_MAJOR
6876 || (major == VIM_VERSION_MAJOR
6877 && (minor < VIM_VERSION_MINOR
6878 || (minor == VIM_VERSION_MINOR
6879 && has_patch(atoi((char *)name + 10))))));
6880 }
6881 else
6882 n = has_patch(atoi((char *)name + 5));
6883 }
6884 else if (STRICMP(name, "vim_starting") == 0)
6885 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006886 else if (STRICMP(name, "ttyin") == 0)
6887 n = mch_input_isatty();
6888 else if (STRICMP(name, "ttyout") == 0)
6889 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006890 else if (STRICMP(name, "multi_byte_encoding") == 0)
6891 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006892#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893 else if (STRICMP(name, "balloon_multiline") == 0)
6894 n = multiline_balloon_available();
6895#endif
6896#ifdef DYNAMIC_TCL
6897 else if (STRICMP(name, "tcl") == 0)
6898 n = tcl_enabled(FALSE);
6899#endif
6900#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6901 else if (STRICMP(name, "iconv") == 0)
6902 n = iconv_enabled(FALSE);
6903#endif
6904#ifdef DYNAMIC_LUA
6905 else if (STRICMP(name, "lua") == 0)
6906 n = lua_enabled(FALSE);
6907#endif
6908#ifdef DYNAMIC_MZSCHEME
6909 else if (STRICMP(name, "mzscheme") == 0)
6910 n = mzscheme_enabled(FALSE);
6911#endif
6912#ifdef DYNAMIC_RUBY
6913 else if (STRICMP(name, "ruby") == 0)
6914 n = ruby_enabled(FALSE);
6915#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916#ifdef DYNAMIC_PYTHON
6917 else if (STRICMP(name, "python") == 0)
6918 n = python_enabled(FALSE);
6919#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920#ifdef DYNAMIC_PYTHON3
6921 else if (STRICMP(name, "python3") == 0)
6922 n = python3_enabled(FALSE);
6923#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006924#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6925 else if (STRICMP(name, "pythonx") == 0)
6926 {
6927# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6928 if (p_pyx == 0)
6929 n = python3_enabled(FALSE) || python_enabled(FALSE);
6930 else if (p_pyx == 3)
6931 n = python3_enabled(FALSE);
6932 else if (p_pyx == 2)
6933 n = python_enabled(FALSE);
6934# elif defined(DYNAMIC_PYTHON)
6935 n = python_enabled(FALSE);
6936# elif defined(DYNAMIC_PYTHON3)
6937 n = python3_enabled(FALSE);
6938# endif
6939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940#endif
6941#ifdef DYNAMIC_PERL
6942 else if (STRICMP(name, "perl") == 0)
6943 n = perl_enabled(FALSE);
6944#endif
6945#ifdef FEAT_GUI
6946 else if (STRICMP(name, "gui_running") == 0)
6947 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948# ifdef FEAT_BROWSE
6949 else if (STRICMP(name, "browse") == 0)
6950 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6951# endif
6952#endif
6953#ifdef FEAT_SYN_HL
6954 else if (STRICMP(name, "syntax_items") == 0)
6955 n = syntax_present(curwin);
6956#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006957#ifdef FEAT_VTP
6958 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006959 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960#endif
6961#ifdef FEAT_NETBEANS_INTG
6962 else if (STRICMP(name, "netbeans_enabled") == 0)
6963 n = netbeans_active();
6964#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006965#ifdef FEAT_MOUSE_GPM
6966 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6967 n = gpm_enabled();
6968#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006969#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006970 else if (STRICMP(name, "terminal") == 0)
6971 n = terminal_enabled();
6972#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006973#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006974 else if (STRICMP(name, "conpty") == 0)
6975 n = use_conpty();
6976#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006977 }
6978
6979 rettv->vval.v_number = n;
6980}
6981
6982/*
6983 * "has_key()" function
6984 */
6985 static void
6986f_has_key(typval_T *argvars, typval_T *rettv)
6987{
6988 if (argvars[0].v_type != VAR_DICT)
6989 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006990 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 return;
6992 }
6993 if (argvars[0].vval.v_dict == NULL)
6994 return;
6995
6996 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006997 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998}
6999
7000/*
7001 * "haslocaldir()" function
7002 */
7003 static void
7004f_haslocaldir(typval_T *argvars, typval_T *rettv)
7005{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02007006 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007007 win_T *wp = NULL;
7008
Bram Moolenaar00aa0692019-04-27 20:37:57 +02007009 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
7010
7011 // Check for window-local and tab-local directories
7012 if (wp != NULL && wp->w_localdir != NULL)
7013 rettv->vval.v_number = 1;
7014 else if (tp != NULL && tp->tp_localdir != NULL)
7015 rettv->vval.v_number = 2;
7016 else
7017 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007018}
7019
7020/*
7021 * "hasmapto()" function
7022 */
7023 static void
7024f_hasmapto(typval_T *argvars, typval_T *rettv)
7025{
7026 char_u *name;
7027 char_u *mode;
7028 char_u buf[NUMBUFLEN];
7029 int abbr = FALSE;
7030
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007031 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007032 if (argvars[1].v_type == VAR_UNKNOWN)
7033 mode = (char_u *)"nvo";
7034 else
7035 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007036 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007037 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007038 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 }
7040
7041 if (map_to_exists(name, mode, abbr))
7042 rettv->vval.v_number = TRUE;
7043 else
7044 rettv->vval.v_number = FALSE;
7045}
7046
7047/*
7048 * "histadd()" function
7049 */
7050 static void
7051f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
7052{
7053#ifdef FEAT_CMDHIST
7054 int histype;
7055 char_u *str;
7056 char_u buf[NUMBUFLEN];
7057#endif
7058
7059 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007060 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061 return;
7062#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007063 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064 histype = str != NULL ? get_histtype(str) : -1;
7065 if (histype >= 0)
7066 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007067 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068 if (*str != NUL)
7069 {
7070 init_history();
7071 add_to_history(histype, str, FALSE, NUL);
7072 rettv->vval.v_number = TRUE;
7073 return;
7074 }
7075 }
7076#endif
7077}
7078
7079/*
7080 * "histdel()" function
7081 */
7082 static void
7083f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7084{
7085#ifdef FEAT_CMDHIST
7086 int n;
7087 char_u buf[NUMBUFLEN];
7088 char_u *str;
7089
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007090 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007091 if (str == NULL)
7092 n = 0;
7093 else if (argvars[1].v_type == VAR_UNKNOWN)
7094 /* only one argument: clear entire history */
7095 n = clr_history(get_histtype(str));
7096 else if (argvars[1].v_type == VAR_NUMBER)
7097 /* index given: remove that entry */
7098 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007099 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007100 else
7101 /* string given: remove all matching entries */
7102 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007103 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007104 rettv->vval.v_number = n;
7105#endif
7106}
7107
7108/*
7109 * "histget()" function
7110 */
7111 static void
7112f_histget(typval_T *argvars UNUSED, typval_T *rettv)
7113{
7114#ifdef FEAT_CMDHIST
7115 int type;
7116 int idx;
7117 char_u *str;
7118
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007119 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007120 if (str == NULL)
7121 rettv->vval.v_string = NULL;
7122 else
7123 {
7124 type = get_histtype(str);
7125 if (argvars[1].v_type == VAR_UNKNOWN)
7126 idx = get_history_idx(type);
7127 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007128 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007129 /* -1 on type error */
7130 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
7131 }
7132#else
7133 rettv->vval.v_string = NULL;
7134#endif
7135 rettv->v_type = VAR_STRING;
7136}
7137
7138/*
7139 * "histnr()" function
7140 */
7141 static void
7142f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
7143{
7144 int i;
7145
7146#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007147 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148
7149 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
7150 if (i >= HIST_CMD && i < HIST_COUNT)
7151 i = get_history_idx(i);
7152 else
7153#endif
7154 i = -1;
7155 rettv->vval.v_number = i;
7156}
7157
7158/*
7159 * "highlightID(name)" function
7160 */
7161 static void
7162f_hlID(typval_T *argvars, typval_T *rettv)
7163{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007164 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007165}
7166
7167/*
7168 * "highlight_exists()" function
7169 */
7170 static void
7171f_hlexists(typval_T *argvars, typval_T *rettv)
7172{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007173 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007174}
7175
7176/*
7177 * "hostname()" function
7178 */
7179 static void
7180f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
7181{
7182 char_u hostname[256];
7183
7184 mch_get_host_name(hostname, 256);
7185 rettv->v_type = VAR_STRING;
7186 rettv->vval.v_string = vim_strsave(hostname);
7187}
7188
7189/*
7190 * iconv() function
7191 */
7192 static void
7193f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7194{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195 char_u buf1[NUMBUFLEN];
7196 char_u buf2[NUMBUFLEN];
7197 char_u *from, *to, *str;
7198 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007199
7200 rettv->v_type = VAR_STRING;
7201 rettv->vval.v_string = NULL;
7202
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007203 str = tv_get_string(&argvars[0]);
7204 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7205 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 vimconv.vc_type = CONV_NONE;
7207 convert_setup(&vimconv, from, to);
7208
7209 /* If the encodings are equal, no conversion needed. */
7210 if (vimconv.vc_type == CONV_NONE)
7211 rettv->vval.v_string = vim_strsave(str);
7212 else
7213 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7214
7215 convert_setup(&vimconv, NULL, NULL);
7216 vim_free(from);
7217 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218}
7219
7220/*
7221 * "indent()" function
7222 */
7223 static void
7224f_indent(typval_T *argvars, typval_T *rettv)
7225{
7226 linenr_T lnum;
7227
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007228 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7230 rettv->vval.v_number = get_indent_lnum(lnum);
7231 else
7232 rettv->vval.v_number = -1;
7233}
7234
7235/*
7236 * "index()" function
7237 */
7238 static void
7239f_index(typval_T *argvars, typval_T *rettv)
7240{
7241 list_T *l;
7242 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007243 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244 long idx = 0;
7245 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007246 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247
7248 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007249 if (argvars[0].v_type == VAR_BLOB)
7250 {
7251 typval_T tv;
7252 int start = 0;
7253
7254 if (argvars[2].v_type != VAR_UNKNOWN)
7255 {
7256 start = tv_get_number_chk(&argvars[2], &error);
7257 if (error)
7258 return;
7259 }
7260 b = argvars[0].vval.v_blob;
7261 if (b == NULL)
7262 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007263 if (start < 0)
7264 {
7265 start = blob_len(b) + start;
7266 if (start < 0)
7267 start = 0;
7268 }
7269
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007270 for (idx = start; idx < blob_len(b); ++idx)
7271 {
7272 tv.v_type = VAR_NUMBER;
7273 tv.vval.v_number = blob_get(b, idx);
7274 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7275 {
7276 rettv->vval.v_number = idx;
7277 return;
7278 }
7279 }
7280 return;
7281 }
7282 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007283 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007284 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 return;
7286 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007287
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 l = argvars[0].vval.v_list;
7289 if (l != NULL)
7290 {
7291 item = l->lv_first;
7292 if (argvars[2].v_type != VAR_UNKNOWN)
7293 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294 /* Start at specified item. Use the cached index that list_find()
7295 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007296 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297 idx = l->lv_idx;
7298 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007299 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007300 if (error)
7301 item = NULL;
7302 }
7303
7304 for ( ; item != NULL; item = item->li_next, ++idx)
7305 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7306 {
7307 rettv->vval.v_number = idx;
7308 break;
7309 }
7310 }
7311}
7312
7313static int inputsecret_flag = 0;
7314
7315/*
7316 * "input()" function
7317 * Also handles inputsecret() when inputsecret is set.
7318 */
7319 static void
7320f_input(typval_T *argvars, typval_T *rettv)
7321{
7322 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7323}
7324
7325/*
7326 * "inputdialog()" function
7327 */
7328 static void
7329f_inputdialog(typval_T *argvars, typval_T *rettv)
7330{
7331#if defined(FEAT_GUI_TEXTDIALOG)
7332 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7333 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7334 {
7335 char_u *message;
7336 char_u buf[NUMBUFLEN];
7337 char_u *defstr = (char_u *)"";
7338
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007339 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007340 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007341 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7343 else
7344 IObuff[0] = NUL;
7345 if (message != NULL && defstr != NULL
7346 && do_dialog(VIM_QUESTION, NULL, message,
7347 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7348 rettv->vval.v_string = vim_strsave(IObuff);
7349 else
7350 {
7351 if (message != NULL && defstr != NULL
7352 && argvars[1].v_type != VAR_UNKNOWN
7353 && argvars[2].v_type != VAR_UNKNOWN)
7354 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007355 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 else
7357 rettv->vval.v_string = NULL;
7358 }
7359 rettv->v_type = VAR_STRING;
7360 }
7361 else
7362#endif
7363 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7364}
7365
7366/*
7367 * "inputlist()" function
7368 */
7369 static void
7370f_inputlist(typval_T *argvars, typval_T *rettv)
7371{
7372 listitem_T *li;
7373 int selected;
7374 int mouse_used;
7375
7376#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007377 /* While starting up, there is no place to enter text. When running tests
7378 * with --not-a-term we assume feedkeys() will be used. */
7379 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007380 return;
7381#endif
7382 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7383 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007384 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385 return;
7386 }
7387
7388 msg_start();
7389 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7390 lines_left = Rows; /* avoid more prompt */
7391 msg_scroll = TRUE;
7392 msg_clr_eos();
7393
7394 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7395 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007396 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007397 msg_putchar('\n');
7398 }
7399
7400 /* Ask for choice. */
7401 selected = prompt_for_number(&mouse_used);
7402 if (mouse_used)
7403 selected -= lines_left;
7404
7405 rettv->vval.v_number = selected;
7406}
7407
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007408static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7409
7410/*
7411 * "inputrestore()" function
7412 */
7413 static void
7414f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7415{
7416 if (ga_userinput.ga_len > 0)
7417 {
7418 --ga_userinput.ga_len;
7419 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7420 + ga_userinput.ga_len);
7421 /* default return is zero == OK */
7422 }
7423 else if (p_verbose > 1)
7424 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007425 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 rettv->vval.v_number = 1; /* Failed */
7427 }
7428}
7429
7430/*
7431 * "inputsave()" function
7432 */
7433 static void
7434f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7435{
7436 /* Add an entry to the stack of typeahead storage. */
7437 if (ga_grow(&ga_userinput, 1) == OK)
7438 {
7439 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7440 + ga_userinput.ga_len);
7441 ++ga_userinput.ga_len;
7442 /* default return is zero == OK */
7443 }
7444 else
7445 rettv->vval.v_number = 1; /* Failed */
7446}
7447
7448/*
7449 * "inputsecret()" function
7450 */
7451 static void
7452f_inputsecret(typval_T *argvars, typval_T *rettv)
7453{
7454 ++cmdline_star;
7455 ++inputsecret_flag;
7456 f_input(argvars, rettv);
7457 --cmdline_star;
7458 --inputsecret_flag;
7459}
7460
7461/*
7462 * "insert()" function
7463 */
7464 static void
7465f_insert(typval_T *argvars, typval_T *rettv)
7466{
7467 long before = 0;
7468 listitem_T *item;
7469 list_T *l;
7470 int error = FALSE;
7471
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007472 if (argvars[0].v_type == VAR_BLOB)
7473 {
7474 int val, len;
7475 char_u *p;
7476
7477 len = blob_len(argvars[0].vval.v_blob);
7478 if (argvars[2].v_type != VAR_UNKNOWN)
7479 {
7480 before = (long)tv_get_number_chk(&argvars[2], &error);
7481 if (error)
7482 return; // type error; errmsg already given
7483 if (before < 0 || before > len)
7484 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007485 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007486 return;
7487 }
7488 }
7489 val = tv_get_number_chk(&argvars[1], &error);
7490 if (error)
7491 return;
7492 if (val < 0 || val > 255)
7493 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007494 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007495 return;
7496 }
7497
7498 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7499 return;
7500 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7501 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7502 *(p + before) = val;
7503 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7504
7505 copy_tv(&argvars[0], rettv);
7506 }
7507 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007508 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007509 else if ((l = argvars[0].vval.v_list) != NULL
7510 && !var_check_lock(l->lv_lock,
7511 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512 {
7513 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007514 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 if (error)
7516 return; /* type error; errmsg already given */
7517
7518 if (before == l->lv_len)
7519 item = NULL;
7520 else
7521 {
7522 item = list_find(l, before);
7523 if (item == NULL)
7524 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007525 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 l = NULL;
7527 }
7528 }
7529 if (l != NULL)
7530 {
7531 list_insert_tv(l, &argvars[1], item);
7532 copy_tv(&argvars[0], rettv);
7533 }
7534 }
7535}
7536
7537/*
7538 * "invert(expr)" function
7539 */
7540 static void
7541f_invert(typval_T *argvars, typval_T *rettv)
7542{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007543 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007544}
7545
7546/*
7547 * "isdirectory()" function
7548 */
7549 static void
7550f_isdirectory(typval_T *argvars, typval_T *rettv)
7551{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007552 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007553}
7554
7555/*
7556 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7557 * or it refers to a List or Dictionary that is locked.
7558 */
7559 static int
7560tv_islocked(typval_T *tv)
7561{
7562 return (tv->v_lock & VAR_LOCKED)
7563 || (tv->v_type == VAR_LIST
7564 && tv->vval.v_list != NULL
7565 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7566 || (tv->v_type == VAR_DICT
7567 && tv->vval.v_dict != NULL
7568 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7569}
7570
7571/*
7572 * "islocked()" function
7573 */
7574 static void
7575f_islocked(typval_T *argvars, typval_T *rettv)
7576{
7577 lval_T lv;
7578 char_u *end;
7579 dictitem_T *di;
7580
7581 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007582 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007583 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584 if (end != NULL && lv.ll_name != NULL)
7585 {
7586 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007587 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588 else
7589 {
7590 if (lv.ll_tv == NULL)
7591 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007592 di = find_var(lv.ll_name, NULL, TRUE);
7593 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007594 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007595 /* Consider a variable locked when:
7596 * 1. the variable itself is locked
7597 * 2. the value of the variable is locked.
7598 * 3. the List or Dict value is locked.
7599 */
7600 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7601 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007602 }
7603 }
7604 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007605 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007606 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007607 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608 else if (lv.ll_list != NULL)
7609 /* List item. */
7610 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7611 else
7612 /* Dictionary item. */
7613 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7614 }
7615 }
7616
7617 clear_lval(&lv);
7618}
7619
7620#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7621/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007622 * "isinf()" function
7623 */
7624 static void
7625f_isinf(typval_T *argvars, typval_T *rettv)
7626{
7627 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7628 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7629}
7630
7631/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632 * "isnan()" function
7633 */
7634 static void
7635f_isnan(typval_T *argvars, typval_T *rettv)
7636{
7637 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7638 && isnan(argvars[0].vval.v_float);
7639}
7640#endif
7641
7642/*
7643 * "items(dict)" function
7644 */
7645 static void
7646f_items(typval_T *argvars, typval_T *rettv)
7647{
7648 dict_list(argvars, rettv, 2);
7649}
7650
7651#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7652/*
7653 * Get the job from the argument.
7654 * Returns NULL if the job is invalid.
7655 */
7656 static job_T *
7657get_job_arg(typval_T *tv)
7658{
7659 job_T *job;
7660
7661 if (tv->v_type != VAR_JOB)
7662 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007663 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007664 return NULL;
7665 }
7666 job = tv->vval.v_job;
7667
7668 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007669 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 return job;
7671}
7672
7673/*
7674 * "job_getchannel()" function
7675 */
7676 static void
7677f_job_getchannel(typval_T *argvars, typval_T *rettv)
7678{
7679 job_T *job = get_job_arg(&argvars[0]);
7680
7681 if (job != NULL)
7682 {
7683 rettv->v_type = VAR_CHANNEL;
7684 rettv->vval.v_channel = job->jv_channel;
7685 if (job->jv_channel != NULL)
7686 ++job->jv_channel->ch_refcount;
7687 }
7688}
7689
7690/*
7691 * "job_info()" function
7692 */
7693 static void
7694f_job_info(typval_T *argvars, typval_T *rettv)
7695{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007696 if (argvars[0].v_type != VAR_UNKNOWN)
7697 {
7698 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007699
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007700 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7701 job_info(job, rettv->vval.v_dict);
7702 }
7703 else if (rettv_list_alloc(rettv) == OK)
7704 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007705}
7706
7707/*
7708 * "job_setoptions()" function
7709 */
7710 static void
7711f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7712{
7713 job_T *job = get_job_arg(&argvars[0]);
7714 jobopt_T opt;
7715
7716 if (job == NULL)
7717 return;
7718 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007719 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007720 job_set_options(job, &opt);
7721 free_job_options(&opt);
7722}
7723
7724/*
7725 * "job_start()" function
7726 */
7727 static void
7728f_job_start(typval_T *argvars, typval_T *rettv)
7729{
7730 rettv->v_type = VAR_JOB;
7731 if (check_restricted() || check_secure())
7732 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007733 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007734}
7735
7736/*
7737 * "job_status()" function
7738 */
7739 static void
7740f_job_status(typval_T *argvars, typval_T *rettv)
7741{
7742 job_T *job = get_job_arg(&argvars[0]);
7743
7744 if (job != NULL)
7745 {
7746 rettv->v_type = VAR_STRING;
7747 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7748 }
7749}
7750
7751/*
7752 * "job_stop()" function
7753 */
7754 static void
7755f_job_stop(typval_T *argvars, typval_T *rettv)
7756{
7757 job_T *job = get_job_arg(&argvars[0]);
7758
7759 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007760 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007761}
7762#endif
7763
7764/*
7765 * "join()" function
7766 */
7767 static void
7768f_join(typval_T *argvars, typval_T *rettv)
7769{
7770 garray_T ga;
7771 char_u *sep;
7772
7773 if (argvars[0].v_type != VAR_LIST)
7774 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007775 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 return;
7777 }
7778 if (argvars[0].vval.v_list == NULL)
7779 return;
7780 if (argvars[1].v_type == VAR_UNKNOWN)
7781 sep = (char_u *)" ";
7782 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007783 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007784
7785 rettv->v_type = VAR_STRING;
7786
7787 if (sep != NULL)
7788 {
7789 ga_init2(&ga, (int)sizeof(char), 80);
7790 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7791 ga_append(&ga, NUL);
7792 rettv->vval.v_string = (char_u *)ga.ga_data;
7793 }
7794 else
7795 rettv->vval.v_string = NULL;
7796}
7797
7798/*
7799 * "js_decode()" function
7800 */
7801 static void
7802f_js_decode(typval_T *argvars, typval_T *rettv)
7803{
7804 js_read_T reader;
7805
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007806 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807 reader.js_fill = NULL;
7808 reader.js_used = 0;
7809 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007810 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007811}
7812
7813/*
7814 * "js_encode()" function
7815 */
7816 static void
7817f_js_encode(typval_T *argvars, typval_T *rettv)
7818{
7819 rettv->v_type = VAR_STRING;
7820 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7821}
7822
7823/*
7824 * "json_decode()" function
7825 */
7826 static void
7827f_json_decode(typval_T *argvars, typval_T *rettv)
7828{
7829 js_read_T reader;
7830
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007831 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 reader.js_fill = NULL;
7833 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007834 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835}
7836
7837/*
7838 * "json_encode()" function
7839 */
7840 static void
7841f_json_encode(typval_T *argvars, typval_T *rettv)
7842{
7843 rettv->v_type = VAR_STRING;
7844 rettv->vval.v_string = json_encode(&argvars[0], 0);
7845}
7846
7847/*
7848 * "keys()" function
7849 */
7850 static void
7851f_keys(typval_T *argvars, typval_T *rettv)
7852{
7853 dict_list(argvars, rettv, 0);
7854}
7855
7856/*
7857 * "last_buffer_nr()" function.
7858 */
7859 static void
7860f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7861{
7862 int n = 0;
7863 buf_T *buf;
7864
Bram Moolenaar29323592016-07-24 22:04:11 +02007865 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 if (n < buf->b_fnum)
7867 n = buf->b_fnum;
7868
7869 rettv->vval.v_number = n;
7870}
7871
7872/*
7873 * "len()" function
7874 */
7875 static void
7876f_len(typval_T *argvars, typval_T *rettv)
7877{
7878 switch (argvars[0].v_type)
7879 {
7880 case VAR_STRING:
7881 case VAR_NUMBER:
7882 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007883 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007884 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007885 case VAR_BLOB:
7886 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7887 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 case VAR_LIST:
7889 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7890 break;
7891 case VAR_DICT:
7892 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7893 break;
7894 case VAR_UNKNOWN:
7895 case VAR_SPECIAL:
7896 case VAR_FLOAT:
7897 case VAR_FUNC:
7898 case VAR_PARTIAL:
7899 case VAR_JOB:
7900 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007901 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007902 break;
7903 }
7904}
7905
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007906 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007907libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908{
7909#ifdef FEAT_LIBCALL
7910 char_u *string_in;
7911 char_u **string_result;
7912 int nr_result;
7913#endif
7914
7915 rettv->v_type = type;
7916 if (type != VAR_NUMBER)
7917 rettv->vval.v_string = NULL;
7918
7919 if (check_restricted() || check_secure())
7920 return;
7921
7922#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007923 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7925 {
7926 string_in = NULL;
7927 if (argvars[2].v_type == VAR_STRING)
7928 string_in = argvars[2].vval.v_string;
7929 if (type == VAR_NUMBER)
7930 string_result = NULL;
7931 else
7932 string_result = &rettv->vval.v_string;
7933 if (mch_libcall(argvars[0].vval.v_string,
7934 argvars[1].vval.v_string,
7935 string_in,
7936 argvars[2].vval.v_number,
7937 string_result,
7938 &nr_result) == OK
7939 && type == VAR_NUMBER)
7940 rettv->vval.v_number = nr_result;
7941 }
7942#endif
7943}
7944
7945/*
7946 * "libcall()" function
7947 */
7948 static void
7949f_libcall(typval_T *argvars, typval_T *rettv)
7950{
7951 libcall_common(argvars, rettv, VAR_STRING);
7952}
7953
7954/*
7955 * "libcallnr()" function
7956 */
7957 static void
7958f_libcallnr(typval_T *argvars, typval_T *rettv)
7959{
7960 libcall_common(argvars, rettv, VAR_NUMBER);
7961}
7962
7963/*
7964 * "line(string)" function
7965 */
7966 static void
7967f_line(typval_T *argvars, typval_T *rettv)
7968{
7969 linenr_T lnum = 0;
7970 pos_T *fp;
7971 int fnum;
7972
7973 fp = var2fpos(&argvars[0], TRUE, &fnum);
7974 if (fp != NULL)
7975 lnum = fp->lnum;
7976 rettv->vval.v_number = lnum;
7977}
7978
7979/*
7980 * "line2byte(lnum)" function
7981 */
7982 static void
7983f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7984{
7985#ifndef FEAT_BYTEOFF
7986 rettv->vval.v_number = -1;
7987#else
7988 linenr_T lnum;
7989
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007990 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7992 rettv->vval.v_number = -1;
7993 else
7994 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7995 if (rettv->vval.v_number >= 0)
7996 ++rettv->vval.v_number;
7997#endif
7998}
7999
8000/*
8001 * "lispindent(lnum)" function
8002 */
8003 static void
8004f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
8005{
8006#ifdef FEAT_LISP
8007 pos_T pos;
8008 linenr_T lnum;
8009
8010 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008011 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008012 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
8013 {
8014 curwin->w_cursor.lnum = lnum;
8015 rettv->vval.v_number = get_lisp_indent();
8016 curwin->w_cursor = pos;
8017 }
8018 else
8019#endif
8020 rettv->vval.v_number = -1;
8021}
8022
8023/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008024 * "list2str()" function
8025 */
8026 static void
8027f_list2str(typval_T *argvars, typval_T *rettv)
8028{
8029 list_T *l;
8030 listitem_T *li;
8031 garray_T ga;
8032 int utf8 = FALSE;
8033
8034 rettv->v_type = VAR_STRING;
8035 rettv->vval.v_string = NULL;
8036 if (argvars[0].v_type != VAR_LIST)
8037 {
8038 emsg(_(e_invarg));
8039 return;
8040 }
8041
8042 l = argvars[0].vval.v_list;
8043 if (l == NULL)
8044 return; // empty list results in empty string
8045
8046 if (argvars[1].v_type != VAR_UNKNOWN)
8047 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8048
8049 ga_init2(&ga, 1, 80);
8050 if (has_mbyte || utf8)
8051 {
8052 char_u buf[MB_MAXBYTES + 1];
8053 int (*char2bytes)(int, char_u *);
8054
8055 if (utf8 || enc_utf8)
8056 char2bytes = utf_char2bytes;
8057 else
8058 char2bytes = mb_char2bytes;
8059
8060 for (li = l->lv_first; li != NULL; li = li->li_next)
8061 {
8062 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
8063 ga_concat(&ga, buf);
8064 }
8065 ga_append(&ga, NUL);
8066 }
8067 else if (ga_grow(&ga, list_len(l) + 1) == OK)
8068 {
8069 for (li = l->lv_first; li != NULL; li = li->li_next)
8070 ga_append(&ga, tv_get_number(&li->li_tv));
8071 ga_append(&ga, NUL);
8072 }
8073
8074 rettv->v_type = VAR_STRING;
8075 rettv->vval.v_string = ga.ga_data;
8076}
8077
8078/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 * "localtime()" function
8080 */
8081 static void
8082f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
8083{
8084 rettv->vval.v_number = (varnumber_T)time(NULL);
8085}
8086
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087 static void
8088get_maparg(typval_T *argvars, typval_T *rettv, int exact)
8089{
8090 char_u *keys;
8091 char_u *which;
8092 char_u buf[NUMBUFLEN];
8093 char_u *keys_buf = NULL;
8094 char_u *rhs;
8095 int mode;
8096 int abbr = FALSE;
8097 int get_dict = FALSE;
8098 mapblock_T *mp;
8099 int buffer_local;
8100
8101 /* return empty string for failure */
8102 rettv->v_type = VAR_STRING;
8103 rettv->vval.v_string = NULL;
8104
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008105 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 if (*keys == NUL)
8107 return;
8108
8109 if (argvars[1].v_type != VAR_UNKNOWN)
8110 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008111 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112 if (argvars[2].v_type != VAR_UNKNOWN)
8113 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008114 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008115 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008116 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008117 }
8118 }
8119 else
8120 which = (char_u *)"";
8121 if (which == NULL)
8122 return;
8123
8124 mode = get_map_mode(&which, 0);
8125
8126 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
8127 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
8128 vim_free(keys_buf);
8129
8130 if (!get_dict)
8131 {
8132 /* Return a string. */
8133 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02008134 {
8135 if (*rhs == NUL)
8136 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
8137 else
8138 rettv->vval.v_string = str2special_save(rhs, FALSE);
8139 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140
8141 }
8142 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
8143 {
8144 /* Return a dictionary. */
8145 char_u *lhs = str2special_save(mp->m_keys, TRUE);
8146 char_u *mapmode = map_mode_to_chars(mp->m_mode);
8147 dict_T *dict = rettv->vval.v_dict;
8148
Bram Moolenaare0be1672018-07-08 16:50:37 +02008149 dict_add_string(dict, "lhs", lhs);
8150 dict_add_string(dict, "rhs", mp->m_orig_str);
8151 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
8152 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
8153 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02008154 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
8155 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02008156 dict_add_number(dict, "buffer", (long)buffer_local);
8157 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
8158 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159
8160 vim_free(lhs);
8161 vim_free(mapmode);
8162 }
8163}
8164
8165#ifdef FEAT_FLOAT
8166/*
8167 * "log()" function
8168 */
8169 static void
8170f_log(typval_T *argvars, typval_T *rettv)
8171{
8172 float_T f = 0.0;
8173
8174 rettv->v_type = VAR_FLOAT;
8175 if (get_float_arg(argvars, &f) == OK)
8176 rettv->vval.v_float = log(f);
8177 else
8178 rettv->vval.v_float = 0.0;
8179}
8180
8181/*
8182 * "log10()" function
8183 */
8184 static void
8185f_log10(typval_T *argvars, typval_T *rettv)
8186{
8187 float_T f = 0.0;
8188
8189 rettv->v_type = VAR_FLOAT;
8190 if (get_float_arg(argvars, &f) == OK)
8191 rettv->vval.v_float = log10(f);
8192 else
8193 rettv->vval.v_float = 0.0;
8194}
8195#endif
8196
8197#ifdef FEAT_LUA
8198/*
8199 * "luaeval()" function
8200 */
8201 static void
8202f_luaeval(typval_T *argvars, typval_T *rettv)
8203{
8204 char_u *str;
8205 char_u buf[NUMBUFLEN];
8206
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008207 if (check_restricted() || check_secure())
8208 return;
8209
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008210 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 do_luaeval(str, argvars + 1, rettv);
8212}
8213#endif
8214
8215/*
8216 * "map()" function
8217 */
8218 static void
8219f_map(typval_T *argvars, typval_T *rettv)
8220{
8221 filter_map(argvars, rettv, TRUE);
8222}
8223
8224/*
8225 * "maparg()" function
8226 */
8227 static void
8228f_maparg(typval_T *argvars, typval_T *rettv)
8229{
8230 get_maparg(argvars, rettv, TRUE);
8231}
8232
8233/*
8234 * "mapcheck()" function
8235 */
8236 static void
8237f_mapcheck(typval_T *argvars, typval_T *rettv)
8238{
8239 get_maparg(argvars, rettv, FALSE);
8240}
8241
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008242typedef enum
8243{
8244 MATCH_END, /* matchend() */
8245 MATCH_MATCH, /* match() */
8246 MATCH_STR, /* matchstr() */
8247 MATCH_LIST, /* matchlist() */
8248 MATCH_POS /* matchstrpos() */
8249} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008250
8251 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008252find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253{
8254 char_u *str = NULL;
8255 long len = 0;
8256 char_u *expr = NULL;
8257 char_u *pat;
8258 regmatch_T regmatch;
8259 char_u patbuf[NUMBUFLEN];
8260 char_u strbuf[NUMBUFLEN];
8261 char_u *save_cpo;
8262 long start = 0;
8263 long nth = 1;
8264 colnr_T startcol = 0;
8265 int match = 0;
8266 list_T *l = NULL;
8267 listitem_T *li = NULL;
8268 long idx = 0;
8269 char_u *tofree = NULL;
8270
8271 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8272 save_cpo = p_cpo;
8273 p_cpo = (char_u *)"";
8274
8275 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008276 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008277 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008278 /* type MATCH_LIST: return empty list when there are no matches.
8279 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008280 if (rettv_list_alloc(rettv) == FAIL)
8281 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008282 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283 && (list_append_string(rettv->vval.v_list,
8284 (char_u *)"", 0) == FAIL
8285 || list_append_number(rettv->vval.v_list,
8286 (varnumber_T)-1) == 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 {
8292 list_free(rettv->vval.v_list);
8293 rettv->vval.v_list = NULL;
8294 goto theend;
8295 }
8296 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008297 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008298 {
8299 rettv->v_type = VAR_STRING;
8300 rettv->vval.v_string = NULL;
8301 }
8302
8303 if (argvars[0].v_type == VAR_LIST)
8304 {
8305 if ((l = argvars[0].vval.v_list) == NULL)
8306 goto theend;
8307 li = l->lv_first;
8308 }
8309 else
8310 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008311 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008312 len = (long)STRLEN(str);
8313 }
8314
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008315 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 if (pat == NULL)
8317 goto theend;
8318
8319 if (argvars[2].v_type != VAR_UNKNOWN)
8320 {
8321 int error = FALSE;
8322
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008323 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008324 if (error)
8325 goto theend;
8326 if (l != NULL)
8327 {
8328 li = list_find(l, start);
8329 if (li == NULL)
8330 goto theend;
8331 idx = l->lv_idx; /* use the cached index */
8332 }
8333 else
8334 {
8335 if (start < 0)
8336 start = 0;
8337 if (start > len)
8338 goto theend;
8339 /* When "count" argument is there ignore matches before "start",
8340 * otherwise skip part of the string. Differs when pattern is "^"
8341 * or "\<". */
8342 if (argvars[3].v_type != VAR_UNKNOWN)
8343 startcol = start;
8344 else
8345 {
8346 str += start;
8347 len -= start;
8348 }
8349 }
8350
8351 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008352 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 if (error)
8354 goto theend;
8355 }
8356
8357 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8358 if (regmatch.regprog != NULL)
8359 {
8360 regmatch.rm_ic = p_ic;
8361
8362 for (;;)
8363 {
8364 if (l != NULL)
8365 {
8366 if (li == NULL)
8367 {
8368 match = FALSE;
8369 break;
8370 }
8371 vim_free(tofree);
8372 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8373 if (str == NULL)
8374 break;
8375 }
8376
8377 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8378
8379 if (match && --nth <= 0)
8380 break;
8381 if (l == NULL && !match)
8382 break;
8383
8384 /* Advance to just after the match. */
8385 if (l != NULL)
8386 {
8387 li = li->li_next;
8388 ++idx;
8389 }
8390 else
8391 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392 startcol = (colnr_T)(regmatch.startp[0]
8393 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 if (startcol > (colnr_T)len
8395 || str + startcol <= regmatch.startp[0])
8396 {
8397 match = FALSE;
8398 break;
8399 }
8400 }
8401 }
8402
8403 if (match)
8404 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008405 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008406 {
8407 listitem_T *li1 = rettv->vval.v_list->lv_first;
8408 listitem_T *li2 = li1->li_next;
8409 listitem_T *li3 = li2->li_next;
8410 listitem_T *li4 = li3->li_next;
8411
8412 vim_free(li1->li_tv.vval.v_string);
8413 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8414 (int)(regmatch.endp[0] - regmatch.startp[0]));
8415 li3->li_tv.vval.v_number =
8416 (varnumber_T)(regmatch.startp[0] - expr);
8417 li4->li_tv.vval.v_number =
8418 (varnumber_T)(regmatch.endp[0] - expr);
8419 if (l != NULL)
8420 li2->li_tv.vval.v_number = (varnumber_T)idx;
8421 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008422 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423 {
8424 int i;
8425
8426 /* return list with matched string and submatches */
8427 for (i = 0; i < NSUBEXP; ++i)
8428 {
8429 if (regmatch.endp[i] == NULL)
8430 {
8431 if (list_append_string(rettv->vval.v_list,
8432 (char_u *)"", 0) == FAIL)
8433 break;
8434 }
8435 else if (list_append_string(rettv->vval.v_list,
8436 regmatch.startp[i],
8437 (int)(regmatch.endp[i] - regmatch.startp[i]))
8438 == FAIL)
8439 break;
8440 }
8441 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008442 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008443 {
8444 /* return matched string */
8445 if (l != NULL)
8446 copy_tv(&li->li_tv, rettv);
8447 else
8448 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8449 (int)(regmatch.endp[0] - regmatch.startp[0]));
8450 }
8451 else if (l != NULL)
8452 rettv->vval.v_number = idx;
8453 else
8454 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008455 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008456 rettv->vval.v_number =
8457 (varnumber_T)(regmatch.startp[0] - str);
8458 else
8459 rettv->vval.v_number =
8460 (varnumber_T)(regmatch.endp[0] - str);
8461 rettv->vval.v_number += (varnumber_T)(str - expr);
8462 }
8463 }
8464 vim_regfree(regmatch.regprog);
8465 }
8466
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008467theend:
8468 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008469 /* matchstrpos() without a list: drop the second item. */
8470 listitem_remove(rettv->vval.v_list,
8471 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008472 vim_free(tofree);
8473 p_cpo = save_cpo;
8474}
8475
8476/*
8477 * "match()" function
8478 */
8479 static void
8480f_match(typval_T *argvars, typval_T *rettv)
8481{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008482 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008483}
8484
Bram Moolenaar95e51472018-07-28 16:55:56 +02008485#ifdef FEAT_SEARCH_EXTRA
8486 static int
8487matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8488{
8489 dictitem_T *di;
8490
8491 if (tv->v_type != VAR_DICT)
8492 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008493 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008494 return FAIL;
8495 }
8496
8497 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008498 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008499 (char_u *)"conceal", FALSE);
8500
8501 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8502 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008503 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008504 if (*win == NULL)
8505 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01008506 emsg(_(e_invalwindow));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008507 return FAIL;
8508 }
8509 }
8510
8511 return OK;
8512}
8513#endif
8514
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008515/*
8516 * "matchadd()" function
8517 */
8518 static void
8519f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8520{
8521#ifdef FEAT_SEARCH_EXTRA
8522 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008523 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8524 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008525 int prio = 10; /* default priority */
8526 int id = -1;
8527 int error = FALSE;
8528 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008529 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530
8531 rettv->vval.v_number = -1;
8532
8533 if (grp == NULL || pat == NULL)
8534 return;
8535 if (argvars[2].v_type != VAR_UNKNOWN)
8536 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008537 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008538 if (argvars[3].v_type != VAR_UNKNOWN)
8539 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008540 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008541 if (argvars[4].v_type != VAR_UNKNOWN
8542 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8543 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008544 }
8545 }
8546 if (error == TRUE)
8547 return;
8548 if (id >= 1 && id <= 3)
8549 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008550 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008551 return;
8552 }
8553
Bram Moolenaar95e51472018-07-28 16:55:56 +02008554 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008555 conceal_char);
8556#endif
8557}
8558
8559/*
8560 * "matchaddpos()" function
8561 */
8562 static void
8563f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8564{
8565#ifdef FEAT_SEARCH_EXTRA
8566 char_u buf[NUMBUFLEN];
8567 char_u *group;
8568 int prio = 10;
8569 int id = -1;
8570 int error = FALSE;
8571 list_T *l;
8572 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008573 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008574
8575 rettv->vval.v_number = -1;
8576
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008577 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008578 if (group == NULL)
8579 return;
8580
8581 if (argvars[1].v_type != VAR_LIST)
8582 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008583 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008584 return;
8585 }
8586 l = argvars[1].vval.v_list;
8587 if (l == NULL)
8588 return;
8589
8590 if (argvars[2].v_type != VAR_UNKNOWN)
8591 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008592 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008593 if (argvars[3].v_type != VAR_UNKNOWN)
8594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008595 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008596
8597 if (argvars[4].v_type != VAR_UNKNOWN
8598 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8599 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008600 }
8601 }
8602 if (error == TRUE)
8603 return;
8604
8605 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8606 if (id == 1 || id == 2)
8607 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008608 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008609 return;
8610 }
8611
Bram Moolenaar95e51472018-07-28 16:55:56 +02008612 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008613 conceal_char);
8614#endif
8615}
8616
8617/*
8618 * "matcharg()" function
8619 */
8620 static void
8621f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8622{
8623 if (rettv_list_alloc(rettv) == OK)
8624 {
8625#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008626 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008627 matchitem_T *m;
8628
8629 if (id >= 1 && id <= 3)
8630 {
8631 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8632 {
8633 list_append_string(rettv->vval.v_list,
8634 syn_id2name(m->hlg_id), -1);
8635 list_append_string(rettv->vval.v_list, m->pattern, -1);
8636 }
8637 else
8638 {
8639 list_append_string(rettv->vval.v_list, NULL, -1);
8640 list_append_string(rettv->vval.v_list, NULL, -1);
8641 }
8642 }
8643#endif
8644 }
8645}
8646
8647/*
8648 * "matchdelete()" function
8649 */
8650 static void
8651f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8652{
8653#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01008654 win_T *win = get_optional_window(argvars, 1);
8655
8656 if (win == NULL)
8657 rettv->vval.v_number = -1;
8658 else
8659 rettv->vval.v_number = match_delete(win,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008660 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008661#endif
8662}
8663
8664/*
8665 * "matchend()" function
8666 */
8667 static void
8668f_matchend(typval_T *argvars, typval_T *rettv)
8669{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008670 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671}
8672
8673/*
8674 * "matchlist()" function
8675 */
8676 static void
8677f_matchlist(typval_T *argvars, typval_T *rettv)
8678{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008679 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008680}
8681
8682/*
8683 * "matchstr()" function
8684 */
8685 static void
8686f_matchstr(typval_T *argvars, typval_T *rettv)
8687{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008688 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689}
8690
8691/*
8692 * "matchstrpos()" function
8693 */
8694 static void
8695f_matchstrpos(typval_T *argvars, typval_T *rettv)
8696{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008697 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008698}
8699
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008700 static void
8701max_min(typval_T *argvars, typval_T *rettv, int domax)
8702{
8703 varnumber_T n = 0;
8704 varnumber_T i;
8705 int error = FALSE;
8706
8707 if (argvars[0].v_type == VAR_LIST)
8708 {
8709 list_T *l;
8710 listitem_T *li;
8711
8712 l = argvars[0].vval.v_list;
8713 if (l != NULL)
8714 {
8715 li = l->lv_first;
8716 if (li != NULL)
8717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008718 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008719 for (;;)
8720 {
8721 li = li->li_next;
8722 if (li == NULL)
8723 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008724 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725 if (domax ? i > n : i < n)
8726 n = i;
8727 }
8728 }
8729 }
8730 }
8731 else if (argvars[0].v_type == VAR_DICT)
8732 {
8733 dict_T *d;
8734 int first = TRUE;
8735 hashitem_T *hi;
8736 int todo;
8737
8738 d = argvars[0].vval.v_dict;
8739 if (d != NULL)
8740 {
8741 todo = (int)d->dv_hashtab.ht_used;
8742 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8743 {
8744 if (!HASHITEM_EMPTY(hi))
8745 {
8746 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008747 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008748 if (first)
8749 {
8750 n = i;
8751 first = FALSE;
8752 }
8753 else if (domax ? i > n : i < n)
8754 n = i;
8755 }
8756 }
8757 }
8758 }
8759 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008760 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761 rettv->vval.v_number = error ? 0 : n;
8762}
8763
8764/*
8765 * "max()" function
8766 */
8767 static void
8768f_max(typval_T *argvars, typval_T *rettv)
8769{
8770 max_min(argvars, rettv, TRUE);
8771}
8772
8773/*
8774 * "min()" function
8775 */
8776 static void
8777f_min(typval_T *argvars, typval_T *rettv)
8778{
8779 max_min(argvars, rettv, FALSE);
8780}
8781
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008782/*
8783 * Create the directory in which "dir" is located, and higher levels when
8784 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008785 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008786 */
8787 static int
8788mkdir_recurse(char_u *dir, int prot)
8789{
8790 char_u *p;
8791 char_u *updir;
8792 int r = FAIL;
8793
8794 /* Get end of directory name in "dir".
8795 * We're done when it's "/" or "c:/". */
8796 p = gettail_sep(dir);
8797 if (p <= get_past_head(dir))
8798 return OK;
8799
8800 /* If the directory exists we're done. Otherwise: create it.*/
8801 updir = vim_strnsave(dir, (int)(p - dir));
8802 if (updir == NULL)
8803 return FAIL;
8804 if (mch_isdir(updir))
8805 r = OK;
8806 else if (mkdir_recurse(updir, prot) == OK)
8807 r = vim_mkdir_emsg(updir, prot);
8808 vim_free(updir);
8809 return r;
8810}
8811
8812#ifdef vim_mkdir
8813/*
8814 * "mkdir()" function
8815 */
8816 static void
8817f_mkdir(typval_T *argvars, typval_T *rettv)
8818{
8819 char_u *dir;
8820 char_u buf[NUMBUFLEN];
8821 int prot = 0755;
8822
8823 rettv->vval.v_number = FAIL;
8824 if (check_restricted() || check_secure())
8825 return;
8826
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008827 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008828 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008829 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008830
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008831 if (*gettail(dir) == NUL)
8832 /* remove trailing slashes */
8833 *gettail_sep(dir) = NUL;
8834
8835 if (argvars[1].v_type != VAR_UNKNOWN)
8836 {
8837 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008839 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008840 if (prot == -1)
8841 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008842 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008843 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008844 {
8845 if (mch_isdir(dir))
8846 {
8847 /* With the "p" flag it's OK if the dir already exists. */
8848 rettv->vval.v_number = OK;
8849 return;
8850 }
8851 mkdir_recurse(dir, prot);
8852 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008853 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008854 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008855}
8856#endif
8857
8858/*
8859 * "mode()" function
8860 */
8861 static void
8862f_mode(typval_T *argvars, typval_T *rettv)
8863{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008864 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865
Bram Moolenaar612cc382018-07-29 15:34:26 +02008866 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008867
8868 if (time_for_testing == 93784)
8869 {
8870 /* Testing the two-character code. */
8871 buf[0] = 'x';
8872 buf[1] = '!';
8873 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008874#ifdef FEAT_TERMINAL
8875 else if (term_use_loop())
8876 buf[0] = 't';
8877#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008878 else if (VIsual_active)
8879 {
8880 if (VIsual_select)
8881 buf[0] = VIsual_mode + 's' - 'v';
8882 else
8883 buf[0] = VIsual_mode;
8884 }
8885 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8886 || State == CONFIRM)
8887 {
8888 buf[0] = 'r';
8889 if (State == ASKMORE)
8890 buf[1] = 'm';
8891 else if (State == CONFIRM)
8892 buf[1] = '?';
8893 }
8894 else if (State == EXTERNCMD)
8895 buf[0] = '!';
8896 else if (State & INSERT)
8897 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008898 if (State & VREPLACE_FLAG)
8899 {
8900 buf[0] = 'R';
8901 buf[1] = 'v';
8902 }
8903 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008904 {
8905 if (State & REPLACE_FLAG)
8906 buf[0] = 'R';
8907 else
8908 buf[0] = 'i';
8909#ifdef FEAT_INS_EXPAND
8910 if (ins_compl_active())
8911 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008912 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008913 buf[1] = 'x';
8914#endif
8915 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008916 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008917 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008918 {
8919 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008920 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008921 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008922 else if (exmode_active == EXMODE_NORMAL)
8923 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008924 }
8925 else
8926 {
8927 buf[0] = 'n';
8928 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008929 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008930 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008931 // to be able to detect force-linewise/blockwise/characterwise operations
8932 buf[2] = motion_force;
8933 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008934 else if (restart_edit == 'I' || restart_edit == 'R'
8935 || restart_edit == 'V')
8936 {
8937 buf[1] = 'i';
8938 buf[2] = restart_edit;
8939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008940 }
8941
8942 /* Clear out the minor mode when the argument is not a non-zero number or
8943 * non-empty string. */
8944 if (!non_zero_arg(&argvars[0]))
8945 buf[1] = NUL;
8946
8947 rettv->vval.v_string = vim_strsave(buf);
8948 rettv->v_type = VAR_STRING;
8949}
8950
8951#if defined(FEAT_MZSCHEME) || defined(PROTO)
8952/*
8953 * "mzeval()" function
8954 */
8955 static void
8956f_mzeval(typval_T *argvars, typval_T *rettv)
8957{
8958 char_u *str;
8959 char_u buf[NUMBUFLEN];
8960
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008961 if (check_restricted() || check_secure())
8962 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008963 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008964 do_mzeval(str, rettv);
8965}
8966
8967 void
8968mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8969{
8970 typval_T argvars[3];
8971
8972 argvars[0].v_type = VAR_STRING;
8973 argvars[0].vval.v_string = name;
8974 copy_tv(args, &argvars[1]);
8975 argvars[2].v_type = VAR_UNKNOWN;
8976 f_call(argvars, rettv);
8977 clear_tv(&argvars[1]);
8978}
8979#endif
8980
8981/*
8982 * "nextnonblank()" function
8983 */
8984 static void
8985f_nextnonblank(typval_T *argvars, typval_T *rettv)
8986{
8987 linenr_T lnum;
8988
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008989 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008990 {
8991 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8992 {
8993 lnum = 0;
8994 break;
8995 }
8996 if (*skipwhite(ml_get(lnum)) != NUL)
8997 break;
8998 }
8999 rettv->vval.v_number = lnum;
9000}
9001
9002/*
9003 * "nr2char()" function
9004 */
9005 static void
9006f_nr2char(typval_T *argvars, typval_T *rettv)
9007{
9008 char_u buf[NUMBUFLEN];
9009
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009010 if (has_mbyte)
9011 {
9012 int utf8 = 0;
9013
9014 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009015 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009016 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01009017 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009018 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009019 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009020 }
9021 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009022 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009023 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009024 buf[1] = NUL;
9025 }
9026 rettv->v_type = VAR_STRING;
9027 rettv->vval.v_string = vim_strsave(buf);
9028}
9029
9030/*
9031 * "or(expr, expr)" function
9032 */
9033 static void
9034f_or(typval_T *argvars, typval_T *rettv)
9035{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009036 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9037 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009038}
9039
9040/*
9041 * "pathshorten()" function
9042 */
9043 static void
9044f_pathshorten(typval_T *argvars, typval_T *rettv)
9045{
9046 char_u *p;
9047
9048 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009049 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009050 if (p == NULL)
9051 rettv->vval.v_string = NULL;
9052 else
9053 {
9054 p = vim_strsave(p);
9055 rettv->vval.v_string = p;
9056 if (p != NULL)
9057 shorten_dir(p);
9058 }
9059}
9060
9061#ifdef FEAT_PERL
9062/*
9063 * "perleval()" function
9064 */
9065 static void
9066f_perleval(typval_T *argvars, typval_T *rettv)
9067{
9068 char_u *str;
9069 char_u buf[NUMBUFLEN];
9070
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009071 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009072 do_perleval(str, rettv);
9073}
9074#endif
9075
9076#ifdef FEAT_FLOAT
9077/*
9078 * "pow()" function
9079 */
9080 static void
9081f_pow(typval_T *argvars, typval_T *rettv)
9082{
9083 float_T fx = 0.0, fy = 0.0;
9084
9085 rettv->v_type = VAR_FLOAT;
9086 if (get_float_arg(argvars, &fx) == OK
9087 && get_float_arg(&argvars[1], &fy) == OK)
9088 rettv->vval.v_float = pow(fx, fy);
9089 else
9090 rettv->vval.v_float = 0.0;
9091}
9092#endif
9093
9094/*
9095 * "prevnonblank()" function
9096 */
9097 static void
9098f_prevnonblank(typval_T *argvars, typval_T *rettv)
9099{
9100 linenr_T lnum;
9101
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009102 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009103 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
9104 lnum = 0;
9105 else
9106 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
9107 --lnum;
9108 rettv->vval.v_number = lnum;
9109}
9110
9111/* This dummy va_list is here because:
9112 * - passing a NULL pointer doesn't work when va_list isn't a pointer
9113 * - locally in the function results in a "used before set" warning
9114 * - using va_start() to initialize it gives "function with fixed args" error */
9115static va_list ap;
9116
9117/*
9118 * "printf()" function
9119 */
9120 static void
9121f_printf(typval_T *argvars, typval_T *rettv)
9122{
9123 char_u buf[NUMBUFLEN];
9124 int len;
9125 char_u *s;
9126 int saved_did_emsg = did_emsg;
9127 char *fmt;
9128
9129 rettv->v_type = VAR_STRING;
9130 rettv->vval.v_string = NULL;
9131
9132 /* Get the required length, allocate the buffer and do it for real. */
9133 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009134 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02009135 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009136 if (!did_emsg)
9137 {
9138 s = alloc(len + 1);
9139 if (s != NULL)
9140 {
9141 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02009142 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
9143 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009144 }
9145 }
9146 did_emsg |= saved_did_emsg;
9147}
9148
Bram Moolenaarf2732452018-06-03 14:47:35 +02009149#ifdef FEAT_JOB_CHANNEL
9150/*
9151 * "prompt_setcallback({buffer}, {callback})" function
9152 */
9153 static void
9154f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
9155{
9156 buf_T *buf;
9157 char_u *callback;
9158 partial_T *partial;
9159
9160 if (check_secure())
9161 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009162 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02009163 if (buf == NULL)
9164 return;
9165
9166 callback = get_callback(&argvars[1], &partial);
9167 if (callback == NULL)
9168 return;
9169
9170 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
9171 if (partial == NULL)
9172 buf->b_prompt_callback = vim_strsave(callback);
9173 else
9174 /* pointer into the partial */
9175 buf->b_prompt_callback = callback;
9176 buf->b_prompt_partial = partial;
9177}
9178
9179/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02009180 * "prompt_setinterrupt({buffer}, {callback})" function
9181 */
9182 static void
9183f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
9184{
9185 buf_T *buf;
9186 char_u *callback;
9187 partial_T *partial;
9188
9189 if (check_secure())
9190 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009191 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02009192 if (buf == NULL)
9193 return;
9194
9195 callback = get_callback(&argvars[1], &partial);
9196 if (callback == NULL)
9197 return;
9198
9199 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
9200 if (partial == NULL)
9201 buf->b_prompt_interrupt = vim_strsave(callback);
9202 else
9203 /* pointer into the partial */
9204 buf->b_prompt_interrupt = callback;
9205 buf->b_prompt_int_partial = partial;
9206}
9207
9208/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02009209 * "prompt_setprompt({buffer}, {text})" function
9210 */
9211 static void
9212f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
9213{
9214 buf_T *buf;
9215 char_u *text;
9216
9217 if (check_secure())
9218 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009219 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02009220 if (buf == NULL)
9221 return;
9222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009223 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02009224 vim_free(buf->b_prompt_text);
9225 buf->b_prompt_text = vim_strsave(text);
9226}
9227#endif
9228
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009229/*
9230 * "pumvisible()" function
9231 */
9232 static void
9233f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9234{
9235#ifdef FEAT_INS_EXPAND
9236 if (pum_visible())
9237 rettv->vval.v_number = 1;
9238#endif
9239}
9240
9241#ifdef FEAT_PYTHON3
9242/*
9243 * "py3eval()" function
9244 */
9245 static void
9246f_py3eval(typval_T *argvars, typval_T *rettv)
9247{
9248 char_u *str;
9249 char_u buf[NUMBUFLEN];
9250
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009251 if (check_restricted() || check_secure())
9252 return;
9253
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009254 if (p_pyx == 0)
9255 p_pyx = 3;
9256
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009257 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009258 do_py3eval(str, rettv);
9259}
9260#endif
9261
9262#ifdef FEAT_PYTHON
9263/*
9264 * "pyeval()" function
9265 */
9266 static void
9267f_pyeval(typval_T *argvars, typval_T *rettv)
9268{
9269 char_u *str;
9270 char_u buf[NUMBUFLEN];
9271
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009272 if (check_restricted() || check_secure())
9273 return;
9274
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009275 if (p_pyx == 0)
9276 p_pyx = 2;
9277
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009278 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009279 do_pyeval(str, rettv);
9280}
9281#endif
9282
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009283#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9284/*
9285 * "pyxeval()" function
9286 */
9287 static void
9288f_pyxeval(typval_T *argvars, typval_T *rettv)
9289{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009290 if (check_restricted() || check_secure())
9291 return;
9292
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009293# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9294 init_pyxversion();
9295 if (p_pyx == 2)
9296 f_pyeval(argvars, rettv);
9297 else
9298 f_py3eval(argvars, rettv);
9299# elif defined(FEAT_PYTHON)
9300 f_pyeval(argvars, rettv);
9301# elif defined(FEAT_PYTHON3)
9302 f_py3eval(argvars, rettv);
9303# endif
9304}
9305#endif
9306
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009307/*
9308 * "range()" function
9309 */
9310 static void
9311f_range(typval_T *argvars, typval_T *rettv)
9312{
9313 varnumber_T start;
9314 varnumber_T end;
9315 varnumber_T stride = 1;
9316 varnumber_T i;
9317 int error = FALSE;
9318
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009319 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009320 if (argvars[1].v_type == VAR_UNKNOWN)
9321 {
9322 end = start - 1;
9323 start = 0;
9324 }
9325 else
9326 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009327 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009328 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009329 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009330 }
9331
9332 if (error)
9333 return; /* type error; errmsg already given */
9334 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009335 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009337 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009338 else
9339 {
9340 if (rettv_list_alloc(rettv) == OK)
9341 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9342 if (list_append_number(rettv->vval.v_list,
9343 (varnumber_T)i) == FAIL)
9344 break;
9345 }
9346}
9347
9348/*
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009349 * Evaluate "expr" for readdir().
9350 */
9351 static int
9352readdir_checkitem(typval_T *expr, char_u *name)
9353{
9354 typval_T save_val;
9355 typval_T rettv;
9356 typval_T argv[2];
9357 int retval = 0;
9358 int error = FALSE;
9359
9360 prepare_vimvar(VV_VAL, &save_val);
9361 set_vim_var_string(VV_VAL, name, -1);
9362 argv[0].v_type = VAR_STRING;
9363 argv[0].vval.v_string = name;
9364
9365 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
9366 goto theend;
9367
9368 retval = tv_get_number_chk(&rettv, &error);
9369 if (error)
9370 retval = -1;
9371 clear_tv(&rettv);
9372
9373theend:
9374 set_vim_var_string(VV_VAL, NULL, 0);
9375 restore_vimvar(VV_VAL, &save_val);
9376 return retval;
9377}
9378
9379/*
9380 * "readdir()" function
9381 */
9382 static void
9383f_readdir(typval_T *argvars, typval_T *rettv)
9384{
9385 typval_T *expr;
9386 int failed = FALSE;
9387 char_u *path;
9388 garray_T ga;
9389 int i;
9390#ifdef MSWIN
9391 char_u *buf, *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009392 int ok;
9393 HANDLE hFind = INVALID_HANDLE_VALUE;
9394 WIN32_FIND_DATAW wfb;
9395 WCHAR *wn = NULL; // UCS-2 name, NULL when not used.
9396#endif
9397
9398 if (rettv_list_alloc(rettv) == FAIL)
9399 return;
9400 path = tv_get_string(&argvars[0]);
9401 expr = &argvars[1];
9402 ga_init2(&ga, (int)sizeof(char *), 20);
9403
9404#ifdef MSWIN
9405 buf = alloc((int)MAXPATHL);
9406 if (buf == NULL)
9407 return;
9408 STRNCPY(buf, path, MAXPATHL-5);
9409 p = vim_strpbrk(path, (char_u *)"\\/");
9410 if (p != NULL)
9411 *p = NUL;
9412 STRCAT(buf, "\\*");
9413
9414 wn = enc_to_utf16(buf, NULL);
9415 if (wn != NULL)
9416 hFind = FindFirstFileW(wn, &wfb);
9417 ok = (hFind != INVALID_HANDLE_VALUE);
9418 if (!ok)
9419 smsg(_(e_notopen), path);
9420 else
9421 {
9422 while (ok)
9423 {
9424 int ignore;
9425
9426 p = utf16_to_enc(wfb.cFileName, NULL); // p is allocated here
9427 if (p == NULL)
9428 break; // out of memory
9429
9430 ignore = p[0] == '.' && (p[1] == NUL
9431 || (p[1] == '.' && p[2] == NUL));
9432 if (!ignore && expr->v_type != VAR_UNKNOWN)
9433 {
9434 int r = readdir_checkitem(expr, p);
9435
9436 if (r < 0)
9437 {
9438 vim_free(p);
9439 break;
9440 }
9441 if (r == 0)
9442 ignore = TRUE;
9443 }
9444
9445 if (!ignore)
9446 {
9447 if (ga_grow(&ga, 1) == OK)
9448 ((char_u**)ga.ga_data)[ga.ga_len++] = vim_strsave(p);
9449 else
9450 {
9451 failed = TRUE;
9452 vim_free(p);
9453 break;
9454 }
9455 }
9456
9457 vim_free(p);
9458 ok = FindNextFileW(hFind, &wfb);
9459 }
9460 FindClose(hFind);
9461 }
9462
9463 vim_free(buf);
9464 vim_free(wn);
9465#else
9466 DIR *dirp;
9467 struct dirent *dp;
9468 char_u *p;
9469
9470 dirp = opendir((char *)path);
9471 if (dirp == NULL)
9472 smsg(_(e_notopen), path);
9473 else
9474 {
9475 for (;;)
9476 {
9477 int ignore;
9478
9479 dp = readdir(dirp);
9480 if (dp == NULL)
9481 break;
9482 p = (char_u *)dp->d_name;
9483
9484 ignore = p[0] == '.' &&
9485 (p[1] == NUL ||
9486 (p[1] == '.' && p[2] == NUL));
9487 if (!ignore && expr->v_type != VAR_UNKNOWN)
9488 {
9489 int r = readdir_checkitem(expr, p);
9490
9491 if (r < 0)
9492 break;
9493 if (r == 0)
9494 ignore = TRUE;
9495 }
9496
9497 if (!ignore)
9498 {
9499 if (ga_grow(&ga, 1) == OK)
9500 ((char_u**)ga.ga_data)[ga.ga_len++] = vim_strsave(p);
9501 else
9502 {
9503 failed = TRUE;
9504 break;
9505 }
9506 }
9507 }
9508
9509 closedir(dirp);
9510 }
9511#endif
9512
Bram Moolenaar334ad412019-04-19 15:20:46 +02009513 if (!failed && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009514 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009515 sort_strings((char_u **)ga.ga_data, ga.ga_len);
9516 for (i = 0; i < ga.ga_len; i++)
9517 {
9518 p = ((char_u **)ga.ga_data)[i];
9519 list_append_string(rettv->vval.v_list, p, -1);
9520 }
9521 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02009522 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009523}
9524
9525/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009526 * "readfile()" function
9527 */
9528 static void
9529f_readfile(typval_T *argvars, typval_T *rettv)
9530{
9531 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009532 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009533 int failed = FALSE;
9534 char_u *fname;
9535 FILE *fd;
9536 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9537 int io_size = sizeof(buf);
9538 int readlen; /* size of last fread() */
9539 char_u *prev = NULL; /* previously read bytes, if any */
9540 long prevlen = 0; /* length of data in prev */
9541 long prevsize = 0; /* size of prev buffer */
9542 long maxline = MAXLNUM;
9543 long cnt = 0;
9544 char_u *p; /* position in buf */
9545 char_u *start; /* start of current line */
9546
9547 if (argvars[1].v_type != VAR_UNKNOWN)
9548 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009549 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009550 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009551 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9552 blob = TRUE;
9553
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009554 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009555 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009556 }
9557
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009558 if (blob)
9559 {
9560 if (rettv_blob_alloc(rettv) == FAIL)
9561 return;
9562 }
9563 else
9564 {
9565 if (rettv_list_alloc(rettv) == FAIL)
9566 return;
9567 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009568
9569 /* Always open the file in binary mode, library functions have a mind of
9570 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009571 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009572 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9573 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009574 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009575 return;
9576 }
9577
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009578 if (blob)
9579 {
9580 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9581 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009582 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009583 blob_free(rettv->vval.v_blob);
9584 }
9585 fclose(fd);
9586 return;
9587 }
9588
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009589 while (cnt < maxline || maxline < 0)
9590 {
9591 readlen = (int)fread(buf, 1, io_size, fd);
9592
9593 /* This for loop processes what was read, but is also entered at end
9594 * of file so that either:
9595 * - an incomplete line gets written
9596 * - a "binary" file gets an empty line at the end if it ends in a
9597 * newline. */
9598 for (p = buf, start = buf;
9599 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9600 ++p)
9601 {
9602 if (*p == '\n' || readlen <= 0)
9603 {
9604 listitem_T *li;
9605 char_u *s = NULL;
9606 long_u len = p - start;
9607
9608 /* Finished a line. Remove CRs before NL. */
9609 if (readlen > 0 && !binary)
9610 {
9611 while (len > 0 && start[len - 1] == '\r')
9612 --len;
9613 /* removal may cross back to the "prev" string */
9614 if (len == 0)
9615 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9616 --prevlen;
9617 }
9618 if (prevlen == 0)
9619 s = vim_strnsave(start, (int)len);
9620 else
9621 {
9622 /* Change "prev" buffer to be the right size. This way
9623 * the bytes are only copied once, and very long lines are
9624 * allocated only once. */
9625 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9626 {
9627 mch_memmove(s + prevlen, start, len);
9628 s[prevlen + len] = NUL;
9629 prev = NULL; /* the list will own the string */
9630 prevlen = prevsize = 0;
9631 }
9632 }
9633 if (s == NULL)
9634 {
9635 do_outofmem_msg((long_u) prevlen + len + 1);
9636 failed = TRUE;
9637 break;
9638 }
9639
9640 if ((li = listitem_alloc()) == NULL)
9641 {
9642 vim_free(s);
9643 failed = TRUE;
9644 break;
9645 }
9646 li->li_tv.v_type = VAR_STRING;
9647 li->li_tv.v_lock = 0;
9648 li->li_tv.vval.v_string = s;
9649 list_append(rettv->vval.v_list, li);
9650
9651 start = p + 1; /* step over newline */
9652 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9653 break;
9654 }
9655 else if (*p == NUL)
9656 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009657 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9658 * when finding the BF and check the previous two bytes. */
9659 else if (*p == 0xbf && enc_utf8 && !binary)
9660 {
9661 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9662 * + 1, these may be in the "prev" string. */
9663 char_u back1 = p >= buf + 1 ? p[-1]
9664 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9665 char_u back2 = p >= buf + 2 ? p[-2]
9666 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9667 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9668
9669 if (back2 == 0xef && back1 == 0xbb)
9670 {
9671 char_u *dest = p - 2;
9672
9673 /* Usually a BOM is at the beginning of a file, and so at
9674 * the beginning of a line; then we can just step over it.
9675 */
9676 if (start == dest)
9677 start = p + 1;
9678 else
9679 {
9680 /* have to shuffle buf to close gap */
9681 int adjust_prevlen = 0;
9682
9683 if (dest < buf)
9684 {
9685 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9686 dest = buf;
9687 }
9688 if (readlen > p - buf + 1)
9689 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9690 readlen -= 3 - adjust_prevlen;
9691 prevlen -= adjust_prevlen;
9692 p = dest - 1;
9693 }
9694 }
9695 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009696 } /* for */
9697
9698 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9699 break;
9700 if (start < p)
9701 {
9702 /* There's part of a line in buf, store it in "prev". */
9703 if (p - start + prevlen >= prevsize)
9704 {
9705 /* need bigger "prev" buffer */
9706 char_u *newprev;
9707
9708 /* A common use case is ordinary text files and "prev" gets a
9709 * fragment of a line, so the first allocation is made
9710 * small, to avoid repeatedly 'allocing' large and
9711 * 'reallocing' small. */
9712 if (prevsize == 0)
9713 prevsize = (long)(p - start);
9714 else
9715 {
9716 long grow50pc = (prevsize * 3) / 2;
9717 long growmin = (long)((p - start) * 2 + prevlen);
9718 prevsize = grow50pc > growmin ? grow50pc : growmin;
9719 }
9720 newprev = prev == NULL ? alloc(prevsize)
9721 : vim_realloc(prev, prevsize);
9722 if (newprev == NULL)
9723 {
9724 do_outofmem_msg((long_u)prevsize);
9725 failed = TRUE;
9726 break;
9727 }
9728 prev = newprev;
9729 }
9730 /* Add the line part to end of "prev". */
9731 mch_memmove(prev + prevlen, start, p - start);
9732 prevlen += (long)(p - start);
9733 }
9734 } /* while */
9735
9736 /*
9737 * For a negative line count use only the lines at the end of the file,
9738 * free the rest.
9739 */
9740 if (!failed && maxline < 0)
9741 while (cnt > -maxline)
9742 {
9743 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9744 --cnt;
9745 }
9746
9747 if (failed)
9748 {
9749 list_free(rettv->vval.v_list);
9750 /* readfile doc says an empty list is returned on error */
9751 rettv->vval.v_list = list_alloc();
9752 }
9753
9754 vim_free(prev);
9755 fclose(fd);
9756}
9757
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009758 static void
9759return_register(int regname, typval_T *rettv)
9760{
9761 char_u buf[2] = {0, 0};
9762
9763 buf[0] = (char_u)regname;
9764 rettv->v_type = VAR_STRING;
9765 rettv->vval.v_string = vim_strsave(buf);
9766}
9767
9768/*
9769 * "reg_executing()" function
9770 */
9771 static void
9772f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9773{
9774 return_register(reg_executing, rettv);
9775}
9776
9777/*
9778 * "reg_recording()" function
9779 */
9780 static void
9781f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9782{
9783 return_register(reg_recording, rettv);
9784}
9785
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009786#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009787/*
9788 * Convert a List to proftime_T.
9789 * Return FAIL when there is something wrong.
9790 */
9791 static int
9792list2proftime(typval_T *arg, proftime_T *tm)
9793{
9794 long n1, n2;
9795 int error = FALSE;
9796
9797 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9798 || arg->vval.v_list->lv_len != 2)
9799 return FAIL;
9800 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9801 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009802# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009803 tm->HighPart = n1;
9804 tm->LowPart = n2;
9805# else
9806 tm->tv_sec = n1;
9807 tm->tv_usec = n2;
9808# endif
9809 return error ? FAIL : OK;
9810}
9811#endif /* FEAT_RELTIME */
9812
9813/*
9814 * "reltime()" function
9815 */
9816 static void
9817f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9818{
9819#ifdef FEAT_RELTIME
9820 proftime_T res;
9821 proftime_T start;
9822
9823 if (argvars[0].v_type == VAR_UNKNOWN)
9824 {
9825 /* No arguments: get current time. */
9826 profile_start(&res);
9827 }
9828 else if (argvars[1].v_type == VAR_UNKNOWN)
9829 {
9830 if (list2proftime(&argvars[0], &res) == FAIL)
9831 return;
9832 profile_end(&res);
9833 }
9834 else
9835 {
9836 /* Two arguments: compute the difference. */
9837 if (list2proftime(&argvars[0], &start) == FAIL
9838 || list2proftime(&argvars[1], &res) == FAIL)
9839 return;
9840 profile_sub(&res, &start);
9841 }
9842
9843 if (rettv_list_alloc(rettv) == OK)
9844 {
9845 long n1, n2;
9846
Bram Moolenaar4f974752019-02-17 17:44:42 +01009847# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009848 n1 = res.HighPart;
9849 n2 = res.LowPart;
9850# else
9851 n1 = res.tv_sec;
9852 n2 = res.tv_usec;
9853# endif
9854 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9855 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9856 }
9857#endif
9858}
9859
9860#ifdef FEAT_FLOAT
9861/*
9862 * "reltimefloat()" function
9863 */
9864 static void
9865f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9866{
9867# ifdef FEAT_RELTIME
9868 proftime_T tm;
9869# endif
9870
9871 rettv->v_type = VAR_FLOAT;
9872 rettv->vval.v_float = 0;
9873# ifdef FEAT_RELTIME
9874 if (list2proftime(&argvars[0], &tm) == OK)
9875 rettv->vval.v_float = profile_float(&tm);
9876# endif
9877}
9878#endif
9879
9880/*
9881 * "reltimestr()" function
9882 */
9883 static void
9884f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9885{
9886#ifdef FEAT_RELTIME
9887 proftime_T tm;
9888#endif
9889
9890 rettv->v_type = VAR_STRING;
9891 rettv->vval.v_string = NULL;
9892#ifdef FEAT_RELTIME
9893 if (list2proftime(&argvars[0], &tm) == OK)
9894 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9895#endif
9896}
9897
9898#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009899 static void
9900make_connection(void)
9901{
9902 if (X_DISPLAY == NULL
9903# ifdef FEAT_GUI
9904 && !gui.in_use
9905# endif
9906 )
9907 {
9908 x_force_connect = TRUE;
9909 setup_term_clip();
9910 x_force_connect = FALSE;
9911 }
9912}
9913
9914 static int
9915check_connection(void)
9916{
9917 make_connection();
9918 if (X_DISPLAY == NULL)
9919 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009920 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009921 return FAIL;
9922 }
9923 return OK;
9924}
9925#endif
9926
9927#ifdef FEAT_CLIENTSERVER
9928 static void
9929remote_common(typval_T *argvars, typval_T *rettv, int expr)
9930{
9931 char_u *server_name;
9932 char_u *keys;
9933 char_u *r = NULL;
9934 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009935 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009936# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009937 HWND w;
9938# else
9939 Window w;
9940# endif
9941
9942 if (check_restricted() || check_secure())
9943 return;
9944
9945# ifdef FEAT_X11
9946 if (check_connection() == FAIL)
9947 return;
9948# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009949 if (argvars[2].v_type != VAR_UNKNOWN
9950 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009951 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009952
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009953 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009954 if (server_name == NULL)
9955 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009956 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009957# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009958 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009959# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009960 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9961 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009962# endif
9963 {
9964 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009965 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009966 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009967 vim_free(r);
9968 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009969 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009970 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009971 return;
9972 }
9973
9974 rettv->vval.v_string = r;
9975
9976 if (argvars[2].v_type != VAR_UNKNOWN)
9977 {
9978 dictitem_T v;
9979 char_u str[30];
9980 char_u *idvar;
9981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009982 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009983 if (idvar != NULL && *idvar != NUL)
9984 {
9985 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9986 v.di_tv.v_type = VAR_STRING;
9987 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009988 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009989 vim_free(v.di_tv.vval.v_string);
9990 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009991 }
9992}
9993#endif
9994
9995/*
9996 * "remote_expr()" function
9997 */
9998 static void
9999f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
10000{
10001 rettv->v_type = VAR_STRING;
10002 rettv->vval.v_string = NULL;
10003#ifdef FEAT_CLIENTSERVER
10004 remote_common(argvars, rettv, TRUE);
10005#endif
10006}
10007
10008/*
10009 * "remote_foreground()" function
10010 */
10011 static void
10012f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10013{
10014#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010015# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010016 /* On Win32 it's done in this application. */
10017 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010018 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019
10020 if (server_name != NULL)
10021 serverForeground(server_name);
10022 }
10023# else
10024 /* Send a foreground() expression to the server. */
10025 argvars[1].v_type = VAR_STRING;
10026 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
10027 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +020010028 rettv->v_type = VAR_STRING;
10029 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010030 remote_common(argvars, rettv, TRUE);
10031 vim_free(argvars[1].vval.v_string);
10032# endif
10033#endif
10034}
10035
10036 static void
10037f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
10038{
10039#ifdef FEAT_CLIENTSERVER
10040 dictitem_T v;
10041 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +010010042# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010043 long_u n = 0;
10044# endif
10045 char_u *serverid;
10046
10047 if (check_restricted() || check_secure())
10048 {
10049 rettv->vval.v_number = -1;
10050 return;
10051 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010052 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010053 if (serverid == NULL)
10054 {
10055 rettv->vval.v_number = -1;
10056 return; /* type error; errmsg already given */
10057 }
Bram Moolenaar4f974752019-02-17 17:44:42 +010010058# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010059 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
10060 if (n == 0)
10061 rettv->vval.v_number = -1;
10062 else
10063 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010064 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010065 rettv->vval.v_number = (s != NULL);
10066 }
10067# else
10068 if (check_connection() == FAIL)
10069 return;
10070
10071 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
10072 serverStrToWin(serverid), &s);
10073# endif
10074
10075 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
10076 {
10077 char_u *retvar;
10078
10079 v.di_tv.v_type = VAR_STRING;
10080 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010081 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010082 if (retvar != NULL)
10083 set_var(retvar, &v.di_tv, FALSE);
10084 vim_free(v.di_tv.vval.v_string);
10085 }
10086#else
10087 rettv->vval.v_number = -1;
10088#endif
10089}
10090
10091 static void
10092f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
10093{
10094 char_u *r = NULL;
10095
10096#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010097 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010098
10099 if (serverid != NULL && !check_restricted() && !check_secure())
10100 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010101 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +010010102# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +010010103 /* The server's HWND is encoded in the 'id' parameter */
10104 long_u n = 0;
10105# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010106
10107 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010108 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010109
Bram Moolenaar4f974752019-02-17 17:44:42 +010010110# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010111 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
10112 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010113 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010114 if (r == NULL)
10115# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +010010116 if (check_connection() == FAIL
10117 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
10118 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010119# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010120 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010121 }
10122#endif
10123 rettv->v_type = VAR_STRING;
10124 rettv->vval.v_string = r;
10125}
10126
10127/*
10128 * "remote_send()" function
10129 */
10130 static void
10131f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
10132{
10133 rettv->v_type = VAR_STRING;
10134 rettv->vval.v_string = NULL;
10135#ifdef FEAT_CLIENTSERVER
10136 remote_common(argvars, rettv, FALSE);
10137#endif
10138}
10139
10140/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010141 * "remote_startserver()" function
10142 */
10143 static void
10144f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10145{
10146#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010147 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010148
10149 if (server == NULL)
10150 return; /* type error; errmsg already given */
10151 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010152 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010153 else
10154 {
10155# ifdef FEAT_X11
10156 if (check_connection() == OK)
10157 serverRegisterName(X_DISPLAY, server);
10158# else
10159 serverSetName(server);
10160# endif
10161 }
10162#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010163 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +010010164#endif
10165}
10166
10167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010168 * "remove()" function
10169 */
10170 static void
10171f_remove(typval_T *argvars, typval_T *rettv)
10172{
10173 list_T *l;
10174 listitem_T *item, *item2;
10175 listitem_T *li;
10176 long idx;
10177 long end;
10178 char_u *key;
10179 dict_T *d;
10180 dictitem_T *di;
10181 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010182 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010183
10184 if (argvars[0].v_type == VAR_DICT)
10185 {
10186 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010187 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010188 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010189 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010191 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010192 if (key != NULL)
10193 {
10194 di = dict_find(d, key, -1);
10195 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010196 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010197 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
10198 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
10199 {
10200 *rettv = di->di_tv;
10201 init_tv(&di->di_tv);
10202 dictitem_remove(d, di);
10203 }
10204 }
10205 }
10206 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010207 else if (argvars[0].v_type == VAR_BLOB)
10208 {
10209 idx = (long)tv_get_number_chk(&argvars[1], &error);
10210 if (!error)
10211 {
10212 blob_T *b = argvars[0].vval.v_blob;
10213 int len = blob_len(b);
10214 char_u *p;
10215
10216 if (idx < 0)
10217 // count from the end
10218 idx = len + idx;
10219 if (idx < 0 || idx >= len)
10220 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010221 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010222 return;
10223 }
10224 if (argvars[2].v_type == VAR_UNKNOWN)
10225 {
10226 // Remove one item, return its value.
10227 p = (char_u *)b->bv_ga.ga_data;
10228 rettv->vval.v_number = (varnumber_T) *(p + idx);
10229 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
10230 --b->bv_ga.ga_len;
10231 }
10232 else
10233 {
10234 blob_T *blob;
10235
10236 // Remove range of items, return list with values.
10237 end = (long)tv_get_number_chk(&argvars[2], &error);
10238 if (error)
10239 return;
10240 if (end < 0)
10241 // count from the end
10242 end = len + end;
10243 if (end >= len || idx > end)
10244 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010245 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010246 return;
10247 }
10248 blob = blob_alloc();
10249 if (blob == NULL)
10250 return;
10251 blob->bv_ga.ga_len = end - idx + 1;
10252 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
10253 {
10254 vim_free(blob);
10255 return;
10256 }
10257 p = (char_u *)b->bv_ga.ga_data;
10258 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
10259 (size_t)(end - idx + 1));
10260 ++blob->bv_refcount;
10261 rettv->v_type = VAR_BLOB;
10262 rettv->vval.v_blob = blob;
10263
10264 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
10265 b->bv_ga.ga_len -= end - idx + 1;
10266 }
10267 }
10268 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010269 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010270 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010272 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010274 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010276 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010277 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010278 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010279 else
10280 {
10281 if (argvars[2].v_type == VAR_UNKNOWN)
10282 {
10283 /* Remove one item, return its value. */
10284 vimlist_remove(l, item, item);
10285 *rettv = item->li_tv;
10286 vim_free(item);
10287 }
10288 else
10289 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010290 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010291 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010292 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010293 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010294 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010295 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 else
10297 {
10298 int cnt = 0;
10299
10300 for (li = item; li != NULL; li = li->li_next)
10301 {
10302 ++cnt;
10303 if (li == item2)
10304 break;
10305 }
10306 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010307 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010308 else
10309 {
10310 vimlist_remove(l, item, item2);
10311 if (rettv_list_alloc(rettv) == OK)
10312 {
10313 l = rettv->vval.v_list;
10314 l->lv_first = item;
10315 l->lv_last = item2;
10316 item->li_prev = NULL;
10317 item2->li_next = NULL;
10318 l->lv_len = cnt;
10319 }
10320 }
10321 }
10322 }
10323 }
10324 }
10325}
10326
10327/*
10328 * "rename({from}, {to})" function
10329 */
10330 static void
10331f_rename(typval_T *argvars, typval_T *rettv)
10332{
10333 char_u buf[NUMBUFLEN];
10334
10335 if (check_restricted() || check_secure())
10336 rettv->vval.v_number = -1;
10337 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010338 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
10339 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010340}
10341
10342/*
10343 * "repeat()" function
10344 */
10345 static void
10346f_repeat(typval_T *argvars, typval_T *rettv)
10347{
10348 char_u *p;
10349 int n;
10350 int slen;
10351 int len;
10352 char_u *r;
10353 int i;
10354
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010355 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010356 if (argvars[0].v_type == VAR_LIST)
10357 {
10358 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
10359 while (n-- > 0)
10360 if (list_extend(rettv->vval.v_list,
10361 argvars[0].vval.v_list, NULL) == FAIL)
10362 break;
10363 }
10364 else
10365 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010366 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010367 rettv->v_type = VAR_STRING;
10368 rettv->vval.v_string = NULL;
10369
10370 slen = (int)STRLEN(p);
10371 len = slen * n;
10372 if (len <= 0)
10373 return;
10374
10375 r = alloc(len + 1);
10376 if (r != NULL)
10377 {
10378 for (i = 0; i < n; i++)
10379 mch_memmove(r + i * slen, p, (size_t)slen);
10380 r[len] = NUL;
10381 }
10382
10383 rettv->vval.v_string = r;
10384 }
10385}
10386
10387/*
10388 * "resolve()" function
10389 */
10390 static void
10391f_resolve(typval_T *argvars, typval_T *rettv)
10392{
10393 char_u *p;
10394#ifdef HAVE_READLINK
10395 char_u *buf = NULL;
10396#endif
10397
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010398 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010399#ifdef FEAT_SHORTCUT
10400 {
10401 char_u *v = NULL;
10402
Bram Moolenaardce1e892019-02-10 23:18:53 +010010403 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010404 if (v != NULL)
10405 rettv->vval.v_string = v;
10406 else
10407 rettv->vval.v_string = vim_strsave(p);
10408 }
10409#else
10410# ifdef HAVE_READLINK
10411 {
10412 char_u *cpy;
10413 int len;
10414 char_u *remain = NULL;
10415 char_u *q;
10416 int is_relative_to_current = FALSE;
10417 int has_trailing_pathsep = FALSE;
10418 int limit = 100;
10419
10420 p = vim_strsave(p);
10421
10422 if (p[0] == '.' && (vim_ispathsep(p[1])
10423 || (p[1] == '.' && (vim_ispathsep(p[2])))))
10424 is_relative_to_current = TRUE;
10425
10426 len = STRLEN(p);
10427 if (len > 0 && after_pathsep(p, p + len))
10428 {
10429 has_trailing_pathsep = TRUE;
10430 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
10431 }
10432
10433 q = getnextcomp(p);
10434 if (*q != NUL)
10435 {
10436 /* Separate the first path component in "p", and keep the
10437 * remainder (beginning with the path separator). */
10438 remain = vim_strsave(q - 1);
10439 q[-1] = NUL;
10440 }
10441
10442 buf = alloc(MAXPATHL + 1);
10443 if (buf == NULL)
10444 goto fail;
10445
10446 for (;;)
10447 {
10448 for (;;)
10449 {
10450 len = readlink((char *)p, (char *)buf, MAXPATHL);
10451 if (len <= 0)
10452 break;
10453 buf[len] = NUL;
10454
10455 if (limit-- == 0)
10456 {
10457 vim_free(p);
10458 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010459 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010460 rettv->vval.v_string = NULL;
10461 goto fail;
10462 }
10463
10464 /* Ensure that the result will have a trailing path separator
10465 * if the argument has one. */
10466 if (remain == NULL && has_trailing_pathsep)
10467 add_pathsep(buf);
10468
10469 /* Separate the first path component in the link value and
10470 * concatenate the remainders. */
10471 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10472 if (*q != NUL)
10473 {
10474 if (remain == NULL)
10475 remain = vim_strsave(q - 1);
10476 else
10477 {
10478 cpy = concat_str(q - 1, remain);
10479 if (cpy != NULL)
10480 {
10481 vim_free(remain);
10482 remain = cpy;
10483 }
10484 }
10485 q[-1] = NUL;
10486 }
10487
10488 q = gettail(p);
10489 if (q > p && *q == NUL)
10490 {
10491 /* Ignore trailing path separator. */
10492 q[-1] = NUL;
10493 q = gettail(p);
10494 }
10495 if (q > p && !mch_isFullName(buf))
10496 {
10497 /* symlink is relative to directory of argument */
10498 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10499 if (cpy != NULL)
10500 {
10501 STRCPY(cpy, p);
10502 STRCPY(gettail(cpy), buf);
10503 vim_free(p);
10504 p = cpy;
10505 }
10506 }
10507 else
10508 {
10509 vim_free(p);
10510 p = vim_strsave(buf);
10511 }
10512 }
10513
10514 if (remain == NULL)
10515 break;
10516
10517 /* Append the first path component of "remain" to "p". */
10518 q = getnextcomp(remain + 1);
10519 len = q - remain - (*q != NUL);
10520 cpy = vim_strnsave(p, STRLEN(p) + len);
10521 if (cpy != NULL)
10522 {
10523 STRNCAT(cpy, remain, len);
10524 vim_free(p);
10525 p = cpy;
10526 }
10527 /* Shorten "remain". */
10528 if (*q != NUL)
10529 STRMOVE(remain, q - 1);
10530 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010531 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010532 }
10533
10534 /* If the result is a relative path name, make it explicitly relative to
10535 * the current directory if and only if the argument had this form. */
10536 if (!vim_ispathsep(*p))
10537 {
10538 if (is_relative_to_current
10539 && *p != NUL
10540 && !(p[0] == '.'
10541 && (p[1] == NUL
10542 || vim_ispathsep(p[1])
10543 || (p[1] == '.'
10544 && (p[2] == NUL
10545 || vim_ispathsep(p[2]))))))
10546 {
10547 /* Prepend "./". */
10548 cpy = concat_str((char_u *)"./", p);
10549 if (cpy != NULL)
10550 {
10551 vim_free(p);
10552 p = cpy;
10553 }
10554 }
10555 else if (!is_relative_to_current)
10556 {
10557 /* Strip leading "./". */
10558 q = p;
10559 while (q[0] == '.' && vim_ispathsep(q[1]))
10560 q += 2;
10561 if (q > p)
10562 STRMOVE(p, p + 2);
10563 }
10564 }
10565
10566 /* Ensure that the result will have no trailing path separator
10567 * if the argument had none. But keep "/" or "//". */
10568 if (!has_trailing_pathsep)
10569 {
10570 q = p + STRLEN(p);
10571 if (after_pathsep(p, q))
10572 *gettail_sep(p) = NUL;
10573 }
10574
10575 rettv->vval.v_string = p;
10576 }
10577# else
10578 rettv->vval.v_string = vim_strsave(p);
10579# endif
10580#endif
10581
10582 simplify_filename(rettv->vval.v_string);
10583
10584#ifdef HAVE_READLINK
10585fail:
10586 vim_free(buf);
10587#endif
10588 rettv->v_type = VAR_STRING;
10589}
10590
10591/*
10592 * "reverse({list})" function
10593 */
10594 static void
10595f_reverse(typval_T *argvars, typval_T *rettv)
10596{
10597 list_T *l;
10598 listitem_T *li, *ni;
10599
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010600 if (argvars[0].v_type == VAR_BLOB)
10601 {
10602 blob_T *b = argvars[0].vval.v_blob;
10603 int i, len = blob_len(b);
10604
10605 for (i = 0; i < len / 2; i++)
10606 {
10607 int tmp = blob_get(b, i);
10608
10609 blob_set(b, i, blob_get(b, len - i - 1));
10610 blob_set(b, len - i - 1, tmp);
10611 }
10612 rettv_blob_set(rettv, b);
10613 return;
10614 }
10615
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010616 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010617 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010618 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010619 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010620 (char_u *)N_("reverse() argument"), TRUE))
10621 {
10622 li = l->lv_last;
10623 l->lv_first = l->lv_last = NULL;
10624 l->lv_len = 0;
10625 while (li != NULL)
10626 {
10627 ni = li->li_prev;
10628 list_append(l, li);
10629 li = ni;
10630 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010631 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010632 l->lv_idx = l->lv_len - l->lv_idx - 1;
10633 }
10634}
10635
10636#define SP_NOMOVE 0x01 /* don't move cursor */
10637#define SP_REPEAT 0x02 /* repeat to find outer pair */
10638#define SP_RETCOUNT 0x04 /* return matchcount */
10639#define SP_SETPCMARK 0x08 /* set previous context mark */
10640#define SP_START 0x10 /* accept match at start position */
10641#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10642#define SP_END 0x40 /* leave cursor at end of match */
10643#define SP_COLUMN 0x80 /* start at cursor column */
10644
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010645/*
10646 * Get flags for a search function.
10647 * Possibly sets "p_ws".
10648 * Returns BACKWARD, FORWARD or zero (for an error).
10649 */
10650 static int
10651get_search_arg(typval_T *varp, int *flagsp)
10652{
10653 int dir = FORWARD;
10654 char_u *flags;
10655 char_u nbuf[NUMBUFLEN];
10656 int mask;
10657
10658 if (varp->v_type != VAR_UNKNOWN)
10659 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010660 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010661 if (flags == NULL)
10662 return 0; /* type error; errmsg already given */
10663 while (*flags != NUL)
10664 {
10665 switch (*flags)
10666 {
10667 case 'b': dir = BACKWARD; break;
10668 case 'w': p_ws = TRUE; break;
10669 case 'W': p_ws = FALSE; break;
10670 default: mask = 0;
10671 if (flagsp != NULL)
10672 switch (*flags)
10673 {
10674 case 'c': mask = SP_START; break;
10675 case 'e': mask = SP_END; break;
10676 case 'm': mask = SP_RETCOUNT; break;
10677 case 'n': mask = SP_NOMOVE; break;
10678 case 'p': mask = SP_SUBPAT; break;
10679 case 'r': mask = SP_REPEAT; break;
10680 case 's': mask = SP_SETPCMARK; break;
10681 case 'z': mask = SP_COLUMN; break;
10682 }
10683 if (mask == 0)
10684 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010685 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010686 dir = 0;
10687 }
10688 else
10689 *flagsp |= mask;
10690 }
10691 if (dir == 0)
10692 break;
10693 ++flags;
10694 }
10695 }
10696 return dir;
10697}
10698
10699/*
10700 * Shared by search() and searchpos() functions.
10701 */
10702 static int
10703search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10704{
10705 int flags;
10706 char_u *pat;
10707 pos_T pos;
10708 pos_T save_cursor;
10709 int save_p_ws = p_ws;
10710 int dir;
10711 int retval = 0; /* default: FAIL */
10712 long lnum_stop = 0;
10713 proftime_T tm;
10714#ifdef FEAT_RELTIME
10715 long time_limit = 0;
10716#endif
10717 int options = SEARCH_KEEP;
10718 int subpatnum;
10719
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010720 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010721 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10722 if (dir == 0)
10723 goto theend;
10724 flags = *flagsp;
10725 if (flags & SP_START)
10726 options |= SEARCH_START;
10727 if (flags & SP_END)
10728 options |= SEARCH_END;
10729 if (flags & SP_COLUMN)
10730 options |= SEARCH_COL;
10731
10732 /* Optional arguments: line number to stop searching and timeout. */
10733 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10734 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010735 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010736 if (lnum_stop < 0)
10737 goto theend;
10738#ifdef FEAT_RELTIME
10739 if (argvars[3].v_type != VAR_UNKNOWN)
10740 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010741 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010742 if (time_limit < 0)
10743 goto theend;
10744 }
10745#endif
10746 }
10747
10748#ifdef FEAT_RELTIME
10749 /* Set the time limit, if there is one. */
10750 profile_setlimit(time_limit, &tm);
10751#endif
10752
10753 /*
10754 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10755 * Check to make sure only those flags are set.
10756 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10757 * flags cannot be set. Check for that condition also.
10758 */
10759 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10760 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10761 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010762 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010763 goto theend;
10764 }
10765
10766 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010767 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010768 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010769 if (subpatnum != FAIL)
10770 {
10771 if (flags & SP_SUBPAT)
10772 retval = subpatnum;
10773 else
10774 retval = pos.lnum;
10775 if (flags & SP_SETPCMARK)
10776 setpcmark();
10777 curwin->w_cursor = pos;
10778 if (match_pos != NULL)
10779 {
10780 /* Store the match cursor position */
10781 match_pos->lnum = pos.lnum;
10782 match_pos->col = pos.col + 1;
10783 }
10784 /* "/$" will put the cursor after the end of the line, may need to
10785 * correct that here */
10786 check_cursor();
10787 }
10788
10789 /* If 'n' flag is used: restore cursor position. */
10790 if (flags & SP_NOMOVE)
10791 curwin->w_cursor = save_cursor;
10792 else
10793 curwin->w_set_curswant = TRUE;
10794theend:
10795 p_ws = save_p_ws;
10796
10797 return retval;
10798}
10799
10800#ifdef FEAT_FLOAT
10801
10802/*
10803 * round() is not in C90, use ceil() or floor() instead.
10804 */
10805 float_T
10806vim_round(float_T f)
10807{
10808 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10809}
10810
10811/*
10812 * "round({float})" function
10813 */
10814 static void
10815f_round(typval_T *argvars, typval_T *rettv)
10816{
10817 float_T f = 0.0;
10818
10819 rettv->v_type = VAR_FLOAT;
10820 if (get_float_arg(argvars, &f) == OK)
10821 rettv->vval.v_float = vim_round(f);
10822 else
10823 rettv->vval.v_float = 0.0;
10824}
10825#endif
10826
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010827#ifdef FEAT_RUBY
10828/*
10829 * "rubyeval()" function
10830 */
10831 static void
10832f_rubyeval(typval_T *argvars, typval_T *rettv)
10833{
10834 char_u *str;
10835 char_u buf[NUMBUFLEN];
10836
10837 str = tv_get_string_buf(&argvars[0], buf);
10838 do_rubyeval(str, rettv);
10839}
10840#endif
10841
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010842/*
10843 * "screenattr()" function
10844 */
10845 static void
10846f_screenattr(typval_T *argvars, typval_T *rettv)
10847{
10848 int row;
10849 int col;
10850 int c;
10851
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010852 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10853 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010854 if (row < 0 || row >= screen_Rows
10855 || col < 0 || col >= screen_Columns)
10856 c = -1;
10857 else
10858 c = ScreenAttrs[LineOffset[row] + col];
10859 rettv->vval.v_number = c;
10860}
10861
10862/*
10863 * "screenchar()" function
10864 */
10865 static void
10866f_screenchar(typval_T *argvars, typval_T *rettv)
10867{
10868 int row;
10869 int col;
10870 int off;
10871 int c;
10872
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010873 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10874 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010875 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010876 c = -1;
10877 else
10878 {
10879 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010880 if (enc_utf8 && ScreenLinesUC[off] != 0)
10881 c = ScreenLinesUC[off];
10882 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010883 c = ScreenLines[off];
10884 }
10885 rettv->vval.v_number = c;
10886}
10887
10888/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010889 * "screenchars()" function
10890 */
10891 static void
10892f_screenchars(typval_T *argvars, typval_T *rettv)
10893{
10894 int row;
10895 int col;
10896 int off;
10897 int c;
10898 int i;
10899
10900 if (rettv_list_alloc(rettv) == FAIL)
10901 return;
10902 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10903 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10904 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10905 return;
10906
10907 off = LineOffset[row] + col;
10908 if (enc_utf8 && ScreenLinesUC[off] != 0)
10909 c = ScreenLinesUC[off];
10910 else
10911 c = ScreenLines[off];
10912 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10913
10914 if (enc_utf8)
10915
10916 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10917 list_append_number(rettv->vval.v_list,
10918 (varnumber_T)ScreenLinesC[i][off]);
10919}
10920
10921/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010922 * "screencol()" function
10923 *
10924 * First column is 1 to be consistent with virtcol().
10925 */
10926 static void
10927f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10928{
10929 rettv->vval.v_number = screen_screencol() + 1;
10930}
10931
10932/*
10933 * "screenrow()" function
10934 */
10935 static void
10936f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10937{
10938 rettv->vval.v_number = screen_screenrow() + 1;
10939}
10940
10941/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010942 * "screenstring()" function
10943 */
10944 static void
10945f_screenstring(typval_T *argvars, typval_T *rettv)
10946{
10947 int row;
10948 int col;
10949 int off;
10950 int c;
10951 int i;
10952 char_u buf[MB_MAXBYTES + 1];
10953 int buflen = 0;
10954
10955 rettv->vval.v_string = NULL;
10956 rettv->v_type = VAR_STRING;
10957
10958 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10959 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10960 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10961 return;
10962
10963 off = LineOffset[row] + col;
10964 if (enc_utf8 && ScreenLinesUC[off] != 0)
10965 c = ScreenLinesUC[off];
10966 else
10967 c = ScreenLines[off];
10968 buflen += mb_char2bytes(c, buf);
10969
10970 if (enc_utf8)
10971 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10972 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10973
10974 buf[buflen] = NUL;
10975 rettv->vval.v_string = vim_strsave(buf);
10976}
10977
10978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010979 * "search()" function
10980 */
10981 static void
10982f_search(typval_T *argvars, typval_T *rettv)
10983{
10984 int flags = 0;
10985
10986 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10987}
10988
10989/*
10990 * "searchdecl()" function
10991 */
10992 static void
10993f_searchdecl(typval_T *argvars, typval_T *rettv)
10994{
10995 int locally = 1;
10996 int thisblock = 0;
10997 int error = FALSE;
10998 char_u *name;
10999
11000 rettv->vval.v_number = 1; /* default: FAIL */
11001
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011002 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011003 if (argvars[1].v_type != VAR_UNKNOWN)
11004 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011005 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011006 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011007 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011008 }
11009 if (!error && name != NULL)
11010 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
11011 locally, thisblock, SEARCH_KEEP) == FAIL;
11012}
11013
11014/*
11015 * Used by searchpair() and searchpairpos()
11016 */
11017 static int
11018searchpair_cmn(typval_T *argvars, pos_T *match_pos)
11019{
11020 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010011021 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011022 int save_p_ws = p_ws;
11023 int dir;
11024 int flags = 0;
11025 char_u nbuf1[NUMBUFLEN];
11026 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011027 int retval = 0; /* default: FAIL */
11028 long lnum_stop = 0;
11029 long time_limit = 0;
11030
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011031 /* Get the three pattern arguments: start, middle, end. Will result in an
11032 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011033 spat = tv_get_string_chk(&argvars[0]);
11034 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
11035 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011036 if (spat == NULL || mpat == NULL || epat == NULL)
11037 goto theend; /* type error */
11038
11039 /* Handle the optional fourth argument: flags */
11040 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
11041 if (dir == 0)
11042 goto theend;
11043
11044 /* Don't accept SP_END or SP_SUBPAT.
11045 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
11046 */
11047 if ((flags & (SP_END | SP_SUBPAT)) != 0
11048 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
11049 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011050 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011051 goto theend;
11052 }
11053
11054 /* Using 'r' implies 'W', otherwise it doesn't work. */
11055 if (flags & SP_REPEAT)
11056 p_ws = FALSE;
11057
11058 /* Optional fifth argument: skip expression */
11059 if (argvars[3].v_type == VAR_UNKNOWN
11060 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010011061 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011062 else
11063 {
Bram Moolenaar48570482017-10-30 21:48:41 +010011064 skip = &argvars[4];
11065 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
11066 && skip->v_type != VAR_STRING)
11067 {
11068 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011069 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010011070 goto theend;
11071 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011072 if (argvars[5].v_type != VAR_UNKNOWN)
11073 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011074 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011075 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011076 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011077 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011078 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011079 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080#ifdef FEAT_RELTIME
11081 if (argvars[6].v_type != VAR_UNKNOWN)
11082 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011083 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011084 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011085 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011086 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011087 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020011088 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011089 }
11090#endif
11091 }
11092 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011093
11094 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
11095 match_pos, lnum_stop, time_limit);
11096
11097theend:
11098 p_ws = save_p_ws;
11099
11100 return retval;
11101}
11102
11103/*
11104 * "searchpair()" function
11105 */
11106 static void
11107f_searchpair(typval_T *argvars, typval_T *rettv)
11108{
11109 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
11110}
11111
11112/*
11113 * "searchpairpos()" function
11114 */
11115 static void
11116f_searchpairpos(typval_T *argvars, typval_T *rettv)
11117{
11118 pos_T match_pos;
11119 int lnum = 0;
11120 int col = 0;
11121
11122 if (rettv_list_alloc(rettv) == FAIL)
11123 return;
11124
11125 if (searchpair_cmn(argvars, &match_pos) > 0)
11126 {
11127 lnum = match_pos.lnum;
11128 col = match_pos.col;
11129 }
11130
11131 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
11132 list_append_number(rettv->vval.v_list, (varnumber_T)col);
11133}
11134
11135/*
11136 * Search for a start/middle/end thing.
11137 * Used by searchpair(), see its documentation for the details.
11138 * Returns 0 or -1 for no match,
11139 */
11140 long
11141do_searchpair(
11142 char_u *spat, /* start pattern */
11143 char_u *mpat, /* middle pattern */
11144 char_u *epat, /* end pattern */
11145 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010011146 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011147 int flags, /* SP_SETPCMARK and other SP_ values */
11148 pos_T *match_pos,
11149 linenr_T lnum_stop, /* stop at this line if not zero */
11150 long time_limit UNUSED) /* stop after this many msec */
11151{
11152 char_u *save_cpo;
11153 char_u *pat, *pat2 = NULL, *pat3 = NULL;
11154 long retval = 0;
11155 pos_T pos;
11156 pos_T firstpos;
11157 pos_T foundpos;
11158 pos_T save_cursor;
11159 pos_T save_pos;
11160 int n;
11161 int r;
11162 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010011163 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011164 int err;
11165 int options = SEARCH_KEEP;
11166 proftime_T tm;
11167
11168 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11169 save_cpo = p_cpo;
11170 p_cpo = empty_option;
11171
11172#ifdef FEAT_RELTIME
11173 /* Set the time limit, if there is one. */
11174 profile_setlimit(time_limit, &tm);
11175#endif
11176
11177 /* Make two search patterns: start/end (pat2, for in nested pairs) and
11178 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010011179 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
11180 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011181 if (pat2 == NULL || pat3 == NULL)
11182 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010011183 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011184 if (*mpat == NUL)
11185 STRCPY(pat3, pat2);
11186 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010011187 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011188 spat, epat, mpat);
11189 if (flags & SP_START)
11190 options |= SEARCH_START;
11191
Bram Moolenaar48570482017-10-30 21:48:41 +010011192 if (skip != NULL)
11193 {
11194 /* Empty string means to not use the skip expression. */
11195 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
11196 use_skip = skip->vval.v_string != NULL
11197 && *skip->vval.v_string != NUL;
11198 }
11199
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011200 save_cursor = curwin->w_cursor;
11201 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010011202 CLEAR_POS(&firstpos);
11203 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011204 pat = pat3;
11205 for (;;)
11206 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010011207 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020011208 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010011209 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011210 /* didn't find it or found the first match again: FAIL */
11211 break;
11212
11213 if (firstpos.lnum == 0)
11214 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010011215 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011216 {
11217 /* Found the same position again. Can happen with a pattern that
11218 * has "\zs" at the end and searching backwards. Advance one
11219 * character and try again. */
11220 if (dir == BACKWARD)
11221 decl(&pos);
11222 else
11223 incl(&pos);
11224 }
11225 foundpos = pos;
11226
11227 /* clear the start flag to avoid getting stuck here */
11228 options &= ~SEARCH_START;
11229
11230 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010011231 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011232 {
11233 save_pos = curwin->w_cursor;
11234 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010011235 err = FALSE;
11236 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011237 curwin->w_cursor = save_pos;
11238 if (err)
11239 {
11240 /* Evaluating {skip} caused an error, break here. */
11241 curwin->w_cursor = save_cursor;
11242 retval = -1;
11243 break;
11244 }
11245 if (r)
11246 continue;
11247 }
11248
11249 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
11250 {
11251 /* Found end when searching backwards or start when searching
11252 * forward: nested pair. */
11253 ++nest;
11254 pat = pat2; /* nested, don't search for middle */
11255 }
11256 else
11257 {
11258 /* Found end when searching forward or start when searching
11259 * backward: end of (nested) pair; or found middle in outer pair. */
11260 if (--nest == 1)
11261 pat = pat3; /* outer level, search for middle */
11262 }
11263
11264 if (nest == 0)
11265 {
11266 /* Found the match: return matchcount or line number. */
11267 if (flags & SP_RETCOUNT)
11268 ++retval;
11269 else
11270 retval = pos.lnum;
11271 if (flags & SP_SETPCMARK)
11272 setpcmark();
11273 curwin->w_cursor = pos;
11274 if (!(flags & SP_REPEAT))
11275 break;
11276 nest = 1; /* search for next unmatched */
11277 }
11278 }
11279
11280 if (match_pos != NULL)
11281 {
11282 /* Store the match cursor position */
11283 match_pos->lnum = curwin->w_cursor.lnum;
11284 match_pos->col = curwin->w_cursor.col + 1;
11285 }
11286
11287 /* If 'n' flag is used or search failed: restore cursor position. */
11288 if ((flags & SP_NOMOVE) || retval == 0)
11289 curwin->w_cursor = save_cursor;
11290
11291theend:
11292 vim_free(pat2);
11293 vim_free(pat3);
11294 if (p_cpo == empty_option)
11295 p_cpo = save_cpo;
11296 else
11297 /* Darn, evaluating the {skip} expression changed the value. */
11298 free_string_option(save_cpo);
11299
11300 return retval;
11301}
11302
11303/*
11304 * "searchpos()" function
11305 */
11306 static void
11307f_searchpos(typval_T *argvars, typval_T *rettv)
11308{
11309 pos_T match_pos;
11310 int lnum = 0;
11311 int col = 0;
11312 int n;
11313 int flags = 0;
11314
11315 if (rettv_list_alloc(rettv) == FAIL)
11316 return;
11317
11318 n = search_cmn(argvars, &match_pos, &flags);
11319 if (n > 0)
11320 {
11321 lnum = match_pos.lnum;
11322 col = match_pos.col;
11323 }
11324
11325 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
11326 list_append_number(rettv->vval.v_list, (varnumber_T)col);
11327 if (flags & SP_SUBPAT)
11328 list_append_number(rettv->vval.v_list, (varnumber_T)n);
11329}
11330
11331 static void
11332f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
11333{
11334#ifdef FEAT_CLIENTSERVER
11335 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011336 char_u *server = tv_get_string_chk(&argvars[0]);
11337 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011338
11339 rettv->vval.v_number = -1;
11340 if (server == NULL || reply == NULL)
11341 return;
11342 if (check_restricted() || check_secure())
11343 return;
11344# ifdef FEAT_X11
11345 if (check_connection() == FAIL)
11346 return;
11347# endif
11348
11349 if (serverSendReply(server, reply) < 0)
11350 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011351 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011352 return;
11353 }
11354 rettv->vval.v_number = 0;
11355#else
11356 rettv->vval.v_number = -1;
11357#endif
11358}
11359
11360 static void
11361f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
11362{
11363 char_u *r = NULL;
11364
11365#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010011366# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011367 r = serverGetVimNames();
11368# else
11369 make_connection();
11370 if (X_DISPLAY != NULL)
11371 r = serverGetVimNames(X_DISPLAY);
11372# endif
11373#endif
11374 rettv->v_type = VAR_STRING;
11375 rettv->vval.v_string = r;
11376}
11377
11378/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011379 * "setbufline()" function
11380 */
11381 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020011382f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011383{
11384 linenr_T lnum;
11385 buf_T *buf;
11386
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011387 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011388 if (buf == NULL)
11389 rettv->vval.v_number = 1; /* FAIL */
11390 else
11391 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011392 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020011393 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020011394 }
11395}
11396
11397/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011398 * "setbufvar()" function
11399 */
11400 static void
11401f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
11402{
11403 buf_T *buf;
11404 char_u *varname, *bufvarname;
11405 typval_T *varp;
11406 char_u nbuf[NUMBUFLEN];
11407
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011408 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011409 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011410 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
11411 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011412 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011413 varp = &argvars[2];
11414
11415 if (buf != NULL && varname != NULL && varp != NULL)
11416 {
11417 if (*varname == '&')
11418 {
11419 long numval;
11420 char_u *strval;
11421 int error = FALSE;
11422 aco_save_T aco;
11423
11424 /* set curbuf to be our buf, temporarily */
11425 aucmd_prepbuf(&aco, buf);
11426
11427 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011428 numval = (long)tv_get_number_chk(varp, &error);
11429 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011430 if (!error && strval != NULL)
11431 set_option_value(varname, numval, strval, OPT_LOCAL);
11432
11433 /* reset notion of buffer */
11434 aucmd_restbuf(&aco);
11435 }
11436 else
11437 {
11438 buf_T *save_curbuf = curbuf;
11439
11440 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
11441 if (bufvarname != NULL)
11442 {
11443 curbuf = buf;
11444 STRCPY(bufvarname, "b:");
11445 STRCPY(bufvarname + 2, varname);
11446 set_var(bufvarname, varp, TRUE);
11447 vim_free(bufvarname);
11448 curbuf = save_curbuf;
11449 }
11450 }
11451 }
11452}
11453
11454 static void
11455f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
11456{
11457 dict_T *d;
11458 dictitem_T *di;
11459 char_u *csearch;
11460
11461 if (argvars[0].v_type != VAR_DICT)
11462 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011463 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011464 return;
11465 }
11466
11467 if ((d = argvars[0].vval.v_dict) != NULL)
11468 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011469 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011470 if (csearch != NULL)
11471 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011472 if (enc_utf8)
11473 {
11474 int pcc[MAX_MCO];
11475 int c = utfc_ptr2char(csearch, pcc);
11476
11477 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11478 }
11479 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011480 set_last_csearch(PTR2CHAR(csearch),
11481 csearch, MB_PTR2LEN(csearch));
11482 }
11483
11484 di = dict_find(d, (char_u *)"forward", -1);
11485 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011486 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011487 ? FORWARD : BACKWARD);
11488
11489 di = dict_find(d, (char_u *)"until", -1);
11490 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011491 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011492 }
11493}
11494
11495/*
11496 * "setcmdpos()" function
11497 */
11498 static void
11499f_setcmdpos(typval_T *argvars, typval_T *rettv)
11500{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011501 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011502
11503 if (pos >= 0)
11504 rettv->vval.v_number = set_cmdline_pos(pos);
11505}
11506
11507/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020011508 * "setenv()" function
11509 */
11510 static void
11511f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
11512{
11513 char_u namebuf[NUMBUFLEN];
11514 char_u valbuf[NUMBUFLEN];
11515 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
11516
11517 if (argvars[1].v_type == VAR_SPECIAL
11518 && argvars[1].vval.v_number == VVAL_NULL)
11519 vim_unsetenv(name);
11520 else
11521 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
11522}
11523
11524/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011525 * "setfperm({fname}, {mode})" function
11526 */
11527 static void
11528f_setfperm(typval_T *argvars, typval_T *rettv)
11529{
11530 char_u *fname;
11531 char_u modebuf[NUMBUFLEN];
11532 char_u *mode_str;
11533 int i;
11534 int mask;
11535 int mode = 0;
11536
11537 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011538 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011539 if (fname == NULL)
11540 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011541 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011542 if (mode_str == NULL)
11543 return;
11544 if (STRLEN(mode_str) != 9)
11545 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011546 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011547 return;
11548 }
11549
11550 mask = 1;
11551 for (i = 8; i >= 0; --i)
11552 {
11553 if (mode_str[i] != '-')
11554 mode |= mask;
11555 mask = mask << 1;
11556 }
11557 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11558}
11559
11560/*
11561 * "setline()" function
11562 */
11563 static void
11564f_setline(typval_T *argvars, typval_T *rettv)
11565{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011566 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011567
Bram Moolenaarca851592018-06-06 21:04:07 +020011568 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011569}
11570
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011571/*
11572 * Used by "setqflist()" and "setloclist()" functions
11573 */
11574 static void
11575set_qf_ll_list(
11576 win_T *wp UNUSED,
11577 typval_T *list_arg UNUSED,
11578 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011579 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011580 typval_T *rettv)
11581{
11582#ifdef FEAT_QUICKFIX
11583 static char *e_invact = N_("E927: Invalid action: '%s'");
11584 char_u *act;
11585 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011586 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011587#endif
11588
11589 rettv->vval.v_number = -1;
11590
11591#ifdef FEAT_QUICKFIX
11592 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011593 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011594 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011595 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011596 else
11597 {
11598 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011599 dict_T *d = NULL;
11600 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011601
11602 if (action_arg->v_type == VAR_STRING)
11603 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011604 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011605 if (act == NULL)
11606 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011607 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11608 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011609 action = *act;
11610 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011611 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011612 }
11613 else if (action_arg->v_type == VAR_UNKNOWN)
11614 action = ' ';
11615 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011616 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011617
Bram Moolenaard823fa92016-08-12 16:29:27 +020011618 if (action_arg->v_type != VAR_UNKNOWN
11619 && what_arg->v_type != VAR_UNKNOWN)
11620 {
11621 if (what_arg->v_type == VAR_DICT)
11622 d = what_arg->vval.v_dict;
11623 else
11624 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011625 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011626 valid_dict = FALSE;
11627 }
11628 }
11629
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011630 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011631 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011632 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11633 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011634 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011635 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011636 }
11637#endif
11638}
11639
11640/*
11641 * "setloclist()" function
11642 */
11643 static void
11644f_setloclist(typval_T *argvars, typval_T *rettv)
11645{
11646 win_T *win;
11647
11648 rettv->vval.v_number = -1;
11649
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011650 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011651 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011652 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011653}
11654
11655/*
11656 * "setmatches()" function
11657 */
11658 static void
11659f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11660{
11661#ifdef FEAT_SEARCH_EXTRA
11662 list_T *l;
11663 listitem_T *li;
11664 dict_T *d;
11665 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010011666 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011667
11668 rettv->vval.v_number = -1;
11669 if (argvars[0].v_type != VAR_LIST)
11670 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011671 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011672 return;
11673 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010011674 if (win == NULL)
11675 return;
11676
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011677 if ((l = argvars[0].vval.v_list) != NULL)
11678 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011679 /* To some extent make sure that we are dealing with a list from
11680 * "getmatches()". */
11681 li = l->lv_first;
11682 while (li != NULL)
11683 {
11684 if (li->li_tv.v_type != VAR_DICT
11685 || (d = li->li_tv.vval.v_dict) == NULL)
11686 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011687 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011688 return;
11689 }
11690 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11691 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11692 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11693 && dict_find(d, (char_u *)"priority", -1) != NULL
11694 && dict_find(d, (char_u *)"id", -1) != NULL))
11695 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011696 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011697 return;
11698 }
11699 li = li->li_next;
11700 }
11701
Bram Moolenaaraff74912019-03-30 18:11:49 +010011702 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011703 li = l->lv_first;
11704 while (li != NULL)
11705 {
11706 int i = 0;
Bram Moolenaar54315892019-04-26 22:33:49 +020011707 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011708 dictitem_T *di;
11709 char_u *group;
11710 int priority;
11711 int id;
11712 char_u *conceal;
11713
11714 d = li->li_tv.vval.v_dict;
11715 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11716 {
11717 if (s == NULL)
11718 {
11719 s = list_alloc();
11720 if (s == NULL)
11721 return;
11722 }
11723
11724 /* match from matchaddpos() */
11725 for (i = 1; i < 9; i++)
11726 {
11727 sprintf((char *)buf, (char *)"pos%d", i);
11728 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11729 {
11730 if (di->di_tv.v_type != VAR_LIST)
11731 return;
11732
11733 list_append_tv(s, &di->di_tv);
11734 s->lv_refcount++;
11735 }
11736 else
11737 break;
11738 }
11739 }
11740
Bram Moolenaar8f667172018-12-14 15:38:31 +010011741 group = dict_get_string(d, (char_u *)"group", TRUE);
11742 priority = (int)dict_get_number(d, (char_u *)"priority");
11743 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011744 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011745 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011746 : NULL;
11747 if (i == 0)
11748 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011749 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011750 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011751 priority, id, NULL, conceal);
11752 }
11753 else
11754 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011755 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011756 list_unref(s);
11757 s = NULL;
11758 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011759 vim_free(group);
11760 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011761
11762 li = li->li_next;
11763 }
11764 rettv->vval.v_number = 0;
11765 }
11766#endif
11767}
11768
11769/*
11770 * "setpos()" function
11771 */
11772 static void
11773f_setpos(typval_T *argvars, typval_T *rettv)
11774{
11775 pos_T pos;
11776 int fnum;
11777 char_u *name;
11778 colnr_T curswant = -1;
11779
11780 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011781 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011782 if (name != NULL)
11783 {
11784 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11785 {
11786 if (--pos.col < 0)
11787 pos.col = 0;
11788 if (name[0] == '.' && name[1] == NUL)
11789 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011790 /* set cursor; "fnum" is ignored */
11791 curwin->w_cursor = pos;
11792 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011793 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011794 curwin->w_curswant = curswant - 1;
11795 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011796 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011797 check_cursor();
11798 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011799 }
11800 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11801 {
11802 /* set mark */
11803 if (setmark_pos(name[1], &pos, fnum) == OK)
11804 rettv->vval.v_number = 0;
11805 }
11806 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011807 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011808 }
11809 }
11810}
11811
11812/*
11813 * "setqflist()" function
11814 */
11815 static void
11816f_setqflist(typval_T *argvars, typval_T *rettv)
11817{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011818 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011819}
11820
11821/*
11822 * "setreg()" function
11823 */
11824 static void
11825f_setreg(typval_T *argvars, typval_T *rettv)
11826{
11827 int regname;
11828 char_u *strregname;
11829 char_u *stropt;
11830 char_u *strval;
11831 int append;
11832 char_u yank_type;
11833 long block_len;
11834
11835 block_len = -1;
11836 yank_type = MAUTO;
11837 append = FALSE;
11838
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011839 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011840 rettv->vval.v_number = 1; /* FAIL is default */
11841
11842 if (strregname == NULL)
11843 return; /* type error; errmsg already given */
11844 regname = *strregname;
11845 if (regname == 0 || regname == '@')
11846 regname = '"';
11847
11848 if (argvars[2].v_type != VAR_UNKNOWN)
11849 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011850 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011851 if (stropt == NULL)
11852 return; /* type error */
11853 for (; *stropt != NUL; ++stropt)
11854 switch (*stropt)
11855 {
11856 case 'a': case 'A': /* append */
11857 append = TRUE;
11858 break;
11859 case 'v': case 'c': /* character-wise selection */
11860 yank_type = MCHAR;
11861 break;
11862 case 'V': case 'l': /* line-wise selection */
11863 yank_type = MLINE;
11864 break;
11865 case 'b': case Ctrl_V: /* block-wise selection */
11866 yank_type = MBLOCK;
11867 if (VIM_ISDIGIT(stropt[1]))
11868 {
11869 ++stropt;
11870 block_len = getdigits(&stropt) - 1;
11871 --stropt;
11872 }
11873 break;
11874 }
11875 }
11876
11877 if (argvars[1].v_type == VAR_LIST)
11878 {
11879 char_u **lstval;
11880 char_u **allocval;
11881 char_u buf[NUMBUFLEN];
11882 char_u **curval;
11883 char_u **curallocval;
11884 list_T *ll = argvars[1].vval.v_list;
11885 listitem_T *li;
11886 int len;
11887
11888 /* If the list is NULL handle like an empty list. */
11889 len = ll == NULL ? 0 : ll->lv_len;
11890
11891 /* First half: use for pointers to result lines; second half: use for
11892 * pointers to allocated copies. */
11893 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11894 if (lstval == NULL)
11895 return;
11896 curval = lstval;
11897 allocval = lstval + len + 2;
11898 curallocval = allocval;
11899
11900 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11901 li = li->li_next)
11902 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011903 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011904 if (strval == NULL)
11905 goto free_lstval;
11906 if (strval == buf)
11907 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011908 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011909 * overwrite the string. */
11910 strval = vim_strsave(buf);
11911 if (strval == NULL)
11912 goto free_lstval;
11913 *curallocval++ = strval;
11914 }
11915 *curval++ = strval;
11916 }
11917 *curval++ = NULL;
11918
11919 write_reg_contents_lst(regname, lstval, -1,
11920 append, yank_type, block_len);
11921free_lstval:
11922 while (curallocval > allocval)
11923 vim_free(*--curallocval);
11924 vim_free(lstval);
11925 }
11926 else
11927 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011928 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011929 if (strval == NULL)
11930 return;
11931 write_reg_contents_ex(regname, strval, -1,
11932 append, yank_type, block_len);
11933 }
11934 rettv->vval.v_number = 0;
11935}
11936
11937/*
11938 * "settabvar()" function
11939 */
11940 static void
11941f_settabvar(typval_T *argvars, typval_T *rettv)
11942{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011943 tabpage_T *save_curtab;
11944 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011945 char_u *varname, *tabvarname;
11946 typval_T *varp;
11947
11948 rettv->vval.v_number = 0;
11949
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011950 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011951 return;
11952
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011953 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11954 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011955 varp = &argvars[2];
11956
Bram Moolenaar4033c552017-09-16 20:54:51 +020011957 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011958 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011959 save_curtab = curtab;
11960 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011961
11962 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11963 if (tabvarname != NULL)
11964 {
11965 STRCPY(tabvarname, "t:");
11966 STRCPY(tabvarname + 2, varname);
11967 set_var(tabvarname, varp, TRUE);
11968 vim_free(tabvarname);
11969 }
11970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011971 /* Restore current tabpage */
11972 if (valid_tabpage(save_curtab))
11973 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011974 }
11975}
11976
11977/*
11978 * "settabwinvar()" function
11979 */
11980 static void
11981f_settabwinvar(typval_T *argvars, typval_T *rettv)
11982{
11983 setwinvar(argvars, rettv, 1);
11984}
11985
11986/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011987 * "settagstack()" function
11988 */
11989 static void
11990f_settagstack(typval_T *argvars, typval_T *rettv)
11991{
11992 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11993 win_T *wp;
11994 dict_T *d;
11995 int action = 'r';
11996
11997 rettv->vval.v_number = -1;
11998
11999 // first argument: window number or id
12000 wp = find_win_by_nr_or_id(&argvars[0]);
12001 if (wp == NULL)
12002 return;
12003
12004 // second argument: dict with items to set in the tag stack
12005 if (argvars[1].v_type != VAR_DICT)
12006 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012007 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012008 return;
12009 }
12010 d = argvars[1].vval.v_dict;
12011 if (d == NULL)
12012 return;
12013
12014 // third argument: action - 'a' for append and 'r' for replace.
12015 // default is to replace the stack.
12016 if (argvars[2].v_type == VAR_UNKNOWN)
12017 action = 'r';
12018 else if (argvars[2].v_type == VAR_STRING)
12019 {
12020 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012021 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012022 if (actstr == NULL)
12023 return;
12024 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
12025 action = *actstr;
12026 else
12027 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012028 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012029 return;
12030 }
12031 }
12032 else
12033 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012034 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010012035 return;
12036 }
12037
12038 if (set_tagstack(wp, d, action) == OK)
12039 rettv->vval.v_number = 0;
12040}
12041
12042/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012043 * "setwinvar()" function
12044 */
12045 static void
12046f_setwinvar(typval_T *argvars, typval_T *rettv)
12047{
12048 setwinvar(argvars, rettv, 0);
12049}
12050
12051#ifdef FEAT_CRYPT
12052/*
12053 * "sha256({string})" function
12054 */
12055 static void
12056f_sha256(typval_T *argvars, typval_T *rettv)
12057{
12058 char_u *p;
12059
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012060 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012061 rettv->vval.v_string = vim_strsave(
12062 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
12063 rettv->v_type = VAR_STRING;
12064}
12065#endif /* FEAT_CRYPT */
12066
12067/*
12068 * "shellescape({string})" function
12069 */
12070 static void
12071f_shellescape(typval_T *argvars, typval_T *rettv)
12072{
Bram Moolenaar20615522017-06-05 18:46:26 +020012073 int do_special = non_zero_arg(&argvars[1]);
12074
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012075 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012076 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012077 rettv->v_type = VAR_STRING;
12078}
12079
12080/*
12081 * shiftwidth() function
12082 */
12083 static void
12084f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
12085{
Bram Moolenaarf9514162018-11-22 03:08:29 +010012086 rettv->vval.v_number = 0;
12087
12088 if (argvars[0].v_type != VAR_UNKNOWN)
12089 {
12090 long col;
12091
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012092 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010012093 if (col < 0)
12094 return; // type error; errmsg already given
12095#ifdef FEAT_VARTABS
12096 rettv->vval.v_number = get_sw_value_col(curbuf, col);
12097 return;
12098#endif
12099 }
12100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012101 rettv->vval.v_number = get_sw_value(curbuf);
12102}
12103
Bram Moolenaar162b7142018-12-21 15:17:36 +010012104#ifdef FEAT_SIGNS
12105/*
12106 * "sign_define()" function
12107 */
12108 static void
12109f_sign_define(typval_T *argvars, typval_T *rettv)
12110{
12111 char_u *name;
12112 dict_T *dict;
12113 char_u *icon = NULL;
12114 char_u *linehl = NULL;
12115 char_u *text = NULL;
12116 char_u *texthl = NULL;
12117
12118 rettv->vval.v_number = -1;
12119
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012120 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012121 if (name == NULL)
12122 return;
12123
12124 if (argvars[1].v_type != VAR_UNKNOWN)
12125 {
12126 if (argvars[1].v_type != VAR_DICT)
12127 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012128 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012129 return;
12130 }
12131
12132 // sign attributes
12133 dict = argvars[1].vval.v_dict;
12134 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
12135 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
12136 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
12137 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
12138 if (dict_find(dict, (char_u *)"text", -1) != NULL)
12139 text = dict_get_string(dict, (char_u *)"text", TRUE);
12140 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
12141 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
12142 }
12143
12144 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
12145 rettv->vval.v_number = 0;
12146
12147 vim_free(icon);
12148 vim_free(linehl);
12149 vim_free(text);
12150 vim_free(texthl);
12151}
12152
12153/*
12154 * "sign_getdefined()" function
12155 */
12156 static void
12157f_sign_getdefined(typval_T *argvars, typval_T *rettv)
12158{
12159 char_u *name = NULL;
12160
12161 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
12162 return;
12163
12164 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012165 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012166
12167 sign_getlist(name, rettv->vval.v_list);
12168}
12169
12170/*
12171 * "sign_getplaced()" function
12172 */
12173 static void
12174f_sign_getplaced(typval_T *argvars, typval_T *rettv)
12175{
12176 buf_T *buf = NULL;
12177 dict_T *dict;
12178 dictitem_T *di;
12179 linenr_T lnum = 0;
12180 int sign_id = 0;
12181 char_u *group = NULL;
12182 int notanum = FALSE;
12183
12184 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
12185 return;
12186
12187 if (argvars[0].v_type != VAR_UNKNOWN)
12188 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012189 // get signs placed in the specified buffer
12190 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012191 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012192 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012193
12194 if (argvars[1].v_type != VAR_UNKNOWN)
12195 {
12196 if (argvars[1].v_type != VAR_DICT ||
12197 ((dict = argvars[1].vval.v_dict) == NULL))
12198 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012199 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012200 return;
12201 }
12202 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
12203 {
12204 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012205 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012206 if (notanum)
12207 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012208 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012209 }
12210 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
12211 {
12212 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012213 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012214 if (notanum)
12215 return;
12216 }
12217 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
12218 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012219 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012220 if (group == NULL)
12221 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010012222 if (*group == '\0') // empty string means global group
12223 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012224 }
12225 }
12226 }
12227
12228 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
12229}
12230
12231/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012232 * "sign_jump()" function
12233 */
12234 static void
12235f_sign_jump(typval_T *argvars, typval_T *rettv)
12236{
12237 int sign_id;
12238 char_u *sign_group = NULL;
12239 buf_T *buf;
12240 int notanum = FALSE;
12241
12242 rettv->vval.v_number = -1;
12243
Bram Moolenaarbdace832019-03-02 10:13:42 +010012244 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012245 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
12246 if (notanum)
12247 return;
12248 if (sign_id <= 0)
12249 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012250 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012251 return;
12252 }
12253
12254 // Sign group
12255 sign_group = tv_get_string_chk(&argvars[1]);
12256 if (sign_group == NULL)
12257 return;
12258 if (sign_group[0] == '\0')
12259 sign_group = NULL; // global sign group
12260 else
12261 {
12262 sign_group = vim_strsave(sign_group);
12263 if (sign_group == NULL)
12264 return;
12265 }
12266
12267 // Buffer to place the sign
12268 buf = get_buf_arg(&argvars[2]);
12269 if (buf == NULL)
12270 goto cleanup;
12271
12272 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
12273
12274cleanup:
12275 vim_free(sign_group);
12276}
12277
12278/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010012279 * "sign_place()" function
12280 */
12281 static void
12282f_sign_place(typval_T *argvars, typval_T *rettv)
12283{
12284 int sign_id;
12285 char_u *group = NULL;
12286 char_u *sign_name;
12287 buf_T *buf;
12288 dict_T *dict;
12289 dictitem_T *di;
12290 linenr_T lnum = 0;
12291 int prio = SIGN_DEF_PRIO;
12292 int notanum = FALSE;
12293
12294 rettv->vval.v_number = -1;
12295
Bram Moolenaarbdace832019-03-02 10:13:42 +010012296 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012297 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012298 if (notanum)
12299 return;
12300 if (sign_id < 0)
12301 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012302 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012303 return;
12304 }
12305
12306 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012307 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012308 if (group == NULL)
12309 return;
12310 if (group[0] == '\0')
12311 group = NULL; // global sign group
12312 else
12313 {
12314 group = vim_strsave(group);
12315 if (group == NULL)
12316 return;
12317 }
12318
12319 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012320 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012321 if (sign_name == NULL)
12322 goto cleanup;
12323
12324 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012325 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012326 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012327 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012328
12329 if (argvars[4].v_type != VAR_UNKNOWN)
12330 {
12331 if (argvars[4].v_type != VAR_DICT ||
12332 ((dict = argvars[4].vval.v_dict) == NULL))
12333 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012334 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012335 goto cleanup;
12336 }
12337
12338 // Line number where the sign is to be placed
12339 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
12340 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012341 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012342 if (notanum)
12343 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012344 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012345 }
12346 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
12347 {
12348 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012349 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012350 if (notanum)
12351 goto cleanup;
12352 }
12353 }
12354
12355 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
12356 rettv->vval.v_number = sign_id;
12357
12358cleanup:
12359 vim_free(group);
12360}
12361
12362/*
12363 * "sign_undefine()" function
12364 */
12365 static void
12366f_sign_undefine(typval_T *argvars, typval_T *rettv)
12367{
12368 char_u *name;
12369
12370 rettv->vval.v_number = -1;
12371
12372 if (argvars[0].v_type == VAR_UNKNOWN)
12373 {
12374 // Free all the signs
12375 free_signs();
12376 rettv->vval.v_number = 0;
12377 }
12378 else
12379 {
12380 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012381 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012382 if (name == NULL)
12383 return;
12384
12385 if (sign_undefine_by_name(name) == OK)
12386 rettv->vval.v_number = 0;
12387 }
12388}
12389
12390/*
12391 * "sign_unplace()" function
12392 */
12393 static void
12394f_sign_unplace(typval_T *argvars, typval_T *rettv)
12395{
12396 dict_T *dict;
12397 dictitem_T *di;
12398 int sign_id = 0;
12399 buf_T *buf = NULL;
12400 char_u *group = NULL;
12401
12402 rettv->vval.v_number = -1;
12403
12404 if (argvars[0].v_type != VAR_STRING)
12405 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012406 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010012407 return;
12408 }
12409
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012410 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012411 if (group[0] == '\0')
12412 group = NULL; // global sign group
12413 else
12414 {
12415 group = vim_strsave(group);
12416 if (group == NULL)
12417 return;
12418 }
12419
12420 if (argvars[1].v_type != VAR_UNKNOWN)
12421 {
12422 if (argvars[1].v_type != VAR_DICT)
12423 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012424 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012425 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012426 }
12427 dict = argvars[1].vval.v_dict;
12428
12429 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
12430 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012431 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012432 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012433 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012434 }
12435 if (dict_find(dict, (char_u *)"id", -1) != NULL)
12436 sign_id = dict_get_number(dict, (char_u *)"id");
12437 }
12438
12439 if (buf == NULL)
12440 {
12441 // Delete the sign in all the buffers
12442 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012443 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012444 rettv->vval.v_number = 0;
12445 }
12446 else
12447 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012448 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012449 rettv->vval.v_number = 0;
12450 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012451
12452cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010012453 vim_free(group);
12454}
12455#endif
12456
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012457/*
12458 * "simplify()" function
12459 */
12460 static void
12461f_simplify(typval_T *argvars, typval_T *rettv)
12462{
12463 char_u *p;
12464
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012465 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012466 rettv->vval.v_string = vim_strsave(p);
12467 simplify_filename(rettv->vval.v_string); /* simplify in place */
12468 rettv->v_type = VAR_STRING;
12469}
12470
12471#ifdef FEAT_FLOAT
12472/*
12473 * "sin()" function
12474 */
12475 static void
12476f_sin(typval_T *argvars, typval_T *rettv)
12477{
12478 float_T f = 0.0;
12479
12480 rettv->v_type = VAR_FLOAT;
12481 if (get_float_arg(argvars, &f) == OK)
12482 rettv->vval.v_float = sin(f);
12483 else
12484 rettv->vval.v_float = 0.0;
12485}
12486
12487/*
12488 * "sinh()" function
12489 */
12490 static void
12491f_sinh(typval_T *argvars, typval_T *rettv)
12492{
12493 float_T f = 0.0;
12494
12495 rettv->v_type = VAR_FLOAT;
12496 if (get_float_arg(argvars, &f) == OK)
12497 rettv->vval.v_float = sinh(f);
12498 else
12499 rettv->vval.v_float = 0.0;
12500}
12501#endif
12502
12503static int
12504#ifdef __BORLANDC__
12505 _RTLENTRYF
12506#endif
12507 item_compare(const void *s1, const void *s2);
12508static int
12509#ifdef __BORLANDC__
12510 _RTLENTRYF
12511#endif
12512 item_compare2(const void *s1, const void *s2);
12513
12514/* struct used in the array that's given to qsort() */
12515typedef struct
12516{
12517 listitem_T *item;
12518 int idx;
12519} sortItem_T;
12520
12521/* struct storing information about current sort */
12522typedef struct
12523{
12524 int item_compare_ic;
12525 int item_compare_numeric;
12526 int item_compare_numbers;
12527#ifdef FEAT_FLOAT
12528 int item_compare_float;
12529#endif
12530 char_u *item_compare_func;
12531 partial_T *item_compare_partial;
12532 dict_T *item_compare_selfdict;
12533 int item_compare_func_err;
12534 int item_compare_keep_zero;
12535} sortinfo_T;
12536static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012537#define ITEM_COMPARE_FAIL 999
12538
12539/*
12540 * Compare functions for f_sort() and f_uniq() below.
12541 */
12542 static int
12543#ifdef __BORLANDC__
12544_RTLENTRYF
12545#endif
12546item_compare(const void *s1, const void *s2)
12547{
12548 sortItem_T *si1, *si2;
12549 typval_T *tv1, *tv2;
12550 char_u *p1, *p2;
12551 char_u *tofree1 = NULL, *tofree2 = NULL;
12552 int res;
12553 char_u numbuf1[NUMBUFLEN];
12554 char_u numbuf2[NUMBUFLEN];
12555
12556 si1 = (sortItem_T *)s1;
12557 si2 = (sortItem_T *)s2;
12558 tv1 = &si1->item->li_tv;
12559 tv2 = &si2->item->li_tv;
12560
12561 if (sortinfo->item_compare_numbers)
12562 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012563 varnumber_T v1 = tv_get_number(tv1);
12564 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012565
12566 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12567 }
12568
12569#ifdef FEAT_FLOAT
12570 if (sortinfo->item_compare_float)
12571 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012572 float_T v1 = tv_get_float(tv1);
12573 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012574
12575 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12576 }
12577#endif
12578
12579 /* tv2string() puts quotes around a string and allocates memory. Don't do
12580 * that for string variables. Use a single quote when comparing with a
12581 * non-string to do what the docs promise. */
12582 if (tv1->v_type == VAR_STRING)
12583 {
12584 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12585 p1 = (char_u *)"'";
12586 else
12587 p1 = tv1->vval.v_string;
12588 }
12589 else
12590 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12591 if (tv2->v_type == VAR_STRING)
12592 {
12593 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12594 p2 = (char_u *)"'";
12595 else
12596 p2 = tv2->vval.v_string;
12597 }
12598 else
12599 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12600 if (p1 == NULL)
12601 p1 = (char_u *)"";
12602 if (p2 == NULL)
12603 p2 = (char_u *)"";
12604 if (!sortinfo->item_compare_numeric)
12605 {
12606 if (sortinfo->item_compare_ic)
12607 res = STRICMP(p1, p2);
12608 else
12609 res = STRCMP(p1, p2);
12610 }
12611 else
12612 {
12613 double n1, n2;
12614 n1 = strtod((char *)p1, (char **)&p1);
12615 n2 = strtod((char *)p2, (char **)&p2);
12616 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12617 }
12618
12619 /* When the result would be zero, compare the item indexes. Makes the
12620 * sort stable. */
12621 if (res == 0 && !sortinfo->item_compare_keep_zero)
12622 res = si1->idx > si2->idx ? 1 : -1;
12623
12624 vim_free(tofree1);
12625 vim_free(tofree2);
12626 return res;
12627}
12628
12629 static int
12630#ifdef __BORLANDC__
12631_RTLENTRYF
12632#endif
12633item_compare2(const void *s1, const void *s2)
12634{
12635 sortItem_T *si1, *si2;
12636 int res;
12637 typval_T rettv;
12638 typval_T argv[3];
12639 int dummy;
12640 char_u *func_name;
12641 partial_T *partial = sortinfo->item_compare_partial;
12642
12643 /* shortcut after failure in previous call; compare all items equal */
12644 if (sortinfo->item_compare_func_err)
12645 return 0;
12646
12647 si1 = (sortItem_T *)s1;
12648 si2 = (sortItem_T *)s2;
12649
12650 if (partial == NULL)
12651 func_name = sortinfo->item_compare_func;
12652 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012653 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012654
12655 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12656 * in the copy without changing the original list items. */
12657 copy_tv(&si1->item->li_tv, &argv[0]);
12658 copy_tv(&si2->item->li_tv, &argv[1]);
12659
12660 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12661 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012662 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012663 partial, sortinfo->item_compare_selfdict);
12664 clear_tv(&argv[0]);
12665 clear_tv(&argv[1]);
12666
12667 if (res == FAIL)
12668 res = ITEM_COMPARE_FAIL;
12669 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012670 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012671 if (sortinfo->item_compare_func_err)
12672 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12673 clear_tv(&rettv);
12674
12675 /* When the result would be zero, compare the pointers themselves. Makes
12676 * the sort stable. */
12677 if (res == 0 && !sortinfo->item_compare_keep_zero)
12678 res = si1->idx > si2->idx ? 1 : -1;
12679
12680 return res;
12681}
12682
12683/*
12684 * "sort({list})" function
12685 */
12686 static void
12687do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12688{
12689 list_T *l;
12690 listitem_T *li;
12691 sortItem_T *ptrs;
12692 sortinfo_T *old_sortinfo;
12693 sortinfo_T info;
12694 long len;
12695 long i;
12696
12697 /* Pointer to current info struct used in compare function. Save and
12698 * restore the current one for nested calls. */
12699 old_sortinfo = sortinfo;
12700 sortinfo = &info;
12701
12702 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012703 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012704 else
12705 {
12706 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012707 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012708 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12709 TRUE))
12710 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012711 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012712
12713 len = list_len(l);
12714 if (len <= 1)
12715 goto theend; /* short list sorts pretty quickly */
12716
12717 info.item_compare_ic = FALSE;
12718 info.item_compare_numeric = FALSE;
12719 info.item_compare_numbers = FALSE;
12720#ifdef FEAT_FLOAT
12721 info.item_compare_float = FALSE;
12722#endif
12723 info.item_compare_func = NULL;
12724 info.item_compare_partial = NULL;
12725 info.item_compare_selfdict = NULL;
12726 if (argvars[1].v_type != VAR_UNKNOWN)
12727 {
12728 /* optional second argument: {func} */
12729 if (argvars[1].v_type == VAR_FUNC)
12730 info.item_compare_func = argvars[1].vval.v_string;
12731 else if (argvars[1].v_type == VAR_PARTIAL)
12732 info.item_compare_partial = argvars[1].vval.v_partial;
12733 else
12734 {
12735 int error = FALSE;
12736
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012737 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012738 if (error)
12739 goto theend; /* type error; errmsg already given */
12740 if (i == 1)
12741 info.item_compare_ic = TRUE;
12742 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012743 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012744 else if (i != 0)
12745 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012746 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012747 goto theend;
12748 }
12749 if (info.item_compare_func != NULL)
12750 {
12751 if (*info.item_compare_func == NUL)
12752 {
12753 /* empty string means default sort */
12754 info.item_compare_func = NULL;
12755 }
12756 else if (STRCMP(info.item_compare_func, "n") == 0)
12757 {
12758 info.item_compare_func = NULL;
12759 info.item_compare_numeric = TRUE;
12760 }
12761 else if (STRCMP(info.item_compare_func, "N") == 0)
12762 {
12763 info.item_compare_func = NULL;
12764 info.item_compare_numbers = TRUE;
12765 }
12766#ifdef FEAT_FLOAT
12767 else if (STRCMP(info.item_compare_func, "f") == 0)
12768 {
12769 info.item_compare_func = NULL;
12770 info.item_compare_float = TRUE;
12771 }
12772#endif
12773 else if (STRCMP(info.item_compare_func, "i") == 0)
12774 {
12775 info.item_compare_func = NULL;
12776 info.item_compare_ic = TRUE;
12777 }
12778 }
12779 }
12780
12781 if (argvars[2].v_type != VAR_UNKNOWN)
12782 {
12783 /* optional third argument: {dict} */
12784 if (argvars[2].v_type != VAR_DICT)
12785 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012786 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012787 goto theend;
12788 }
12789 info.item_compare_selfdict = argvars[2].vval.v_dict;
12790 }
12791 }
12792
12793 /* Make an array with each entry pointing to an item in the List. */
12794 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12795 if (ptrs == NULL)
12796 goto theend;
12797
12798 i = 0;
12799 if (sort)
12800 {
12801 /* sort(): ptrs will be the list to sort */
12802 for (li = l->lv_first; li != NULL; li = li->li_next)
12803 {
12804 ptrs[i].item = li;
12805 ptrs[i].idx = i;
12806 ++i;
12807 }
12808
12809 info.item_compare_func_err = FALSE;
12810 info.item_compare_keep_zero = FALSE;
12811 /* test the compare function */
12812 if ((info.item_compare_func != NULL
12813 || info.item_compare_partial != NULL)
12814 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12815 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012816 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012817 else
12818 {
12819 /* Sort the array with item pointers. */
12820 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12821 info.item_compare_func == NULL
12822 && info.item_compare_partial == NULL
12823 ? item_compare : item_compare2);
12824
12825 if (!info.item_compare_func_err)
12826 {
12827 /* Clear the List and append the items in sorted order. */
12828 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12829 l->lv_len = 0;
12830 for (i = 0; i < len; ++i)
12831 list_append(l, ptrs[i].item);
12832 }
12833 }
12834 }
12835 else
12836 {
12837 int (*item_compare_func_ptr)(const void *, const void *);
12838
12839 /* f_uniq(): ptrs will be a stack of items to remove */
12840 info.item_compare_func_err = FALSE;
12841 info.item_compare_keep_zero = TRUE;
12842 item_compare_func_ptr = info.item_compare_func != NULL
12843 || info.item_compare_partial != NULL
12844 ? item_compare2 : item_compare;
12845
12846 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12847 li = li->li_next)
12848 {
12849 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12850 == 0)
12851 ptrs[i++].item = li;
12852 if (info.item_compare_func_err)
12853 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012854 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012855 break;
12856 }
12857 }
12858
12859 if (!info.item_compare_func_err)
12860 {
12861 while (--i >= 0)
12862 {
12863 li = ptrs[i].item->li_next;
12864 ptrs[i].item->li_next = li->li_next;
12865 if (li->li_next != NULL)
12866 li->li_next->li_prev = ptrs[i].item;
12867 else
12868 l->lv_last = ptrs[i].item;
12869 list_fix_watch(l, li);
12870 listitem_free(li);
12871 l->lv_len--;
12872 }
12873 }
12874 }
12875
12876 vim_free(ptrs);
12877 }
12878theend:
12879 sortinfo = old_sortinfo;
12880}
12881
12882/*
12883 * "sort({list})" function
12884 */
12885 static void
12886f_sort(typval_T *argvars, typval_T *rettv)
12887{
12888 do_sort_uniq(argvars, rettv, TRUE);
12889}
12890
12891/*
12892 * "uniq({list})" function
12893 */
12894 static void
12895f_uniq(typval_T *argvars, typval_T *rettv)
12896{
12897 do_sort_uniq(argvars, rettv, FALSE);
12898}
12899
12900/*
12901 * "soundfold({word})" function
12902 */
12903 static void
12904f_soundfold(typval_T *argvars, typval_T *rettv)
12905{
12906 char_u *s;
12907
12908 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012909 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012910#ifdef FEAT_SPELL
12911 rettv->vval.v_string = eval_soundfold(s);
12912#else
12913 rettv->vval.v_string = vim_strsave(s);
12914#endif
12915}
12916
12917/*
12918 * "spellbadword()" function
12919 */
12920 static void
12921f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12922{
12923 char_u *word = (char_u *)"";
12924 hlf_T attr = HLF_COUNT;
12925 int len = 0;
12926
12927 if (rettv_list_alloc(rettv) == FAIL)
12928 return;
12929
12930#ifdef FEAT_SPELL
12931 if (argvars[0].v_type == VAR_UNKNOWN)
12932 {
12933 /* Find the start and length of the badly spelled word. */
12934 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12935 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012936 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012937 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012938 curwin->w_set_curswant = TRUE;
12939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012940 }
12941 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12942 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012943 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944 int capcol = -1;
12945
12946 if (str != NULL)
12947 {
12948 /* Check the argument for spelling. */
12949 while (*str != NUL)
12950 {
12951 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12952 if (attr != HLF_COUNT)
12953 {
12954 word = str;
12955 break;
12956 }
12957 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012958 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012959 }
12960 }
12961 }
12962#endif
12963
12964 list_append_string(rettv->vval.v_list, word, len);
12965 list_append_string(rettv->vval.v_list, (char_u *)(
12966 attr == HLF_SPB ? "bad" :
12967 attr == HLF_SPR ? "rare" :
12968 attr == HLF_SPL ? "local" :
12969 attr == HLF_SPC ? "caps" :
12970 ""), -1);
12971}
12972
12973/*
12974 * "spellsuggest()" function
12975 */
12976 static void
12977f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12978{
12979#ifdef FEAT_SPELL
12980 char_u *str;
12981 int typeerr = FALSE;
12982 int maxcount;
12983 garray_T ga;
12984 int i;
12985 listitem_T *li;
12986 int need_capital = FALSE;
12987#endif
12988
12989 if (rettv_list_alloc(rettv) == FAIL)
12990 return;
12991
12992#ifdef FEAT_SPELL
12993 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12994 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012995 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012996 if (argvars[1].v_type != VAR_UNKNOWN)
12997 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012998 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012999 if (maxcount <= 0)
13000 return;
13001 if (argvars[2].v_type != VAR_UNKNOWN)
13002 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013003 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013004 if (typeerr)
13005 return;
13006 }
13007 }
13008 else
13009 maxcount = 25;
13010
13011 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
13012
13013 for (i = 0; i < ga.ga_len; ++i)
13014 {
13015 str = ((char_u **)ga.ga_data)[i];
13016
13017 li = listitem_alloc();
13018 if (li == NULL)
13019 vim_free(str);
13020 else
13021 {
13022 li->li_tv.v_type = VAR_STRING;
13023 li->li_tv.v_lock = 0;
13024 li->li_tv.vval.v_string = str;
13025 list_append(rettv->vval.v_list, li);
13026 }
13027 }
13028 ga_clear(&ga);
13029 }
13030#endif
13031}
13032
13033 static void
13034f_split(typval_T *argvars, typval_T *rettv)
13035{
13036 char_u *str;
13037 char_u *end;
13038 char_u *pat = NULL;
13039 regmatch_T regmatch;
13040 char_u patbuf[NUMBUFLEN];
13041 char_u *save_cpo;
13042 int match;
13043 colnr_T col = 0;
13044 int keepempty = FALSE;
13045 int typeerr = FALSE;
13046
13047 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
13048 save_cpo = p_cpo;
13049 p_cpo = (char_u *)"";
13050
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013051 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013052 if (argvars[1].v_type != VAR_UNKNOWN)
13053 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013054 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013055 if (pat == NULL)
13056 typeerr = TRUE;
13057 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013058 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013059 }
13060 if (pat == NULL || *pat == NUL)
13061 pat = (char_u *)"[\\x01- ]\\+";
13062
13063 if (rettv_list_alloc(rettv) == FAIL)
13064 return;
13065 if (typeerr)
13066 return;
13067
13068 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
13069 if (regmatch.regprog != NULL)
13070 {
13071 regmatch.rm_ic = FALSE;
13072 while (*str != NUL || keepempty)
13073 {
13074 if (*str == NUL)
13075 match = FALSE; /* empty item at the end */
13076 else
13077 match = vim_regexec_nl(&regmatch, str, col);
13078 if (match)
13079 end = regmatch.startp[0];
13080 else
13081 end = str + STRLEN(str);
13082 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
13083 && *str != NUL && match && end < regmatch.endp[0]))
13084 {
13085 if (list_append_string(rettv->vval.v_list, str,
13086 (int)(end - str)) == FAIL)
13087 break;
13088 }
13089 if (!match)
13090 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010013091 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013092 if (regmatch.endp[0] > str)
13093 col = 0;
13094 else
Bram Moolenaar13505972019-01-24 15:04:48 +010013095 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013096 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013097 str = regmatch.endp[0];
13098 }
13099
13100 vim_regfree(regmatch.regprog);
13101 }
13102
13103 p_cpo = save_cpo;
13104}
13105
13106#ifdef FEAT_FLOAT
13107/*
13108 * "sqrt()" function
13109 */
13110 static void
13111f_sqrt(typval_T *argvars, typval_T *rettv)
13112{
13113 float_T f = 0.0;
13114
13115 rettv->v_type = VAR_FLOAT;
13116 if (get_float_arg(argvars, &f) == OK)
13117 rettv->vval.v_float = sqrt(f);
13118 else
13119 rettv->vval.v_float = 0.0;
13120}
13121
13122/*
13123 * "str2float()" function
13124 */
13125 static void
13126f_str2float(typval_T *argvars, typval_T *rettv)
13127{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013128 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010013129 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013130
Bram Moolenaar08243d22017-01-10 16:12:29 +010013131 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013132 p = skipwhite(p + 1);
13133 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010013134 if (isneg)
13135 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013136 rettv->v_type = VAR_FLOAT;
13137}
13138#endif
13139
13140/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020013141 * "str2list()" function
13142 */
13143 static void
13144f_str2list(typval_T *argvars, typval_T *rettv)
13145{
13146 char_u *p;
13147 int utf8 = FALSE;
13148
13149 if (rettv_list_alloc(rettv) == FAIL)
13150 return;
13151
13152 if (argvars[1].v_type != VAR_UNKNOWN)
13153 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
13154
13155 p = tv_get_string(&argvars[0]);
13156
13157 if (has_mbyte || utf8)
13158 {
13159 int (*ptr2len)(char_u *);
13160 int (*ptr2char)(char_u *);
13161
13162 if (utf8 || enc_utf8)
13163 {
13164 ptr2len = utf_ptr2len;
13165 ptr2char = utf_ptr2char;
13166 }
13167 else
13168 {
13169 ptr2len = mb_ptr2len;
13170 ptr2char = mb_ptr2char;
13171 }
13172
13173 for ( ; *p != NUL; p += (*ptr2len)(p))
13174 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
13175 }
13176 else
13177 for ( ; *p != NUL; ++p)
13178 list_append_number(rettv->vval.v_list, *p);
13179}
13180
13181/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013182 * "str2nr()" function
13183 */
13184 static void
13185f_str2nr(typval_T *argvars, typval_T *rettv)
13186{
13187 int base = 10;
13188 char_u *p;
13189 varnumber_T n;
13190 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010013191 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013192
13193 if (argvars[1].v_type != VAR_UNKNOWN)
13194 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013195 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013196 if (base != 2 && base != 8 && base != 10 && base != 16)
13197 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013198 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013199 return;
13200 }
13201 }
13202
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013203 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010013204 isneg = (*p == '-');
13205 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013206 p = skipwhite(p + 1);
13207 switch (base)
13208 {
13209 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
13210 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
13211 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
13212 default: what = 0;
13213 }
13214 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010013215 if (isneg)
13216 rettv->vval.v_number = -n;
13217 else
13218 rettv->vval.v_number = n;
13219
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013220}
13221
13222#ifdef HAVE_STRFTIME
13223/*
13224 * "strftime({format}[, {time}])" function
13225 */
13226 static void
13227f_strftime(typval_T *argvars, typval_T *rettv)
13228{
13229 char_u result_buf[256];
13230 struct tm *curtime;
13231 time_t seconds;
13232 char_u *p;
13233
13234 rettv->v_type = VAR_STRING;
13235
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013236 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013237 if (argvars[1].v_type == VAR_UNKNOWN)
13238 seconds = time(NULL);
13239 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013240 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013241 curtime = localtime(&seconds);
13242 /* MSVC returns NULL for an invalid value of seconds. */
13243 if (curtime == NULL)
13244 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
13245 else
13246 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013247 vimconv_T conv;
13248 char_u *enc;
13249
13250 conv.vc_type = CONV_NONE;
13251 enc = enc_locale();
13252 convert_setup(&conv, p_enc, enc);
13253 if (conv.vc_type != CONV_NONE)
13254 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013255 if (p != NULL)
13256 (void)strftime((char *)result_buf, sizeof(result_buf),
13257 (char *)p, curtime);
13258 else
13259 result_buf[0] = NUL;
13260
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013261 if (conv.vc_type != CONV_NONE)
13262 vim_free(p);
13263 convert_setup(&conv, enc, p_enc);
13264 if (conv.vc_type != CONV_NONE)
13265 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
13266 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013267 rettv->vval.v_string = vim_strsave(result_buf);
13268
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013269 /* Release conversion descriptors */
13270 convert_setup(&conv, NULL, NULL);
13271 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013272 }
13273}
13274#endif
13275
13276/*
13277 * "strgetchar()" function
13278 */
13279 static void
13280f_strgetchar(typval_T *argvars, typval_T *rettv)
13281{
13282 char_u *str;
13283 int len;
13284 int error = FALSE;
13285 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010013286 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013287
13288 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013289 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013290 if (str == NULL)
13291 return;
13292 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013293 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013294 if (error)
13295 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013296
Bram Moolenaar13505972019-01-24 15:04:48 +010013297 while (charidx >= 0 && byteidx < len)
13298 {
13299 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013300 {
Bram Moolenaar13505972019-01-24 15:04:48 +010013301 rettv->vval.v_number = mb_ptr2char(str + byteidx);
13302 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013303 }
Bram Moolenaar13505972019-01-24 15:04:48 +010013304 --charidx;
13305 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013306 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013307}
13308
13309/*
13310 * "stridx()" function
13311 */
13312 static void
13313f_stridx(typval_T *argvars, typval_T *rettv)
13314{
13315 char_u buf[NUMBUFLEN];
13316 char_u *needle;
13317 char_u *haystack;
13318 char_u *save_haystack;
13319 char_u *pos;
13320 int start_idx;
13321
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013322 needle = tv_get_string_chk(&argvars[1]);
13323 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013324 rettv->vval.v_number = -1;
13325 if (needle == NULL || haystack == NULL)
13326 return; /* type error; errmsg already given */
13327
13328 if (argvars[2].v_type != VAR_UNKNOWN)
13329 {
13330 int error = FALSE;
13331
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013332 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013333 if (error || start_idx >= (int)STRLEN(haystack))
13334 return;
13335 if (start_idx >= 0)
13336 haystack += start_idx;
13337 }
13338
13339 pos = (char_u *)strstr((char *)haystack, (char *)needle);
13340 if (pos != NULL)
13341 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
13342}
13343
13344/*
13345 * "string()" function
13346 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010013347 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013348f_string(typval_T *argvars, typval_T *rettv)
13349{
13350 char_u *tofree;
13351 char_u numbuf[NUMBUFLEN];
13352
13353 rettv->v_type = VAR_STRING;
13354 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
13355 get_copyID());
13356 /* Make a copy if we have a value but it's not in allocated memory. */
13357 if (rettv->vval.v_string != NULL && tofree == NULL)
13358 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
13359}
13360
13361/*
13362 * "strlen()" function
13363 */
13364 static void
13365f_strlen(typval_T *argvars, typval_T *rettv)
13366{
13367 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013368 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013369}
13370
13371/*
13372 * "strchars()" function
13373 */
13374 static void
13375f_strchars(typval_T *argvars, typval_T *rettv)
13376{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013377 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013378 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013379 varnumber_T len = 0;
13380 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013381
13382 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013383 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013384 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013385 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013386 else
13387 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013388 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
13389 while (*s != NUL)
13390 {
13391 func_mb_ptr2char_adv(&s);
13392 ++len;
13393 }
13394 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013395 }
13396}
13397
13398/*
13399 * "strdisplaywidth()" function
13400 */
13401 static void
13402f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
13403{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013404 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013405 int col = 0;
13406
13407 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013408 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013409
13410 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
13411}
13412
13413/*
13414 * "strwidth()" function
13415 */
13416 static void
13417f_strwidth(typval_T *argvars, typval_T *rettv)
13418{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013419 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013420
Bram Moolenaar13505972019-01-24 15:04:48 +010013421 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013422}
13423
13424/*
13425 * "strcharpart()" function
13426 */
13427 static void
13428f_strcharpart(typval_T *argvars, typval_T *rettv)
13429{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013430 char_u *p;
13431 int nchar;
13432 int nbyte = 0;
13433 int charlen;
13434 int len = 0;
13435 int slen;
13436 int error = FALSE;
13437
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013438 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013439 slen = (int)STRLEN(p);
13440
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013441 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013442 if (!error)
13443 {
13444 if (nchar > 0)
13445 while (nchar > 0 && nbyte < slen)
13446 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020013447 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013448 --nchar;
13449 }
13450 else
13451 nbyte = nchar;
13452 if (argvars[2].v_type != VAR_UNKNOWN)
13453 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013454 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013455 while (charlen > 0 && nbyte + len < slen)
13456 {
13457 int off = nbyte + len;
13458
13459 if (off < 0)
13460 len += 1;
13461 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020013462 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013463 --charlen;
13464 }
13465 }
13466 else
13467 len = slen - nbyte; /* default: all bytes that are available. */
13468 }
13469
13470 /*
13471 * Only return the overlap between the specified part and the actual
13472 * string.
13473 */
13474 if (nbyte < 0)
13475 {
13476 len += nbyte;
13477 nbyte = 0;
13478 }
13479 else if (nbyte > slen)
13480 nbyte = slen;
13481 if (len < 0)
13482 len = 0;
13483 else if (nbyte + len > slen)
13484 len = slen - nbyte;
13485
13486 rettv->v_type = VAR_STRING;
13487 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013488}
13489
13490/*
13491 * "strpart()" function
13492 */
13493 static void
13494f_strpart(typval_T *argvars, typval_T *rettv)
13495{
13496 char_u *p;
13497 int n;
13498 int len;
13499 int slen;
13500 int error = FALSE;
13501
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013502 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013503 slen = (int)STRLEN(p);
13504
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013505 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013506 if (error)
13507 len = 0;
13508 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013509 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013510 else
13511 len = slen - n; /* default len: all bytes that are available. */
13512
13513 /*
13514 * Only return the overlap between the specified part and the actual
13515 * string.
13516 */
13517 if (n < 0)
13518 {
13519 len += n;
13520 n = 0;
13521 }
13522 else if (n > slen)
13523 n = slen;
13524 if (len < 0)
13525 len = 0;
13526 else if (n + len > slen)
13527 len = slen - n;
13528
13529 rettv->v_type = VAR_STRING;
13530 rettv->vval.v_string = vim_strnsave(p + n, len);
13531}
13532
13533/*
13534 * "strridx()" function
13535 */
13536 static void
13537f_strridx(typval_T *argvars, typval_T *rettv)
13538{
13539 char_u buf[NUMBUFLEN];
13540 char_u *needle;
13541 char_u *haystack;
13542 char_u *rest;
13543 char_u *lastmatch = NULL;
13544 int haystack_len, end_idx;
13545
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013546 needle = tv_get_string_chk(&argvars[1]);
13547 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013548
13549 rettv->vval.v_number = -1;
13550 if (needle == NULL || haystack == NULL)
13551 return; /* type error; errmsg already given */
13552
13553 haystack_len = (int)STRLEN(haystack);
13554 if (argvars[2].v_type != VAR_UNKNOWN)
13555 {
13556 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013557 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013558 if (end_idx < 0)
13559 return; /* can never find a match */
13560 }
13561 else
13562 end_idx = haystack_len;
13563
13564 if (*needle == NUL)
13565 {
13566 /* Empty string matches past the end. */
13567 lastmatch = haystack + end_idx;
13568 }
13569 else
13570 {
13571 for (rest = haystack; *rest != '\0'; ++rest)
13572 {
13573 rest = (char_u *)strstr((char *)rest, (char *)needle);
13574 if (rest == NULL || rest > haystack + end_idx)
13575 break;
13576 lastmatch = rest;
13577 }
13578 }
13579
13580 if (lastmatch == NULL)
13581 rettv->vval.v_number = -1;
13582 else
13583 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13584}
13585
13586/*
13587 * "strtrans()" function
13588 */
13589 static void
13590f_strtrans(typval_T *argvars, typval_T *rettv)
13591{
13592 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013593 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013594}
13595
13596/*
13597 * "submatch()" function
13598 */
13599 static void
13600f_submatch(typval_T *argvars, typval_T *rettv)
13601{
13602 int error = FALSE;
13603 int no;
13604 int retList = 0;
13605
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013606 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013607 if (error)
13608 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013609 if (no < 0 || no >= NSUBEXP)
13610 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013611 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013612 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013613 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013614 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013615 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013616 if (error)
13617 return;
13618
13619 if (retList == 0)
13620 {
13621 rettv->v_type = VAR_STRING;
13622 rettv->vval.v_string = reg_submatch(no);
13623 }
13624 else
13625 {
13626 rettv->v_type = VAR_LIST;
13627 rettv->vval.v_list = reg_submatch_list(no);
13628 }
13629}
13630
13631/*
13632 * "substitute()" function
13633 */
13634 static void
13635f_substitute(typval_T *argvars, typval_T *rettv)
13636{
13637 char_u patbuf[NUMBUFLEN];
13638 char_u subbuf[NUMBUFLEN];
13639 char_u flagsbuf[NUMBUFLEN];
13640
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013641 char_u *str = tv_get_string_chk(&argvars[0]);
13642 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013643 char_u *sub = NULL;
13644 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013645 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013646
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013647 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13648 expr = &argvars[2];
13649 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013650 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013651
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013652 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013653 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13654 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013655 rettv->vval.v_string = NULL;
13656 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013657 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013658}
13659
13660/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013661 * "swapinfo(swap_filename)" function
13662 */
13663 static void
13664f_swapinfo(typval_T *argvars, typval_T *rettv)
13665{
13666 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013667 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013668}
13669
13670/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013671 * "swapname(expr)" function
13672 */
13673 static void
13674f_swapname(typval_T *argvars, typval_T *rettv)
13675{
13676 buf_T *buf;
13677
13678 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013679 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013680 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13681 || buf->b_ml.ml_mfp->mf_fname == NULL)
13682 rettv->vval.v_string = NULL;
13683 else
13684 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13685}
13686
13687/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013688 * "synID(lnum, col, trans)" function
13689 */
13690 static void
13691f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13692{
13693 int id = 0;
13694#ifdef FEAT_SYN_HL
13695 linenr_T lnum;
13696 colnr_T col;
13697 int trans;
13698 int transerr = FALSE;
13699
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013700 lnum = tv_get_lnum(argvars); /* -1 on type error */
13701 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13702 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013703
13704 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13705 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13706 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13707#endif
13708
13709 rettv->vval.v_number = id;
13710}
13711
13712/*
13713 * "synIDattr(id, what [, mode])" function
13714 */
13715 static void
13716f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13717{
13718 char_u *p = NULL;
13719#ifdef FEAT_SYN_HL
13720 int id;
13721 char_u *what;
13722 char_u *mode;
13723 char_u modebuf[NUMBUFLEN];
13724 int modec;
13725
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013726 id = (int)tv_get_number(&argvars[0]);
13727 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013728 if (argvars[2].v_type != VAR_UNKNOWN)
13729 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013730 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013731 modec = TOLOWER_ASC(mode[0]);
13732 if (modec != 't' && modec != 'c' && modec != 'g')
13733 modec = 0; /* replace invalid with current */
13734 }
13735 else
13736 {
13737#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13738 if (USE_24BIT)
13739 modec = 'g';
13740 else
13741#endif
13742 if (t_colors > 1)
13743 modec = 'c';
13744 else
13745 modec = 't';
13746 }
13747
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013748 switch (TOLOWER_ASC(what[0]))
13749 {
13750 case 'b':
13751 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13752 p = highlight_color(id, what, modec);
13753 else /* bold */
13754 p = highlight_has_attr(id, HL_BOLD, modec);
13755 break;
13756
13757 case 'f': /* fg[#] or font */
13758 p = highlight_color(id, what, modec);
13759 break;
13760
13761 case 'i':
13762 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13763 p = highlight_has_attr(id, HL_INVERSE, modec);
13764 else /* italic */
13765 p = highlight_has_attr(id, HL_ITALIC, modec);
13766 break;
13767
13768 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013769 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013770 break;
13771
13772 case 'r': /* reverse */
13773 p = highlight_has_attr(id, HL_INVERSE, modec);
13774 break;
13775
13776 case 's':
13777 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13778 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013779 /* strikeout */
13780 else if (TOLOWER_ASC(what[1]) == 't' &&
13781 TOLOWER_ASC(what[2]) == 'r')
13782 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013783 else /* standout */
13784 p = highlight_has_attr(id, HL_STANDOUT, modec);
13785 break;
13786
13787 case 'u':
13788 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13789 /* underline */
13790 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13791 else
13792 /* undercurl */
13793 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13794 break;
13795 }
13796
13797 if (p != NULL)
13798 p = vim_strsave(p);
13799#endif
13800 rettv->v_type = VAR_STRING;
13801 rettv->vval.v_string = p;
13802}
13803
13804/*
13805 * "synIDtrans(id)" function
13806 */
13807 static void
13808f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13809{
13810 int id;
13811
13812#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013813 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013814
13815 if (id > 0)
13816 id = syn_get_final_id(id);
13817 else
13818#endif
13819 id = 0;
13820
13821 rettv->vval.v_number = id;
13822}
13823
13824/*
13825 * "synconcealed(lnum, col)" function
13826 */
13827 static void
13828f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13829{
13830#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13831 linenr_T lnum;
13832 colnr_T col;
13833 int syntax_flags = 0;
13834 int cchar;
13835 int matchid = 0;
13836 char_u str[NUMBUFLEN];
13837#endif
13838
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013839 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013840
13841#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013842 lnum = tv_get_lnum(argvars); /* -1 on type error */
13843 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013844
13845 vim_memset(str, NUL, sizeof(str));
13846
13847 if (rettv_list_alloc(rettv) != FAIL)
13848 {
13849 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13850 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13851 && curwin->w_p_cole > 0)
13852 {
13853 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13854 syntax_flags = get_syntax_info(&matchid);
13855
13856 /* get the conceal character */
13857 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13858 {
13859 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013860 if (cchar == NUL && curwin->w_p_cole == 1)
13861 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013862 if (cchar != NUL)
13863 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013864 if (has_mbyte)
13865 (*mb_char2bytes)(cchar, str);
13866 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013867 str[0] = cchar;
13868 }
13869 }
13870 }
13871
13872 list_append_number(rettv->vval.v_list,
13873 (syntax_flags & HL_CONCEAL) != 0);
13874 /* -1 to auto-determine strlen */
13875 list_append_string(rettv->vval.v_list, str, -1);
13876 list_append_number(rettv->vval.v_list, matchid);
13877 }
13878#endif
13879}
13880
13881/*
13882 * "synstack(lnum, col)" function
13883 */
13884 static void
13885f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13886{
13887#ifdef FEAT_SYN_HL
13888 linenr_T lnum;
13889 colnr_T col;
13890 int i;
13891 int id;
13892#endif
13893
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013894 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013895
13896#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013897 lnum = tv_get_lnum(argvars); /* -1 on type error */
13898 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013899
13900 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13901 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13902 && rettv_list_alloc(rettv) != FAIL)
13903 {
13904 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13905 for (i = 0; ; ++i)
13906 {
13907 id = syn_get_stack_item(i);
13908 if (id < 0)
13909 break;
13910 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13911 break;
13912 }
13913 }
13914#endif
13915}
13916
13917 static void
13918get_cmd_output_as_rettv(
13919 typval_T *argvars,
13920 typval_T *rettv,
13921 int retlist)
13922{
13923 char_u *res = NULL;
13924 char_u *p;
13925 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013926 int err = FALSE;
13927 FILE *fd;
13928 list_T *list = NULL;
13929 int flags = SHELL_SILENT;
13930
13931 rettv->v_type = VAR_STRING;
13932 rettv->vval.v_string = NULL;
13933 if (check_restricted() || check_secure())
13934 goto errret;
13935
13936 if (argvars[1].v_type != VAR_UNKNOWN)
13937 {
13938 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013939 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013940 * command.
13941 */
13942 if ((infile = vim_tempname('i', TRUE)) == NULL)
13943 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013944 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013945 goto errret;
13946 }
13947
13948 fd = mch_fopen((char *)infile, WRITEBIN);
13949 if (fd == NULL)
13950 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013951 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013952 goto errret;
13953 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013954 if (argvars[1].v_type == VAR_NUMBER)
13955 {
13956 linenr_T lnum;
13957 buf_T *buf;
13958
13959 buf = buflist_findnr(argvars[1].vval.v_number);
13960 if (buf == NULL)
13961 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013962 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013963 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013964 goto errret;
13965 }
13966
13967 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13968 {
13969 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13970 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13971 {
13972 err = TRUE;
13973 break;
13974 }
13975 if (putc(NL, fd) == EOF)
13976 {
13977 err = TRUE;
13978 break;
13979 }
13980 }
13981 }
13982 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013983 {
13984 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13985 err = TRUE;
13986 }
13987 else
13988 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013989 size_t len;
13990 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013991
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013992 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013993 if (p == NULL)
13994 {
13995 fclose(fd);
13996 goto errret; /* type error; errmsg already given */
13997 }
13998 len = STRLEN(p);
13999 if (len > 0 && fwrite(p, len, 1, fd) != 1)
14000 err = TRUE;
14001 }
14002 if (fclose(fd) != 0)
14003 err = TRUE;
14004 if (err)
14005 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014006 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014007 goto errret;
14008 }
14009 }
14010
14011 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
14012 * echoes typeahead, that messes up the display. */
14013 if (!msg_silent)
14014 flags += SHELL_COOKED;
14015
14016 if (retlist)
14017 {
14018 int len;
14019 listitem_T *li;
14020 char_u *s = NULL;
14021 char_u *start;
14022 char_u *end;
14023 int i;
14024
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014025 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014026 if (res == NULL)
14027 goto errret;
14028
14029 list = list_alloc();
14030 if (list == NULL)
14031 goto errret;
14032
14033 for (i = 0; i < len; ++i)
14034 {
14035 start = res + i;
14036 while (i < len && res[i] != NL)
14037 ++i;
14038 end = res + i;
14039
14040 s = alloc((unsigned)(end - start + 1));
14041 if (s == NULL)
14042 goto errret;
14043
14044 for (p = s; start < end; ++p, ++start)
14045 *p = *start == NUL ? NL : *start;
14046 *p = NUL;
14047
14048 li = listitem_alloc();
14049 if (li == NULL)
14050 {
14051 vim_free(s);
14052 goto errret;
14053 }
14054 li->li_tv.v_type = VAR_STRING;
14055 li->li_tv.v_lock = 0;
14056 li->li_tv.vval.v_string = s;
14057 list_append(list, li);
14058 }
14059
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014060 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014061 list = NULL;
14062 }
14063 else
14064 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014065 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010014066#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014067 /* translate <CR><NL> into <NL> */
14068 if (res != NULL)
14069 {
14070 char_u *s, *d;
14071
14072 d = res;
14073 for (s = res; *s; ++s)
14074 {
14075 if (s[0] == CAR && s[1] == NL)
14076 ++s;
14077 *d++ = *s;
14078 }
14079 *d = NUL;
14080 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014081#endif
14082 rettv->vval.v_string = res;
14083 res = NULL;
14084 }
14085
14086errret:
14087 if (infile != NULL)
14088 {
14089 mch_remove(infile);
14090 vim_free(infile);
14091 }
14092 if (res != NULL)
14093 vim_free(res);
14094 if (list != NULL)
14095 list_free(list);
14096}
14097
14098/*
14099 * "system()" function
14100 */
14101 static void
14102f_system(typval_T *argvars, typval_T *rettv)
14103{
14104 get_cmd_output_as_rettv(argvars, rettv, FALSE);
14105}
14106
14107/*
14108 * "systemlist()" function
14109 */
14110 static void
14111f_systemlist(typval_T *argvars, typval_T *rettv)
14112{
14113 get_cmd_output_as_rettv(argvars, rettv, TRUE);
14114}
14115
14116/*
14117 * "tabpagebuflist()" function
14118 */
14119 static void
14120f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14121{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014122 tabpage_T *tp;
14123 win_T *wp = NULL;
14124
14125 if (argvars[0].v_type == VAR_UNKNOWN)
14126 wp = firstwin;
14127 else
14128 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014129 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014130 if (tp != NULL)
14131 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
14132 }
14133 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
14134 {
14135 for (; wp != NULL; wp = wp->w_next)
14136 if (list_append_number(rettv->vval.v_list,
14137 wp->w_buffer->b_fnum) == FAIL)
14138 break;
14139 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014140}
14141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014142/*
14143 * "tabpagenr()" function
14144 */
14145 static void
14146f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
14147{
14148 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014149 char_u *arg;
14150
14151 if (argvars[0].v_type != VAR_UNKNOWN)
14152 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014153 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014154 nr = 0;
14155 if (arg != NULL)
14156 {
14157 if (STRCMP(arg, "$") == 0)
14158 nr = tabpage_index(NULL) - 1;
14159 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014160 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014161 }
14162 }
14163 else
14164 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014165 rettv->vval.v_number = nr;
14166}
14167
14168
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014169/*
14170 * Common code for tabpagewinnr() and winnr().
14171 */
14172 static int
14173get_winnr(tabpage_T *tp, typval_T *argvar)
14174{
14175 win_T *twin;
14176 int nr = 1;
14177 win_T *wp;
14178 char_u *arg;
14179
14180 twin = (tp == curtab) ? curwin : tp->tp_curwin;
14181 if (argvar->v_type != VAR_UNKNOWN)
14182 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020014183 int invalid_arg = FALSE;
14184
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014185 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014186 if (arg == NULL)
14187 nr = 0; /* type error; errmsg already given */
14188 else if (STRCMP(arg, "$") == 0)
14189 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
14190 else if (STRCMP(arg, "#") == 0)
14191 {
14192 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
14193 if (twin == NULL)
14194 nr = 0;
14195 }
14196 else
14197 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020014198 long count;
14199 char_u *endp;
14200
14201 // Extract the window count (if specified). e.g. winnr('3j')
14202 count = strtol((char *)arg, (char **)&endp, 10);
14203 if (count <= 0)
14204 count = 1; // if count is not specified, default to 1
14205 if (endp != NULL && *endp != '\0')
14206 {
14207 if (STRCMP(endp, "j") == 0)
14208 twin = win_vert_neighbor(tp, twin, FALSE, count);
14209 else if (STRCMP(endp, "k") == 0)
14210 twin = win_vert_neighbor(tp, twin, TRUE, count);
14211 else if (STRCMP(endp, "h") == 0)
14212 twin = win_horz_neighbor(tp, twin, TRUE, count);
14213 else if (STRCMP(endp, "l") == 0)
14214 twin = win_horz_neighbor(tp, twin, FALSE, count);
14215 else
14216 invalid_arg = TRUE;
14217 }
14218 else
14219 invalid_arg = TRUE;
14220 }
14221
14222 if (invalid_arg)
14223 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014224 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014225 nr = 0;
14226 }
14227 }
14228
14229 if (nr > 0)
14230 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
14231 wp != twin; wp = wp->w_next)
14232 {
14233 if (wp == NULL)
14234 {
14235 /* didn't find it in this tabpage */
14236 nr = 0;
14237 break;
14238 }
14239 ++nr;
14240 }
14241 return nr;
14242}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014243
14244/*
14245 * "tabpagewinnr()" function
14246 */
14247 static void
14248f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
14249{
14250 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014251 tabpage_T *tp;
14252
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014253 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014254 if (tp == NULL)
14255 nr = 0;
14256 else
14257 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014258 rettv->vval.v_number = nr;
14259}
14260
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014261/*
14262 * "tagfiles()" function
14263 */
14264 static void
14265f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
14266{
14267 char_u *fname;
14268 tagname_T tn;
14269 int first;
14270
14271 if (rettv_list_alloc(rettv) == FAIL)
14272 return;
14273 fname = alloc(MAXPATHL);
14274 if (fname == NULL)
14275 return;
14276
14277 for (first = TRUE; ; first = FALSE)
14278 if (get_tagfname(&tn, first, fname) == FAIL
14279 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
14280 break;
14281 tagname_free(&tn);
14282 vim_free(fname);
14283}
14284
14285/*
14286 * "taglist()" function
14287 */
14288 static void
14289f_taglist(typval_T *argvars, typval_T *rettv)
14290{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010014291 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014292 char_u *tag_pattern;
14293
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014294 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014295
14296 rettv->vval.v_number = FALSE;
14297 if (*tag_pattern == NUL)
14298 return;
14299
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010014300 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014301 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014302 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010014303 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014304}
14305
14306/*
14307 * "tempname()" function
14308 */
14309 static void
14310f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
14311{
14312 static int x = 'A';
14313
14314 rettv->v_type = VAR_STRING;
14315 rettv->vval.v_string = vim_tempname(x, FALSE);
14316
14317 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
14318 * names. Skip 'I' and 'O', they are used for shell redirection. */
14319 do
14320 {
14321 if (x == 'Z')
14322 x = '0';
14323 else if (x == '9')
14324 x = 'A';
14325 else
14326 {
14327#ifdef EBCDIC
14328 if (x == 'I')
14329 x = 'J';
14330 else if (x == 'R')
14331 x = 'S';
14332 else
14333#endif
14334 ++x;
14335 }
14336 } while (x == 'I' || x == 'O');
14337}
14338
14339#ifdef FEAT_FLOAT
14340/*
14341 * "tan()" function
14342 */
14343 static void
14344f_tan(typval_T *argvars, typval_T *rettv)
14345{
14346 float_T f = 0.0;
14347
14348 rettv->v_type = VAR_FLOAT;
14349 if (get_float_arg(argvars, &f) == OK)
14350 rettv->vval.v_float = tan(f);
14351 else
14352 rettv->vval.v_float = 0.0;
14353}
14354
14355/*
14356 * "tanh()" function
14357 */
14358 static void
14359f_tanh(typval_T *argvars, typval_T *rettv)
14360{
14361 float_T f = 0.0;
14362
14363 rettv->v_type = VAR_FLOAT;
14364 if (get_float_arg(argvars, &f) == OK)
14365 rettv->vval.v_float = tanh(f);
14366 else
14367 rettv->vval.v_float = 0.0;
14368}
14369#endif
14370
14371/*
14372 * "test_alloc_fail(id, countdown, repeat)" function
14373 */
14374 static void
14375f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
14376{
14377 if (argvars[0].v_type != VAR_NUMBER
14378 || argvars[0].vval.v_number <= 0
14379 || argvars[1].v_type != VAR_NUMBER
14380 || argvars[1].vval.v_number < 0
14381 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014382 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014383 else
14384 {
14385 alloc_fail_id = argvars[0].vval.v_number;
14386 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014387 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014388 alloc_fail_countdown = argvars[1].vval.v_number;
14389 alloc_fail_repeat = argvars[2].vval.v_number;
14390 did_outofmem_msg = FALSE;
14391 }
14392}
14393
14394/*
14395 * "test_autochdir()"
14396 */
14397 static void
14398f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14399{
14400#if defined(FEAT_AUTOCHDIR)
14401 test_autochdir = TRUE;
14402#endif
14403}
14404
14405/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020014406 * "test_feedinput()"
14407 */
14408 static void
14409f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
14410{
14411#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014412 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020014413
14414 if (val != NULL)
14415 {
14416 trash_input_buf();
14417 add_to_input_buf_csi(val, (int)STRLEN(val));
14418 }
14419#endif
14420}
14421
14422/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014423 * "test_option_not_set({name})" function
14424 */
14425 static void
14426f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
14427{
14428 char_u *name = (char_u *)"";
14429
14430 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014431 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014432 else
14433 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014434 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014435 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014436 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020014437 }
14438}
14439
14440/*
14441 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014442 */
14443 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014444f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014445{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014446 char_u *name = (char_u *)"";
14447 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020014448 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014449
14450 if (argvars[0].v_type != VAR_STRING
14451 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014452 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014453 else
14454 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010014455 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014456 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014457
14458 if (STRCMP(name, (char_u *)"redraw") == 0)
14459 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020014460 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
14461 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014462 else if (STRCMP(name, (char_u *)"char_avail") == 0)
14463 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020014464 else if (STRCMP(name, (char_u *)"starting") == 0)
14465 {
14466 if (val)
14467 {
14468 if (save_starting < 0)
14469 save_starting = starting;
14470 starting = 0;
14471 }
14472 else
14473 {
14474 starting = save_starting;
14475 save_starting = -1;
14476 }
14477 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020014478 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
14479 nfa_fail_for_testing = val;
Bram Moolenaar92fd5992019-05-02 23:00:22 +020014480 else if (STRCMP(name, (char_u *)"no_query_mouse") == 0)
14481 no_query_mouse_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014482 else if (STRCMP(name, (char_u *)"ALL") == 0)
14483 {
14484 disable_char_avail_for_testing = FALSE;
14485 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020014486 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020014487 nfa_fail_for_testing = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +020014488 no_query_mouse_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020014489 if (save_starting >= 0)
14490 {
14491 starting = save_starting;
14492 save_starting = -1;
14493 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014494 }
14495 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014496 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014497 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014498}
14499
14500/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010014501 * "test_refcount({expr})" function
14502 */
14503 static void
14504f_test_refcount(typval_T *argvars, typval_T *rettv)
14505{
14506 int retval = -1;
14507
14508 switch (argvars[0].v_type)
14509 {
14510 case VAR_UNKNOWN:
14511 case VAR_NUMBER:
14512 case VAR_FLOAT:
14513 case VAR_SPECIAL:
14514 case VAR_STRING:
14515 break;
14516 case VAR_JOB:
14517#ifdef FEAT_JOB_CHANNEL
14518 if (argvars[0].vval.v_job != NULL)
14519 retval = argvars[0].vval.v_job->jv_refcount - 1;
14520#endif
14521 break;
14522 case VAR_CHANNEL:
14523#ifdef FEAT_JOB_CHANNEL
14524 if (argvars[0].vval.v_channel != NULL)
14525 retval = argvars[0].vval.v_channel->ch_refcount - 1;
14526#endif
14527 break;
14528 case VAR_FUNC:
14529 if (argvars[0].vval.v_string != NULL)
14530 {
14531 ufunc_T *fp;
14532
14533 fp = find_func(argvars[0].vval.v_string);
14534 if (fp != NULL)
14535 retval = fp->uf_refcount;
14536 }
14537 break;
14538 case VAR_PARTIAL:
14539 if (argvars[0].vval.v_partial != NULL)
14540 retval = argvars[0].vval.v_partial->pt_refcount - 1;
14541 break;
14542 case VAR_BLOB:
14543 if (argvars[0].vval.v_blob != NULL)
14544 retval = argvars[0].vval.v_blob->bv_refcount - 1;
14545 break;
14546 case VAR_LIST:
14547 if (argvars[0].vval.v_list != NULL)
14548 retval = argvars[0].vval.v_list->lv_refcount - 1;
14549 break;
14550 case VAR_DICT:
14551 if (argvars[0].vval.v_dict != NULL)
14552 retval = argvars[0].vval.v_dict->dv_refcount - 1;
14553 break;
14554 }
14555
14556 rettv->v_type = VAR_NUMBER;
14557 rettv->vval.v_number = retval;
14558
14559}
14560
14561/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014562 * "test_garbagecollect_now()" function
14563 */
14564 static void
14565f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14566{
14567 /* This is dangerous, any Lists and Dicts used internally may be freed
14568 * while still in use. */
14569 garbage_collect(TRUE);
14570}
14571
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014572/*
14573 * "test_ignore_error()" function
14574 */
14575 static void
14576f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
14577{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014578 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014579}
14580
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010014581 static void
14582f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
14583{
14584 rettv->v_type = VAR_BLOB;
14585 rettv->vval.v_blob = NULL;
14586}
14587
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014588#ifdef FEAT_JOB_CHANNEL
14589 static void
14590f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
14591{
14592 rettv->v_type = VAR_CHANNEL;
14593 rettv->vval.v_channel = NULL;
14594}
14595#endif
14596
14597 static void
14598f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
14599{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014600 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014601}
14602
14603#ifdef FEAT_JOB_CHANNEL
14604 static void
14605f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14606{
14607 rettv->v_type = VAR_JOB;
14608 rettv->vval.v_job = NULL;
14609}
14610#endif
14611
14612 static void
14613f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14614{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014615 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014616}
14617
14618 static void
14619f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14620{
14621 rettv->v_type = VAR_PARTIAL;
14622 rettv->vval.v_partial = NULL;
14623}
14624
14625 static void
14626f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14627{
14628 rettv->v_type = VAR_STRING;
14629 rettv->vval.v_string = NULL;
14630}
14631
Bram Moolenaarab186732018-09-14 21:27:06 +020014632#ifdef FEAT_GUI
14633 static void
14634f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14635{
14636 char_u *which;
14637 long value;
14638 int dragging;
14639 scrollbar_T *sb = NULL;
14640
14641 if (argvars[0].v_type != VAR_STRING
14642 || (argvars[1].v_type) != VAR_NUMBER
14643 || (argvars[2].v_type) != VAR_NUMBER)
14644 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014645 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014646 return;
14647 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014648 which = tv_get_string(&argvars[0]);
14649 value = tv_get_number(&argvars[1]);
14650 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014651
14652 if (STRCMP(which, "left") == 0)
14653 sb = &curwin->w_scrollbars[SBAR_LEFT];
14654 else if (STRCMP(which, "right") == 0)
14655 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14656 else if (STRCMP(which, "hor") == 0)
14657 sb = &gui.bottom_sbar;
14658 if (sb == NULL)
14659 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014660 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014661 return;
14662 }
14663 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014664# ifndef USE_ON_FLY_SCROLL
14665 // need to loop through normal_cmd() to handle the scroll events
14666 exec_normal(FALSE, TRUE, FALSE);
14667# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014668}
14669#endif
14670
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +020014671#ifdef FEAT_MOUSE
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014672 static void
Bram Moolenaarbb8476b2019-05-04 15:47:48 +020014673f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
14674{
14675 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
14676 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
14677}
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +020014678#endif
Bram Moolenaarbb8476b2019-05-04 15:47:48 +020014679
14680 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014681f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14682{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014683 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014684}
14685
14686#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14687/*
14688 * Get a callback from "arg". It can be a Funcref or a function name.
14689 * When "arg" is zero return an empty string.
14690 * Return NULL for an invalid argument.
14691 */
14692 char_u *
14693get_callback(typval_T *arg, partial_T **pp)
14694{
14695 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14696 {
14697 *pp = arg->vval.v_partial;
14698 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014699 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014700 }
14701 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014702 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014703 {
14704 func_ref(arg->vval.v_string);
14705 return arg->vval.v_string;
14706 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014707 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14708 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014709 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014710 return NULL;
14711}
14712
14713/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014714 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014715 */
14716 void
14717free_callback(char_u *callback, partial_T *partial)
14718{
14719 if (partial != NULL)
14720 partial_unref(partial);
14721 else if (callback != NULL)
14722 {
14723 func_unref(callback);
14724 vim_free(callback);
14725 }
14726}
14727#endif
14728
14729#ifdef FEAT_TIMERS
14730/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014731 * "timer_info([timer])" function
14732 */
14733 static void
14734f_timer_info(typval_T *argvars, typval_T *rettv)
14735{
14736 timer_T *timer = NULL;
14737
14738 if (rettv_list_alloc(rettv) != OK)
14739 return;
14740 if (argvars[0].v_type != VAR_UNKNOWN)
14741 {
14742 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014743 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014744 else
14745 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014746 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014747 if (timer != NULL)
14748 add_timer_info(rettv, timer);
14749 }
14750 }
14751 else
14752 add_timer_info_all(rettv);
14753}
14754
14755/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014756 * "timer_pause(timer, paused)" function
14757 */
14758 static void
14759f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14760{
14761 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014762 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014763
14764 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014765 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014766 else
14767 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014768 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014769 if (timer != NULL)
14770 timer->tr_paused = paused;
14771 }
14772}
14773
14774/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014775 * "timer_start(time, callback [, options])" function
14776 */
14777 static void
14778f_timer_start(typval_T *argvars, typval_T *rettv)
14779{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014780 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014781 timer_T *timer;
14782 int repeat = 0;
14783 char_u *callback;
14784 dict_T *dict;
14785 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014786
Bram Moolenaar75537a92016-09-05 22:45:28 +020014787 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014788 if (check_secure())
14789 return;
14790 if (argvars[2].v_type != VAR_UNKNOWN)
14791 {
14792 if (argvars[2].v_type != VAR_DICT
14793 || (dict = argvars[2].vval.v_dict) == NULL)
14794 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014795 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014796 return;
14797 }
14798 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014799 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014800 }
14801
Bram Moolenaar75537a92016-09-05 22:45:28 +020014802 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014803 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014804 return;
14805
14806 timer = create_timer(msec, repeat);
14807 if (timer == NULL)
14808 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014809 else
14810 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014811 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014812 timer->tr_callback = vim_strsave(callback);
14813 else
14814 /* pointer into the partial */
14815 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014816 timer->tr_partial = partial;
14817 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014818 }
14819}
14820
14821/*
14822 * "timer_stop(timer)" function
14823 */
14824 static void
14825f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14826{
14827 timer_T *timer;
14828
14829 if (argvars[0].v_type != VAR_NUMBER)
14830 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014831 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014832 return;
14833 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014834 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014835 if (timer != NULL)
14836 stop_timer(timer);
14837}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014838
14839/*
14840 * "timer_stopall()" function
14841 */
14842 static void
14843f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14844{
14845 stop_all_timers();
14846}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014847#endif
14848
14849/*
14850 * "tolower(string)" function
14851 */
14852 static void
14853f_tolower(typval_T *argvars, typval_T *rettv)
14854{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014855 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014856 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014857}
14858
14859/*
14860 * "toupper(string)" function
14861 */
14862 static void
14863f_toupper(typval_T *argvars, typval_T *rettv)
14864{
14865 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014866 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014867}
14868
14869/*
14870 * "tr(string, fromstr, tostr)" function
14871 */
14872 static void
14873f_tr(typval_T *argvars, typval_T *rettv)
14874{
14875 char_u *in_str;
14876 char_u *fromstr;
14877 char_u *tostr;
14878 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014879 int inlen;
14880 int fromlen;
14881 int tolen;
14882 int idx;
14883 char_u *cpstr;
14884 int cplen;
14885 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014886 char_u buf[NUMBUFLEN];
14887 char_u buf2[NUMBUFLEN];
14888 garray_T ga;
14889
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014890 in_str = tv_get_string(&argvars[0]);
14891 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14892 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014893
14894 /* Default return value: empty string. */
14895 rettv->v_type = VAR_STRING;
14896 rettv->vval.v_string = NULL;
14897 if (fromstr == NULL || tostr == NULL)
14898 return; /* type error; errmsg already given */
14899 ga_init2(&ga, (int)sizeof(char), 80);
14900
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014901 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014902 /* not multi-byte: fromstr and tostr must be the same length */
14903 if (STRLEN(fromstr) != STRLEN(tostr))
14904 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014905error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014906 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014907 ga_clear(&ga);
14908 return;
14909 }
14910
14911 /* fromstr and tostr have to contain the same number of chars */
14912 while (*in_str != NUL)
14913 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014914 if (has_mbyte)
14915 {
14916 inlen = (*mb_ptr2len)(in_str);
14917 cpstr = in_str;
14918 cplen = inlen;
14919 idx = 0;
14920 for (p = fromstr; *p != NUL; p += fromlen)
14921 {
14922 fromlen = (*mb_ptr2len)(p);
14923 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14924 {
14925 for (p = tostr; *p != NUL; p += tolen)
14926 {
14927 tolen = (*mb_ptr2len)(p);
14928 if (idx-- == 0)
14929 {
14930 cplen = tolen;
14931 cpstr = p;
14932 break;
14933 }
14934 }
14935 if (*p == NUL) /* tostr is shorter than fromstr */
14936 goto error;
14937 break;
14938 }
14939 ++idx;
14940 }
14941
14942 if (first && cpstr == in_str)
14943 {
14944 /* Check that fromstr and tostr have the same number of
14945 * (multi-byte) characters. Done only once when a character
14946 * of in_str doesn't appear in fromstr. */
14947 first = FALSE;
14948 for (p = tostr; *p != NUL; p += tolen)
14949 {
14950 tolen = (*mb_ptr2len)(p);
14951 --idx;
14952 }
14953 if (idx != 0)
14954 goto error;
14955 }
14956
14957 (void)ga_grow(&ga, cplen);
14958 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14959 ga.ga_len += cplen;
14960
14961 in_str += inlen;
14962 }
14963 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014964 {
14965 /* When not using multi-byte chars we can do it faster. */
14966 p = vim_strchr(fromstr, *in_str);
14967 if (p != NULL)
14968 ga_append(&ga, tostr[p - fromstr]);
14969 else
14970 ga_append(&ga, *in_str);
14971 ++in_str;
14972 }
14973 }
14974
14975 /* add a terminating NUL */
14976 (void)ga_grow(&ga, 1);
14977 ga_append(&ga, NUL);
14978
14979 rettv->vval.v_string = ga.ga_data;
14980}
14981
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014982/*
14983 * "trim({expr})" function
14984 */
14985 static void
14986f_trim(typval_T *argvars, typval_T *rettv)
14987{
14988 char_u buf1[NUMBUFLEN];
14989 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014990 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014991 char_u *mask = NULL;
14992 char_u *tail;
14993 char_u *prev;
14994 char_u *p;
14995 int c1;
14996
14997 rettv->v_type = VAR_STRING;
14998 if (head == NULL)
14999 {
15000 rettv->vval.v_string = NULL;
15001 return;
15002 }
15003
15004 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015005 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010015006
15007 while (*head != NUL)
15008 {
15009 c1 = PTR2CHAR(head);
15010 if (mask == NULL)
15011 {
15012 if (c1 > ' ' && c1 != 0xa0)
15013 break;
15014 }
15015 else
15016 {
15017 for (p = mask; *p != NUL; MB_PTR_ADV(p))
15018 if (c1 == PTR2CHAR(p))
15019 break;
15020 if (*p == NUL)
15021 break;
15022 }
15023 MB_PTR_ADV(head);
15024 }
15025
15026 for (tail = head + STRLEN(head); tail > head; tail = prev)
15027 {
15028 prev = tail;
15029 MB_PTR_BACK(head, prev);
15030 c1 = PTR2CHAR(prev);
15031 if (mask == NULL)
15032 {
15033 if (c1 > ' ' && c1 != 0xa0)
15034 break;
15035 }
15036 else
15037 {
15038 for (p = mask; *p != NUL; MB_PTR_ADV(p))
15039 if (c1 == PTR2CHAR(p))
15040 break;
15041 if (*p == NUL)
15042 break;
15043 }
15044 }
15045 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
15046}
15047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015048#ifdef FEAT_FLOAT
15049/*
15050 * "trunc({float})" function
15051 */
15052 static void
15053f_trunc(typval_T *argvars, typval_T *rettv)
15054{
15055 float_T f = 0.0;
15056
15057 rettv->v_type = VAR_FLOAT;
15058 if (get_float_arg(argvars, &f) == OK)
15059 /* trunc() is not in C90, use floor() or ceil() instead. */
15060 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
15061 else
15062 rettv->vval.v_float = 0.0;
15063}
15064#endif
15065
15066/*
15067 * "type(expr)" function
15068 */
15069 static void
15070f_type(typval_T *argvars, typval_T *rettv)
15071{
15072 int n = -1;
15073
15074 switch (argvars[0].v_type)
15075 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020015076 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
15077 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015078 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020015079 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
15080 case VAR_LIST: n = VAR_TYPE_LIST; break;
15081 case VAR_DICT: n = VAR_TYPE_DICT; break;
15082 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015083 case VAR_SPECIAL:
15084 if (argvars[0].vval.v_number == VVAL_FALSE
15085 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020015086 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015087 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020015088 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015089 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020015090 case VAR_JOB: n = VAR_TYPE_JOB; break;
15091 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015092 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015093 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010015094 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015095 n = -1;
15096 break;
15097 }
15098 rettv->vval.v_number = n;
15099}
15100
15101/*
15102 * "undofile(name)" function
15103 */
15104 static void
15105f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
15106{
15107 rettv->v_type = VAR_STRING;
15108#ifdef FEAT_PERSISTENT_UNDO
15109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015110 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015111
15112 if (*fname == NUL)
15113 {
15114 /* If there is no file name there will be no undo file. */
15115 rettv->vval.v_string = NULL;
15116 }
15117 else
15118 {
15119 char_u *ffname = FullName_save(fname, FALSE);
15120
15121 if (ffname != NULL)
15122 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
15123 vim_free(ffname);
15124 }
15125 }
15126#else
15127 rettv->vval.v_string = NULL;
15128#endif
15129}
15130
15131/*
15132 * "undotree()" function
15133 */
15134 static void
15135f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
15136{
15137 if (rettv_dict_alloc(rettv) == OK)
15138 {
15139 dict_T *dict = rettv->vval.v_dict;
15140 list_T *list;
15141
Bram Moolenaare0be1672018-07-08 16:50:37 +020015142 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
15143 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
15144 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
15145 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
15146 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
15147 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015148
15149 list = list_alloc();
15150 if (list != NULL)
15151 {
15152 u_eval_tree(curbuf->b_u_oldhead, list);
15153 dict_add_list(dict, "entries", list);
15154 }
15155 }
15156}
15157
15158/*
15159 * "values(dict)" function
15160 */
15161 static void
15162f_values(typval_T *argvars, typval_T *rettv)
15163{
15164 dict_list(argvars, rettv, 1);
15165}
15166
15167/*
15168 * "virtcol(string)" function
15169 */
15170 static void
15171f_virtcol(typval_T *argvars, typval_T *rettv)
15172{
15173 colnr_T vcol = 0;
15174 pos_T *fp;
15175 int fnum = curbuf->b_fnum;
15176
15177 fp = var2fpos(&argvars[0], FALSE, &fnum);
15178 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
15179 && fnum == curbuf->b_fnum)
15180 {
15181 getvvcol(curwin, fp, NULL, NULL, &vcol);
15182 ++vcol;
15183 }
15184
15185 rettv->vval.v_number = vcol;
15186}
15187
15188/*
15189 * "visualmode()" function
15190 */
15191 static void
15192f_visualmode(typval_T *argvars, typval_T *rettv)
15193{
15194 char_u str[2];
15195
15196 rettv->v_type = VAR_STRING;
15197 str[0] = curbuf->b_visual_mode_eval;
15198 str[1] = NUL;
15199 rettv->vval.v_string = vim_strsave(str);
15200
15201 /* A non-zero number or non-empty string argument: reset mode. */
15202 if (non_zero_arg(&argvars[0]))
15203 curbuf->b_visual_mode_eval = NUL;
15204}
15205
15206/*
15207 * "wildmenumode()" function
15208 */
15209 static void
15210f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
15211{
15212#ifdef FEAT_WILDMENU
15213 if (wild_menu_showing)
15214 rettv->vval.v_number = 1;
15215#endif
15216}
15217
15218/*
15219 * "winbufnr(nr)" function
15220 */
15221 static void
15222f_winbufnr(typval_T *argvars, typval_T *rettv)
15223{
15224 win_T *wp;
15225
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020015226 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015227 if (wp == NULL)
15228 rettv->vval.v_number = -1;
15229 else
15230 rettv->vval.v_number = wp->w_buffer->b_fnum;
15231}
15232
15233/*
15234 * "wincol()" function
15235 */
15236 static void
15237f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
15238{
15239 validate_cursor();
15240 rettv->vval.v_number = curwin->w_wcol + 1;
15241}
15242
15243/*
15244 * "winheight(nr)" function
15245 */
15246 static void
15247f_winheight(typval_T *argvars, typval_T *rettv)
15248{
15249 win_T *wp;
15250
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020015251 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015252 if (wp == NULL)
15253 rettv->vval.v_number = -1;
15254 else
15255 rettv->vval.v_number = wp->w_height;
15256}
15257
15258/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020015259 * "winlayout()" function
15260 */
15261 static void
15262f_winlayout(typval_T *argvars, typval_T *rettv)
15263{
15264 tabpage_T *tp;
15265
15266 if (rettv_list_alloc(rettv) != OK)
15267 return;
15268
15269 if (argvars[0].v_type == VAR_UNKNOWN)
15270 tp = curtab;
15271 else
15272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015273 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020015274 if (tp == NULL)
15275 return;
15276 }
15277
15278 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
15279}
15280
15281/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015282 * "winline()" function
15283 */
15284 static void
15285f_winline(typval_T *argvars UNUSED, typval_T *rettv)
15286{
15287 validate_cursor();
15288 rettv->vval.v_number = curwin->w_wrow + 1;
15289}
15290
15291/*
15292 * "winnr()" function
15293 */
15294 static void
15295f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
15296{
15297 int nr = 1;
15298
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015299 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015300 rettv->vval.v_number = nr;
15301}
15302
15303/*
15304 * "winrestcmd()" function
15305 */
15306 static void
15307f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
15308{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015309 win_T *wp;
15310 int winnr = 1;
15311 garray_T ga;
15312 char_u buf[50];
15313
15314 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020015315 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015316 {
15317 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
15318 ga_concat(&ga, buf);
15319 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
15320 ga_concat(&ga, buf);
15321 ++winnr;
15322 }
15323 ga_append(&ga, NUL);
15324
15325 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015326 rettv->v_type = VAR_STRING;
15327}
15328
15329/*
15330 * "winrestview()" function
15331 */
15332 static void
15333f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
15334{
15335 dict_T *dict;
15336
15337 if (argvars[0].v_type != VAR_DICT
15338 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010015339 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015340 else
15341 {
15342 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015343 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015344 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015345 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015346 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015347 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015348 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
15349 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010015350 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015351 curwin->w_set_curswant = FALSE;
15352 }
15353
15354 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015355 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015356#ifdef FEAT_DIFF
15357 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015358 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015359#endif
15360 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015361 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015362 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010015363 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015364
15365 check_cursor();
15366 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020015367 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015368 changed_window_setting();
15369
15370 if (curwin->w_topline <= 0)
15371 curwin->w_topline = 1;
15372 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
15373 curwin->w_topline = curbuf->b_ml.ml_line_count;
15374#ifdef FEAT_DIFF
15375 check_topfill(curwin, TRUE);
15376#endif
15377 }
15378}
15379
15380/*
15381 * "winsaveview()" function
15382 */
15383 static void
15384f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
15385{
15386 dict_T *dict;
15387
15388 if (rettv_dict_alloc(rettv) == FAIL)
15389 return;
15390 dict = rettv->vval.v_dict;
15391
Bram Moolenaare0be1672018-07-08 16:50:37 +020015392 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
15393 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020015394 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015395 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020015396 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015397
Bram Moolenaare0be1672018-07-08 16:50:37 +020015398 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015399#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020015400 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015401#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020015402 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
15403 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015404}
15405
15406/*
15407 * "winwidth(nr)" function
15408 */
15409 static void
15410f_winwidth(typval_T *argvars, typval_T *rettv)
15411{
15412 win_T *wp;
15413
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020015414 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015415 if (wp == NULL)
15416 rettv->vval.v_number = -1;
15417 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015418 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015419}
15420
15421/*
15422 * "wordcount()" function
15423 */
15424 static void
15425f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
15426{
15427 if (rettv_dict_alloc(rettv) == FAIL)
15428 return;
15429 cursor_pos_info(rettv->vval.v_dict);
15430}
15431
15432/*
15433 * "writefile()" function
15434 */
15435 static void
15436f_writefile(typval_T *argvars, typval_T *rettv)
15437{
15438 int binary = FALSE;
15439 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015440#ifdef HAVE_FSYNC
15441 int do_fsync = p_fs;
15442#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015443 char_u *fname;
15444 FILE *fd;
15445 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015446 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015447 list_T *list = NULL;
15448 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015449
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015450 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010015451 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015452 return;
15453
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015454 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015455 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015456 list = argvars[0].vval.v_list;
15457 if (list == NULL)
15458 return;
15459 for (li = list->lv_first; li != NULL; li = li->li_next)
15460 if (tv_get_string_chk(&li->li_tv) == NULL)
15461 return;
15462 }
15463 else if (argvars[0].v_type == VAR_BLOB)
15464 {
15465 blob = argvars[0].vval.v_blob;
15466 if (blob == NULL)
15467 return;
15468 }
15469 else
15470 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010015471 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015472 return;
15473 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015474
15475 if (argvars[2].v_type != VAR_UNKNOWN)
15476 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015477 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015478
15479 if (arg2 == NULL)
15480 return;
15481 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015482 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015483 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015484 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015485#ifdef HAVE_FSYNC
15486 if (vim_strchr(arg2, 's') != NULL)
15487 do_fsync = TRUE;
15488 else if (vim_strchr(arg2, 'S') != NULL)
15489 do_fsync = FALSE;
15490#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015491 }
15492
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015493 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015494 if (fname == NULL)
15495 return;
15496
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015497 /* Always open the file in binary mode, library functions have a mind of
15498 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015499 if (*fname == NUL || (fd = mch_fopen((char *)fname,
15500 append ? APPENDBIN : WRITEBIN)) == NULL)
15501 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010015502 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015503 ret = -1;
15504 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015505 else if (blob)
15506 {
15507 if (write_blob(fd, blob) == FAIL)
15508 ret = -1;
15509#ifdef HAVE_FSYNC
15510 else if (do_fsync)
15511 // Ignore the error, the user wouldn't know what to do about it.
15512 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010015513 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015514#endif
15515 fclose(fd);
15516 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015517 else
15518 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015519 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015520 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015521#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010015522 else if (do_fsync)
15523 /* Ignore the error, the user wouldn't know what to do about it.
15524 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010015525 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015526#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015527 fclose(fd);
15528 }
15529
15530 rettv->vval.v_number = ret;
15531}
15532
15533/*
15534 * "xor(expr, expr)" function
15535 */
15536 static void
15537f_xor(typval_T *argvars, typval_T *rettv)
15538{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015539 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
15540 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015541}
15542
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015543#endif /* FEAT_EVAL */