blob: 01afa3d4aa3029a9086082211f58b2d387ecfcbb [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);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020074static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020075static void f_bufexists(typval_T *argvars, typval_T *rettv);
76static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020077static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020078static void f_bufloaded(typval_T *argvars, typval_T *rettv);
79static void f_bufname(typval_T *argvars, typval_T *rettv);
80static void f_bufnr(typval_T *argvars, typval_T *rettv);
81static void f_bufwinid(typval_T *argvars, typval_T *rettv);
82static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
83static void f_byte2line(typval_T *argvars, typval_T *rettv);
84static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
85static void f_byteidx(typval_T *argvars, typval_T *rettv);
86static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
87static void f_call(typval_T *argvars, typval_T *rettv);
88#ifdef FEAT_FLOAT
89static void f_ceil(typval_T *argvars, typval_T *rettv);
90#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_changenr(typval_T *argvars, typval_T *rettv);
92static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020093static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020094static void f_cindent(typval_T *argvars, typval_T *rettv);
95static void f_clearmatches(typval_T *argvars, typval_T *rettv);
96static void f_col(typval_T *argvars, typval_T *rettv);
97#if defined(FEAT_INS_EXPAND)
98static void f_complete(typval_T *argvars, typval_T *rettv);
99static void f_complete_add(typval_T *argvars, typval_T *rettv);
100static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +0100101static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200102#endif
103static void f_confirm(typval_T *argvars, typval_T *rettv);
104static void f_copy(typval_T *argvars, typval_T *rettv);
105#ifdef FEAT_FLOAT
106static void f_cos(typval_T *argvars, typval_T *rettv);
107static void f_cosh(typval_T *argvars, typval_T *rettv);
108#endif
109static void f_count(typval_T *argvars, typval_T *rettv);
110static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
111static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100112#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200113static void f_debugbreak(typval_T *argvars, typval_T *rettv);
114#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_deepcopy(typval_T *argvars, typval_T *rettv);
116static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200117static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_did_filetype(typval_T *argvars, typval_T *rettv);
119static void f_diff_filler(typval_T *argvars, typval_T *rettv);
120static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
121static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200122static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_escape(typval_T *argvars, typval_T *rettv);
124static void f_eval(typval_T *argvars, typval_T *rettv);
125static void f_eventhandler(typval_T *argvars, typval_T *rettv);
126static void f_executable(typval_T *argvars, typval_T *rettv);
127static void f_execute(typval_T *argvars, typval_T *rettv);
128static void f_exepath(typval_T *argvars, typval_T *rettv);
129static void f_exists(typval_T *argvars, typval_T *rettv);
130#ifdef FEAT_FLOAT
131static void f_exp(typval_T *argvars, typval_T *rettv);
132#endif
133static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200134static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_extend(typval_T *argvars, typval_T *rettv);
136static void f_feedkeys(typval_T *argvars, typval_T *rettv);
137static void f_filereadable(typval_T *argvars, typval_T *rettv);
138static void f_filewritable(typval_T *argvars, typval_T *rettv);
139static void f_filter(typval_T *argvars, typval_T *rettv);
140static void f_finddir(typval_T *argvars, typval_T *rettv);
141static void f_findfile(typval_T *argvars, typval_T *rettv);
142#ifdef FEAT_FLOAT
143static void f_float2nr(typval_T *argvars, typval_T *rettv);
144static void f_floor(typval_T *argvars, typval_T *rettv);
145static void f_fmod(typval_T *argvars, typval_T *rettv);
146#endif
147static void f_fnameescape(typval_T *argvars, typval_T *rettv);
148static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
149static void f_foldclosed(typval_T *argvars, typval_T *rettv);
150static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
151static void f_foldlevel(typval_T *argvars, typval_T *rettv);
152static void f_foldtext(typval_T *argvars, typval_T *rettv);
153static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
154static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200155static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_function(typval_T *argvars, typval_T *rettv);
157static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
158static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200159static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200160static void f_getbufline(typval_T *argvars, typval_T *rettv);
161static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100162static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_getchar(typval_T *argvars, typval_T *rettv);
164static void f_getcharmod(typval_T *argvars, typval_T *rettv);
165static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
166static void f_getcmdline(typval_T *argvars, typval_T *rettv);
167#if defined(FEAT_CMDL_COMPL)
168static void f_getcompletion(typval_T *argvars, typval_T *rettv);
169#endif
170static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
171static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
172static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
173static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200174static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_getfontname(typval_T *argvars, typval_T *rettv);
176static void f_getfperm(typval_T *argvars, typval_T *rettv);
177static void f_getfsize(typval_T *argvars, typval_T *rettv);
178static void f_getftime(typval_T *argvars, typval_T *rettv);
179static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100180static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200181static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200182static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200183static void f_getmatches(typval_T *argvars, typval_T *rettv);
184static void f_getpid(typval_T *argvars, typval_T *rettv);
185static void f_getcurpos(typval_T *argvars, typval_T *rettv);
186static void f_getpos(typval_T *argvars, typval_T *rettv);
187static void f_getqflist(typval_T *argvars, typval_T *rettv);
188static void f_getreg(typval_T *argvars, typval_T *rettv);
189static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200190static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_gettabvar(typval_T *argvars, typval_T *rettv);
192static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100193static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200194static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100195static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_getwinposx(typval_T *argvars, typval_T *rettv);
197static void f_getwinposy(typval_T *argvars, typval_T *rettv);
198static void f_getwinvar(typval_T *argvars, typval_T *rettv);
199static void f_glob(typval_T *argvars, typval_T *rettv);
200static void f_globpath(typval_T *argvars, typval_T *rettv);
201static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
202static void f_has(typval_T *argvars, typval_T *rettv);
203static void f_has_key(typval_T *argvars, typval_T *rettv);
204static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
205static void f_hasmapto(typval_T *argvars, typval_T *rettv);
206static void f_histadd(typval_T *argvars, typval_T *rettv);
207static void f_histdel(typval_T *argvars, typval_T *rettv);
208static void f_histget(typval_T *argvars, typval_T *rettv);
209static void f_histnr(typval_T *argvars, typval_T *rettv);
210static void f_hlID(typval_T *argvars, typval_T *rettv);
211static void f_hlexists(typval_T *argvars, typval_T *rettv);
212static void f_hostname(typval_T *argvars, typval_T *rettv);
213static void f_iconv(typval_T *argvars, typval_T *rettv);
214static void f_indent(typval_T *argvars, typval_T *rettv);
215static void f_index(typval_T *argvars, typval_T *rettv);
216static void f_input(typval_T *argvars, typval_T *rettv);
217static void f_inputdialog(typval_T *argvars, typval_T *rettv);
218static void f_inputlist(typval_T *argvars, typval_T *rettv);
219static void f_inputrestore(typval_T *argvars, typval_T *rettv);
220static void f_inputsave(typval_T *argvars, typval_T *rettv);
221static void f_inputsecret(typval_T *argvars, typval_T *rettv);
222static void f_insert(typval_T *argvars, typval_T *rettv);
223static void f_invert(typval_T *argvars, typval_T *rettv);
224static void f_isdirectory(typval_T *argvars, typval_T *rettv);
225static void f_islocked(typval_T *argvars, typval_T *rettv);
226#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200227static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200228static void f_isnan(typval_T *argvars, typval_T *rettv);
229#endif
230static void f_items(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200231static void f_join(typval_T *argvars, typval_T *rettv);
232static void f_js_decode(typval_T *argvars, typval_T *rettv);
233static void f_js_encode(typval_T *argvars, typval_T *rettv);
234static void f_json_decode(typval_T *argvars, typval_T *rettv);
235static void f_json_encode(typval_T *argvars, typval_T *rettv);
236static void f_keys(typval_T *argvars, typval_T *rettv);
237static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
238static void f_len(typval_T *argvars, typval_T *rettv);
239static void f_libcall(typval_T *argvars, typval_T *rettv);
240static void f_libcallnr(typval_T *argvars, typval_T *rettv);
241static void f_line(typval_T *argvars, typval_T *rettv);
242static void f_line2byte(typval_T *argvars, typval_T *rettv);
243static void f_lispindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar9d401282019-04-06 13:18:12 +0200244static void f_list2str(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_localtime(typval_T *argvars, typval_T *rettv);
246#ifdef FEAT_FLOAT
247static void f_log(typval_T *argvars, typval_T *rettv);
248static void f_log10(typval_T *argvars, typval_T *rettv);
249#endif
250#ifdef FEAT_LUA
251static void f_luaeval(typval_T *argvars, typval_T *rettv);
252#endif
253static void f_map(typval_T *argvars, typval_T *rettv);
254static void f_maparg(typval_T *argvars, typval_T *rettv);
255static void f_mapcheck(typval_T *argvars, typval_T *rettv);
256static void f_match(typval_T *argvars, typval_T *rettv);
257static void f_matchadd(typval_T *argvars, typval_T *rettv);
258static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
259static void f_matcharg(typval_T *argvars, typval_T *rettv);
260static void f_matchdelete(typval_T *argvars, typval_T *rettv);
261static void f_matchend(typval_T *argvars, typval_T *rettv);
262static void f_matchlist(typval_T *argvars, typval_T *rettv);
263static void f_matchstr(typval_T *argvars, typval_T *rettv);
264static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
265static void f_max(typval_T *argvars, typval_T *rettv);
266static void f_min(typval_T *argvars, typval_T *rettv);
267#ifdef vim_mkdir
268static void f_mkdir(typval_T *argvars, typval_T *rettv);
269#endif
270static void f_mode(typval_T *argvars, typval_T *rettv);
271#ifdef FEAT_MZSCHEME
272static void f_mzeval(typval_T *argvars, typval_T *rettv);
273#endif
274static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
275static void f_nr2char(typval_T *argvars, typval_T *rettv);
276static void f_or(typval_T *argvars, typval_T *rettv);
277static void f_pathshorten(typval_T *argvars, typval_T *rettv);
278#ifdef FEAT_PERL
279static void f_perleval(typval_T *argvars, typval_T *rettv);
280#endif
281#ifdef FEAT_FLOAT
282static void f_pow(typval_T *argvars, typval_T *rettv);
283#endif
284static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
285static void f_printf(typval_T *argvars, typval_T *rettv);
286static void f_pumvisible(typval_T *argvars, typval_T *rettv);
287#ifdef FEAT_PYTHON3
288static void f_py3eval(typval_T *argvars, typval_T *rettv);
289#endif
290#ifdef FEAT_PYTHON
291static void f_pyeval(typval_T *argvars, typval_T *rettv);
292#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100293#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
294static void f_pyxeval(typval_T *argvars, typval_T *rettv);
295#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200297static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200298static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200299static void f_reg_executing(typval_T *argvars, typval_T *rettv);
300static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200301static void f_reltime(typval_T *argvars, typval_T *rettv);
302#ifdef FEAT_FLOAT
303static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
304#endif
305static void f_reltimestr(typval_T *argvars, typval_T *rettv);
306static void f_remote_expr(typval_T *argvars, typval_T *rettv);
307static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
308static void f_remote_peek(typval_T *argvars, typval_T *rettv);
309static void f_remote_read(typval_T *argvars, typval_T *rettv);
310static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100311static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200312static void f_remove(typval_T *argvars, typval_T *rettv);
313static void f_rename(typval_T *argvars, typval_T *rettv);
314static void f_repeat(typval_T *argvars, typval_T *rettv);
315static void f_resolve(typval_T *argvars, typval_T *rettv);
316static void f_reverse(typval_T *argvars, typval_T *rettv);
317#ifdef FEAT_FLOAT
318static void f_round(typval_T *argvars, typval_T *rettv);
319#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100320#ifdef FEAT_RUBY
321static void f_rubyeval(typval_T *argvars, typval_T *rettv);
322#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200323static void f_screenattr(typval_T *argvars, typval_T *rettv);
324static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100325static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326static void f_screencol(typval_T *argvars, typval_T *rettv);
327static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100328static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200329static void f_search(typval_T *argvars, typval_T *rettv);
330static void f_searchdecl(typval_T *argvars, typval_T *rettv);
331static void f_searchpair(typval_T *argvars, typval_T *rettv);
332static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
333static void f_searchpos(typval_T *argvars, typval_T *rettv);
334static void f_server2client(typval_T *argvars, typval_T *rettv);
335static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200336static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337static void f_setbufvar(typval_T *argvars, typval_T *rettv);
338static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
339static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200340static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200341static void f_setfperm(typval_T *argvars, typval_T *rettv);
342static void f_setline(typval_T *argvars, typval_T *rettv);
343static void f_setloclist(typval_T *argvars, typval_T *rettv);
344static void f_setmatches(typval_T *argvars, typval_T *rettv);
345static void f_setpos(typval_T *argvars, typval_T *rettv);
346static void f_setqflist(typval_T *argvars, typval_T *rettv);
347static void f_setreg(typval_T *argvars, typval_T *rettv);
348static void f_settabvar(typval_T *argvars, typval_T *rettv);
349static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100350static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200351static void f_setwinvar(typval_T *argvars, typval_T *rettv);
352#ifdef FEAT_CRYPT
353static void f_sha256(typval_T *argvars, typval_T *rettv);
354#endif /* FEAT_CRYPT */
355static void f_shellescape(typval_T *argvars, typval_T *rettv);
356static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
357static void f_simplify(typval_T *argvars, typval_T *rettv);
358#ifdef FEAT_FLOAT
359static void f_sin(typval_T *argvars, typval_T *rettv);
360static void f_sinh(typval_T *argvars, typval_T *rettv);
361#endif
362static void f_sort(typval_T *argvars, typval_T *rettv);
363static void f_soundfold(typval_T *argvars, typval_T *rettv);
364static void f_spellbadword(typval_T *argvars, typval_T *rettv);
365static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
366static void f_split(typval_T *argvars, typval_T *rettv);
367#ifdef FEAT_FLOAT
368static void f_sqrt(typval_T *argvars, typval_T *rettv);
369static void f_str2float(typval_T *argvars, typval_T *rettv);
370#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200371static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200372static void f_str2nr(typval_T *argvars, typval_T *rettv);
373static void f_strchars(typval_T *argvars, typval_T *rettv);
374#ifdef HAVE_STRFTIME
375static void f_strftime(typval_T *argvars, typval_T *rettv);
376#endif
377static void f_strgetchar(typval_T *argvars, typval_T *rettv);
378static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200379static void f_strlen(typval_T *argvars, typval_T *rettv);
380static void f_strcharpart(typval_T *argvars, typval_T *rettv);
381static void f_strpart(typval_T *argvars, typval_T *rettv);
382static void f_strridx(typval_T *argvars, typval_T *rettv);
383static void f_strtrans(typval_T *argvars, typval_T *rettv);
384static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
385static void f_strwidth(typval_T *argvars, typval_T *rettv);
386static void f_submatch(typval_T *argvars, typval_T *rettv);
387static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200388static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200389static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200390static void f_synID(typval_T *argvars, typval_T *rettv);
391static void f_synIDattr(typval_T *argvars, typval_T *rettv);
392static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
393static void f_synstack(typval_T *argvars, typval_T *rettv);
394static void f_synconcealed(typval_T *argvars, typval_T *rettv);
395static void f_system(typval_T *argvars, typval_T *rettv);
396static void f_systemlist(typval_T *argvars, typval_T *rettv);
397static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
398static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
399static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
400static void f_taglist(typval_T *argvars, typval_T *rettv);
401static void f_tagfiles(typval_T *argvars, typval_T *rettv);
402static void f_tempname(typval_T *argvars, typval_T *rettv);
403static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
404static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200405static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaareda65222019-05-16 20:29:44 +0200406static void f_test_getvalue(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200407static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100408static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100409static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200410static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaaradc67142019-06-22 01:40:42 +0200411static void f_test_garbagecollect_soon(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100412static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100413static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200414#ifdef FEAT_JOB_CHANNEL
415static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
416#endif
417static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
418#ifdef FEAT_JOB_CHANNEL
419static void f_test_null_job(typval_T *argvars, typval_T *rettv);
420#endif
421static void f_test_null_list(typval_T *argvars, typval_T *rettv);
422static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
423static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200424#ifdef FEAT_GUI
425static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
426#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200427#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +0200428static void f_test_setmouse(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200429#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430static void f_test_settime(typval_T *argvars, typval_T *rettv);
431#ifdef FEAT_FLOAT
432static void f_tan(typval_T *argvars, typval_T *rettv);
433static void f_tanh(typval_T *argvars, typval_T *rettv);
434#endif
435#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200436static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200437static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200438static void f_timer_start(typval_T *argvars, typval_T *rettv);
439static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200440static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200441#endif
442static void f_tolower(typval_T *argvars, typval_T *rettv);
443static void f_toupper(typval_T *argvars, typval_T *rettv);
444static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100445static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200446#ifdef FEAT_FLOAT
447static void f_trunc(typval_T *argvars, typval_T *rettv);
448#endif
449static void f_type(typval_T *argvars, typval_T *rettv);
450static void f_undofile(typval_T *argvars, typval_T *rettv);
451static void f_undotree(typval_T *argvars, typval_T *rettv);
452static void f_uniq(typval_T *argvars, typval_T *rettv);
453static void f_values(typval_T *argvars, typval_T *rettv);
454static void f_virtcol(typval_T *argvars, typval_T *rettv);
455static void f_visualmode(typval_T *argvars, typval_T *rettv);
456static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200457static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200458static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
459static void f_win_getid(typval_T *argvars, typval_T *rettv);
460static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
461static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
462static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100463static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464static void f_winbufnr(typval_T *argvars, typval_T *rettv);
465static void f_wincol(typval_T *argvars, typval_T *rettv);
466static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200467static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200468static void f_winline(typval_T *argvars, typval_T *rettv);
469static void f_winnr(typval_T *argvars, typval_T *rettv);
470static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
471static void f_winrestview(typval_T *argvars, typval_T *rettv);
472static void f_winsaveview(typval_T *argvars, typval_T *rettv);
473static void f_winwidth(typval_T *argvars, typval_T *rettv);
474static void f_writefile(typval_T *argvars, typval_T *rettv);
475static void f_wordcount(typval_T *argvars, typval_T *rettv);
476static void f_xor(typval_T *argvars, typval_T *rettv);
477
478/*
479 * Array with names and number of arguments of all internal functions
480 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
481 */
482static struct fst
483{
484 char *f_name; /* function name */
485 char f_min_argc; /* minimal number of arguments */
486 char f_max_argc; /* maximal number of arguments */
487 void (*f_func)(typval_T *args, typval_T *rvar);
488 /* implementation of function */
489} functions[] =
490{
491#ifdef FEAT_FLOAT
492 {"abs", 1, 1, f_abs},
493 {"acos", 1, 1, f_acos}, /* WJMc */
494#endif
495 {"add", 2, 2, f_add},
496 {"and", 2, 2, f_and},
497 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200498 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200499 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200500 {"argidx", 0, 0, f_argidx},
501 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200502 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200503#ifdef FEAT_FLOAT
504 {"asin", 1, 1, f_asin}, /* WJMc */
505#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100506 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200507 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100508 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200510 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200511 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100512 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513 {"assert_match", 2, 3, f_assert_match},
514 {"assert_notequal", 2, 3, f_assert_notequal},
515 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100516 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517 {"assert_true", 1, 2, f_assert_true},
518#ifdef FEAT_FLOAT
519 {"atan", 1, 1, f_atan},
520 {"atan2", 2, 2, f_atan2},
521#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100522#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +0200523 {"balloon_gettext", 0, 0, f_balloon_gettext},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100524 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100525# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100526 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100527# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100528#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529 {"browse", 4, 4, f_browse},
530 {"browsedir", 2, 2, f_browsedir},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200531 {"bufadd", 1, 1, f_bufadd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200532 {"bufexists", 1, 1, f_bufexists},
533 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
534 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
535 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
536 {"buflisted", 1, 1, f_buflisted},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200537 {"bufload", 1, 1, f_bufload},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200538 {"bufloaded", 1, 1, f_bufloaded},
539 {"bufname", 1, 1, f_bufname},
540 {"bufnr", 1, 2, f_bufnr},
541 {"bufwinid", 1, 1, f_bufwinid},
542 {"bufwinnr", 1, 1, f_bufwinnr},
543 {"byte2line", 1, 1, f_byte2line},
544 {"byteidx", 2, 2, f_byteidx},
545 {"byteidxcomp", 2, 2, f_byteidxcomp},
546 {"call", 2, 3, f_call},
547#ifdef FEAT_FLOAT
548 {"ceil", 1, 1, f_ceil},
549#endif
550#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100551 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200552 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200553 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200554 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
555 {"ch_evalraw", 2, 3, f_ch_evalraw},
556 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
557 {"ch_getjob", 1, 1, f_ch_getjob},
558 {"ch_info", 1, 1, f_ch_info},
559 {"ch_log", 1, 2, f_ch_log},
560 {"ch_logfile", 1, 2, f_ch_logfile},
561 {"ch_open", 1, 2, f_ch_open},
562 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100563 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200564 {"ch_readraw", 1, 2, f_ch_readraw},
565 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
566 {"ch_sendraw", 2, 3, f_ch_sendraw},
567 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200568 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200569#endif
570 {"changenr", 0, 0, f_changenr},
571 {"char2nr", 1, 2, f_char2nr},
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200572 {"chdir", 1, 1, f_chdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200573 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100574 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575 {"col", 1, 1, f_col},
576#if defined(FEAT_INS_EXPAND)
577 {"complete", 2, 2, f_complete},
578 {"complete_add", 1, 1, f_complete_add},
579 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100580 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581#endif
582 {"confirm", 1, 4, f_confirm},
583 {"copy", 1, 1, f_copy},
584#ifdef FEAT_FLOAT
585 {"cos", 1, 1, f_cos},
586 {"cosh", 1, 1, f_cosh},
587#endif
588 {"count", 2, 4, f_count},
589 {"cscope_connection",0,3, f_cscope_connection},
590 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100591#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200592 {"debugbreak", 1, 1, f_debugbreak},
593#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200594 {"deepcopy", 1, 2, f_deepcopy},
595 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200596 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200597 {"did_filetype", 0, 0, f_did_filetype},
598 {"diff_filler", 1, 1, f_diff_filler},
599 {"diff_hlID", 2, 2, f_diff_hlID},
600 {"empty", 1, 1, f_empty},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200601 {"environ", 0, 0, f_environ},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200602 {"escape", 2, 2, f_escape},
603 {"eval", 1, 1, f_eval},
604 {"eventhandler", 0, 0, f_eventhandler},
605 {"executable", 1, 1, f_executable},
606 {"execute", 1, 2, f_execute},
607 {"exepath", 1, 1, f_exepath},
608 {"exists", 1, 1, f_exists},
609#ifdef FEAT_FLOAT
610 {"exp", 1, 1, f_exp},
611#endif
612 {"expand", 1, 3, f_expand},
Bram Moolenaar80dad482019-06-09 17:22:31 +0200613 {"expandcmd", 1, 1, f_expandcmd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200614 {"extend", 2, 3, f_extend},
615 {"feedkeys", 1, 2, f_feedkeys},
616 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
617 {"filereadable", 1, 1, f_filereadable},
618 {"filewritable", 1, 1, f_filewritable},
619 {"filter", 2, 2, f_filter},
620 {"finddir", 1, 3, f_finddir},
621 {"findfile", 1, 3, f_findfile},
622#ifdef FEAT_FLOAT
623 {"float2nr", 1, 1, f_float2nr},
624 {"floor", 1, 1, f_floor},
625 {"fmod", 2, 2, f_fmod},
626#endif
627 {"fnameescape", 1, 1, f_fnameescape},
628 {"fnamemodify", 2, 2, f_fnamemodify},
629 {"foldclosed", 1, 1, f_foldclosed},
630 {"foldclosedend", 1, 1, f_foldclosedend},
631 {"foldlevel", 1, 1, f_foldlevel},
632 {"foldtext", 0, 0, f_foldtext},
633 {"foldtextresult", 1, 1, f_foldtextresult},
634 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200635 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636 {"function", 1, 3, f_function},
637 {"garbagecollect", 0, 1, f_garbagecollect},
638 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200639 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640 {"getbufline", 2, 3, f_getbufline},
641 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100642 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643 {"getchar", 0, 1, f_getchar},
644 {"getcharmod", 0, 0, f_getcharmod},
645 {"getcharsearch", 0, 0, f_getcharsearch},
646 {"getcmdline", 0, 0, f_getcmdline},
647 {"getcmdpos", 0, 0, f_getcmdpos},
648 {"getcmdtype", 0, 0, f_getcmdtype},
649 {"getcmdwintype", 0, 0, f_getcmdwintype},
650#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200651 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652#endif
653 {"getcurpos", 0, 0, f_getcurpos},
654 {"getcwd", 0, 2, f_getcwd},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200655 {"getenv", 1, 1, f_getenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200656 {"getfontname", 0, 1, f_getfontname},
657 {"getfperm", 1, 1, f_getfperm},
658 {"getfsize", 1, 1, f_getfsize},
659 {"getftime", 1, 1, f_getftime},
660 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100661 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200663 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100664 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665 {"getpid", 0, 0, f_getpid},
666 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200667 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200668 {"getreg", 0, 3, f_getreg},
669 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200670 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200671 {"gettabvar", 2, 3, f_gettabvar},
672 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100673 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200674 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100675 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200676 {"getwinposx", 0, 0, f_getwinposx},
677 {"getwinposy", 0, 0, f_getwinposy},
678 {"getwinvar", 2, 3, f_getwinvar},
679 {"glob", 1, 4, f_glob},
680 {"glob2regpat", 1, 1, f_glob2regpat},
681 {"globpath", 2, 5, f_globpath},
682 {"has", 1, 1, f_has},
683 {"has_key", 2, 2, f_has_key},
684 {"haslocaldir", 0, 2, f_haslocaldir},
685 {"hasmapto", 1, 3, f_hasmapto},
686 {"highlightID", 1, 1, f_hlID}, /* obsolete */
687 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
688 {"histadd", 2, 2, f_histadd},
689 {"histdel", 1, 2, f_histdel},
690 {"histget", 1, 2, f_histget},
691 {"histnr", 1, 1, f_histnr},
692 {"hlID", 1, 1, f_hlID},
693 {"hlexists", 1, 1, f_hlexists},
694 {"hostname", 0, 0, f_hostname},
695 {"iconv", 3, 3, f_iconv},
696 {"indent", 1, 1, f_indent},
697 {"index", 2, 4, f_index},
698 {"input", 1, 3, f_input},
699 {"inputdialog", 1, 3, f_inputdialog},
700 {"inputlist", 1, 1, f_inputlist},
701 {"inputrestore", 0, 0, f_inputrestore},
702 {"inputsave", 0, 0, f_inputsave},
703 {"inputsecret", 1, 2, f_inputsecret},
704 {"insert", 2, 3, f_insert},
705 {"invert", 1, 1, f_invert},
706 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200707#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
708 {"isinf", 1, 1, f_isinf},
709#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200710 {"islocked", 1, 1, f_islocked},
711#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
712 {"isnan", 1, 1, f_isnan},
713#endif
714 {"items", 1, 1, f_items},
715#ifdef FEAT_JOB_CHANNEL
716 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200717 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200718 {"job_setoptions", 2, 2, f_job_setoptions},
719 {"job_start", 1, 2, f_job_start},
720 {"job_status", 1, 1, f_job_status},
721 {"job_stop", 1, 2, f_job_stop},
722#endif
723 {"join", 1, 2, f_join},
724 {"js_decode", 1, 1, f_js_decode},
725 {"js_encode", 1, 1, f_js_encode},
726 {"json_decode", 1, 1, f_json_decode},
727 {"json_encode", 1, 1, f_json_encode},
728 {"keys", 1, 1, f_keys},
729 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
730 {"len", 1, 1, f_len},
731 {"libcall", 3, 3, f_libcall},
732 {"libcallnr", 3, 3, f_libcallnr},
733 {"line", 1, 1, f_line},
734 {"line2byte", 1, 1, f_line2byte},
735 {"lispindent", 1, 1, f_lispindent},
Bram Moolenaar9d401282019-04-06 13:18:12 +0200736 {"list2str", 1, 2, f_list2str},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200737 {"listener_add", 1, 2, f_listener_add},
Bram Moolenaarfe1ade02019-05-14 21:20:36 +0200738 {"listener_flush", 0, 1, f_listener_flush},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200739 {"listener_remove", 1, 1, f_listener_remove},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200740 {"localtime", 0, 0, f_localtime},
741#ifdef FEAT_FLOAT
742 {"log", 1, 1, f_log},
743 {"log10", 1, 1, f_log10},
744#endif
745#ifdef FEAT_LUA
746 {"luaeval", 1, 2, f_luaeval},
747#endif
748 {"map", 2, 2, f_map},
749 {"maparg", 1, 4, f_maparg},
750 {"mapcheck", 1, 3, f_mapcheck},
751 {"match", 2, 4, f_match},
752 {"matchadd", 2, 5, f_matchadd},
753 {"matchaddpos", 2, 5, f_matchaddpos},
754 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100755 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200756 {"matchend", 2, 4, f_matchend},
757 {"matchlist", 2, 4, f_matchlist},
758 {"matchstr", 2, 4, f_matchstr},
759 {"matchstrpos", 2, 4, f_matchstrpos},
760 {"max", 1, 1, f_max},
761 {"min", 1, 1, f_min},
762#ifdef vim_mkdir
763 {"mkdir", 1, 3, f_mkdir},
764#endif
765 {"mode", 0, 1, f_mode},
766#ifdef FEAT_MZSCHEME
767 {"mzeval", 1, 1, f_mzeval},
768#endif
769 {"nextnonblank", 1, 1, f_nextnonblank},
770 {"nr2char", 1, 2, f_nr2char},
771 {"or", 2, 2, f_or},
772 {"pathshorten", 1, 1, f_pathshorten},
773#ifdef FEAT_PERL
774 {"perleval", 1, 1, f_perleval},
775#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200776#ifdef FEAT_TEXT_PROP
Bram Moolenaarcc31ad92019-05-30 19:25:06 +0200777 {"popup_atcursor", 2, 2, f_popup_atcursor},
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200778 {"popup_clear", 0, 0, f_popup_clear},
Bram Moolenaar9eaac892019-06-01 22:49:29 +0200779 {"popup_close", 1, 2, f_popup_close},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200780 {"popup_create", 2, 2, f_popup_create},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200781 {"popup_dialog", 2, 2, f_popup_dialog},
Bram Moolenaara730e552019-06-16 19:05:31 +0200782 {"popup_filter_menu", 2, 2, f_popup_filter_menu},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200783 {"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
Bram Moolenaar8c2a6002019-05-30 14:29:45 +0200784 {"popup_getoptions", 1, 1, f_popup_getoptions},
Bram Moolenaarccd6e342019-05-30 22:35:18 +0200785 {"popup_getpos", 1, 1, f_popup_getpos},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200786 {"popup_hide", 1, 1, f_popup_hide},
Bram Moolenaara730e552019-06-16 19:05:31 +0200787 {"popup_menu", 2, 2, f_popup_menu},
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200788 {"popup_move", 2, 2, f_popup_move},
Bram Moolenaar68d48f42019-06-12 22:42:41 +0200789 {"popup_notification", 2, 2, f_popup_notification},
Bram Moolenaarae943152019-06-16 22:54:14 +0200790 {"popup_setoptions", 2, 2, f_popup_setoptions},
Bram Moolenaardc2ce582019-06-16 15:32:14 +0200791 {"popup_settext", 2, 2, f_popup_settext},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200792 {"popup_show", 1, 1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200793#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794#ifdef FEAT_FLOAT
795 {"pow", 2, 2, f_pow},
796#endif
797 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100798 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200799#ifdef FEAT_JOB_CHANNEL
800 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200801 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200802 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
803#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100804#ifdef FEAT_TEXT_PROP
805 {"prop_add", 3, 3, f_prop_add},
806 {"prop_clear", 1, 3, f_prop_clear},
807 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100808 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100809 {"prop_type_add", 2, 2, f_prop_type_add},
810 {"prop_type_change", 2, 2, f_prop_type_change},
811 {"prop_type_delete", 1, 2, f_prop_type_delete},
812 {"prop_type_get", 1, 2, f_prop_type_get},
813 {"prop_type_list", 0, 1, f_prop_type_list},
814#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815 {"pumvisible", 0, 0, f_pumvisible},
816#ifdef FEAT_PYTHON3
817 {"py3eval", 1, 1, f_py3eval},
818#endif
819#ifdef FEAT_PYTHON
820 {"pyeval", 1, 1, f_pyeval},
821#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100822#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
823 {"pyxeval", 1, 1, f_pyxeval},
824#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200826 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200828 {"reg_executing", 0, 0, f_reg_executing},
829 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830 {"reltime", 0, 2, f_reltime},
831#ifdef FEAT_FLOAT
832 {"reltimefloat", 1, 1, f_reltimefloat},
833#endif
834 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100835 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836 {"remote_foreground", 1, 1, f_remote_foreground},
837 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100838 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100840 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200841 {"remove", 2, 3, f_remove},
842 {"rename", 2, 2, f_rename},
843 {"repeat", 2, 2, f_repeat},
844 {"resolve", 1, 1, f_resolve},
845 {"reverse", 1, 1, f_reverse},
846#ifdef FEAT_FLOAT
847 {"round", 1, 1, f_round},
848#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100849#ifdef FEAT_RUBY
850 {"rubyeval", 1, 1, f_rubyeval},
851#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200852 {"screenattr", 2, 2, f_screenattr},
853 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100854 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200855 {"screencol", 0, 0, f_screencol},
856 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100857 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200858 {"search", 1, 4, f_search},
859 {"searchdecl", 1, 3, f_searchdecl},
860 {"searchpair", 3, 7, f_searchpair},
861 {"searchpairpos", 3, 7, f_searchpairpos},
862 {"searchpos", 1, 4, f_searchpos},
863 {"server2client", 2, 2, f_server2client},
864 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200865 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866 {"setbufvar", 3, 3, f_setbufvar},
867 {"setcharsearch", 1, 1, f_setcharsearch},
868 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200869 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870 {"setfperm", 2, 2, f_setfperm},
871 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200872 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100873 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200875 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876 {"setreg", 2, 3, f_setreg},
877 {"settabvar", 3, 3, f_settabvar},
878 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100879 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200880 {"setwinvar", 3, 3, f_setwinvar},
881#ifdef FEAT_CRYPT
882 {"sha256", 1, 1, f_sha256},
883#endif
884 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100885 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100886#ifdef FEAT_SIGNS
887 {"sign_define", 1, 2, f_sign_define},
888 {"sign_getdefined", 0, 1, f_sign_getdefined},
889 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100890 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100891 {"sign_place", 4, 5, f_sign_place},
892 {"sign_undefine", 0, 1, f_sign_undefine},
893 {"sign_unplace", 1, 2, f_sign_unplace},
894#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200895 {"simplify", 1, 1, f_simplify},
896#ifdef FEAT_FLOAT
897 {"sin", 1, 1, f_sin},
898 {"sinh", 1, 1, f_sinh},
899#endif
900 {"sort", 1, 3, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200901#ifdef FEAT_SOUND
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200902 {"sound_clear", 0, 0, f_sound_clear},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200903 {"sound_playevent", 1, 2, f_sound_playevent},
904 {"sound_playfile", 1, 2, f_sound_playfile},
905 {"sound_stop", 1, 1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200906#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200907 {"soundfold", 1, 1, f_soundfold},
908 {"spellbadword", 0, 1, f_spellbadword},
909 {"spellsuggest", 1, 3, f_spellsuggest},
910 {"split", 1, 3, f_split},
911#ifdef FEAT_FLOAT
912 {"sqrt", 1, 1, f_sqrt},
913 {"str2float", 1, 1, f_str2float},
914#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200915 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200916 {"str2nr", 1, 2, f_str2nr},
917 {"strcharpart", 2, 3, f_strcharpart},
918 {"strchars", 1, 2, f_strchars},
919 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
920#ifdef HAVE_STRFTIME
921 {"strftime", 1, 2, f_strftime},
922#endif
923 {"strgetchar", 2, 2, f_strgetchar},
924 {"stridx", 2, 3, f_stridx},
925 {"string", 1, 1, f_string},
926 {"strlen", 1, 1, f_strlen},
927 {"strpart", 2, 3, f_strpart},
928 {"strridx", 2, 3, f_strridx},
929 {"strtrans", 1, 1, f_strtrans},
930 {"strwidth", 1, 1, f_strwidth},
931 {"submatch", 1, 2, f_submatch},
932 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200933 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200934 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935 {"synID", 3, 3, f_synID},
936 {"synIDattr", 2, 3, f_synIDattr},
937 {"synIDtrans", 1, 1, f_synIDtrans},
938 {"synconcealed", 2, 2, f_synconcealed},
939 {"synstack", 2, 2, f_synstack},
940 {"system", 1, 2, f_system},
941 {"systemlist", 1, 2, f_systemlist},
942 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
943 {"tabpagenr", 0, 1, f_tabpagenr},
944 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
945 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100946 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200947#ifdef FEAT_FLOAT
948 {"tan", 1, 1, f_tan},
949 {"tanh", 1, 1, f_tanh},
950#endif
951 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200952#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100953 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
954 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100955 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200956 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200957# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
958 {"term_getansicolors", 1, 1, f_term_getansicolors},
959# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200960 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200961 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200962 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200963 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200964 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200965 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200966 {"term_getstatus", 1, 1, f_term_getstatus},
967 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200968 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200969 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200970 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200971 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200972# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
973 {"term_setansicolors", 2, 2, f_term_setansicolors},
974# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100975 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100976 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200977 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200978 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200979 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200980#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200981 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
982 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200983 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200984 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaaradc67142019-06-22 01:40:42 +0200985 {"test_garbagecollect_soon", 0, 0, f_test_garbagecollect_soon},
Bram Moolenaareda65222019-05-16 20:29:44 +0200986 {"test_getvalue", 1, 1, f_test_getvalue},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100987 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100988 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200989#ifdef FEAT_JOB_CHANNEL
990 {"test_null_channel", 0, 0, f_test_null_channel},
991#endif
992 {"test_null_dict", 0, 0, f_test_null_dict},
993#ifdef FEAT_JOB_CHANNEL
994 {"test_null_job", 0, 0, f_test_null_job},
995#endif
996 {"test_null_list", 0, 0, f_test_null_list},
997 {"test_null_partial", 0, 0, f_test_null_partial},
998 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200999 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +01001000 {"test_override", 2, 2, f_test_override},
1001 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +02001002#ifdef FEAT_GUI
1003 {"test_scrollbar", 3, 3, f_test_scrollbar},
1004#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +02001005#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +02001006 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +02001007#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001008 {"test_settime", 1, 1, f_test_settime},
1009#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001010 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001011 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012 {"timer_start", 2, 3, f_timer_start},
1013 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001014 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015#endif
1016 {"tolower", 1, 1, f_tolower},
1017 {"toupper", 1, 1, f_toupper},
1018 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01001019 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001020#ifdef FEAT_FLOAT
1021 {"trunc", 1, 1, f_trunc},
1022#endif
1023 {"type", 1, 1, f_type},
1024 {"undofile", 1, 1, f_undofile},
1025 {"undotree", 0, 0, f_undotree},
1026 {"uniq", 1, 3, f_uniq},
1027 {"values", 1, 1, f_values},
1028 {"virtcol", 1, 1, f_virtcol},
1029 {"visualmode", 0, 1, f_visualmode},
1030 {"wildmenumode", 0, 0, f_wildmenumode},
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001031 {"win_execute", 2, 3, f_win_execute},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001032 {"win_findbuf", 1, 1, f_win_findbuf},
1033 {"win_getid", 0, 2, f_win_getid},
1034 {"win_gotoid", 1, 1, f_win_gotoid},
1035 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1036 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001037 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001038 {"winbufnr", 1, 1, f_winbufnr},
1039 {"wincol", 0, 0, f_wincol},
1040 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001041 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001042 {"winline", 0, 0, f_winline},
1043 {"winnr", 0, 1, f_winnr},
1044 {"winrestcmd", 0, 0, f_winrestcmd},
1045 {"winrestview", 1, 1, f_winrestview},
1046 {"winsaveview", 0, 0, f_winsaveview},
1047 {"winwidth", 1, 1, f_winwidth},
1048 {"wordcount", 0, 0, f_wordcount},
1049 {"writefile", 2, 3, f_writefile},
1050 {"xor", 2, 2, f_xor},
1051};
1052
1053#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1054
1055/*
1056 * Function given to ExpandGeneric() to obtain the list of internal
1057 * or user defined function names.
1058 */
1059 char_u *
1060get_function_name(expand_T *xp, int idx)
1061{
1062 static int intidx = -1;
1063 char_u *name;
1064
1065 if (idx == 0)
1066 intidx = -1;
1067 if (intidx < 0)
1068 {
1069 name = get_user_func_name(xp, idx);
1070 if (name != NULL)
1071 return name;
1072 }
1073 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1074 {
1075 STRCPY(IObuff, functions[intidx].f_name);
1076 STRCAT(IObuff, "(");
1077 if (functions[intidx].f_max_argc == 0)
1078 STRCAT(IObuff, ")");
1079 return IObuff;
1080 }
1081
1082 return NULL;
1083}
1084
1085/*
1086 * Function given to ExpandGeneric() to obtain the list of internal or
1087 * user defined variable or function names.
1088 */
1089 char_u *
1090get_expr_name(expand_T *xp, int idx)
1091{
1092 static int intidx = -1;
1093 char_u *name;
1094
1095 if (idx == 0)
1096 intidx = -1;
1097 if (intidx < 0)
1098 {
1099 name = get_function_name(xp, idx);
1100 if (name != NULL)
1101 return name;
1102 }
1103 return get_user_var_name(xp, ++intidx);
1104}
1105
1106#endif /* FEAT_CMDL_COMPL */
1107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001108/*
1109 * Find internal function in table above.
1110 * Return index, or -1 if not found
1111 */
1112 int
1113find_internal_func(
1114 char_u *name) /* name of the function */
1115{
1116 int first = 0;
1117 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1118 int cmp;
1119 int x;
1120
1121 /*
1122 * Find the function name in the table. Binary search.
1123 */
1124 while (first <= last)
1125 {
1126 x = first + ((unsigned)(last - first) >> 1);
1127 cmp = STRCMP(name, functions[x].f_name);
1128 if (cmp < 0)
1129 last = x - 1;
1130 else if (cmp > 0)
1131 first = x + 1;
1132 else
1133 return x;
1134 }
1135 return -1;
1136}
1137
1138 int
1139call_internal_func(
1140 char_u *name,
1141 int argcount,
1142 typval_T *argvars,
1143 typval_T *rettv)
1144{
1145 int i;
1146
1147 i = find_internal_func(name);
1148 if (i < 0)
1149 return ERROR_UNKNOWN;
1150 if (argcount < functions[i].f_min_argc)
1151 return ERROR_TOOFEW;
1152 if (argcount > functions[i].f_max_argc)
1153 return ERROR_TOOMANY;
1154 argvars[argcount].v_type = VAR_UNKNOWN;
1155 functions[i].f_func(argvars, rettv);
1156 return ERROR_NONE;
1157}
1158
1159/*
1160 * Return TRUE for a non-zero Number and a non-empty String.
1161 */
1162 static int
1163non_zero_arg(typval_T *argvars)
1164{
1165 return ((argvars[0].v_type == VAR_NUMBER
1166 && argvars[0].vval.v_number != 0)
1167 || (argvars[0].v_type == VAR_SPECIAL
1168 && argvars[0].vval.v_number == VVAL_TRUE)
1169 || (argvars[0].v_type == VAR_STRING
1170 && argvars[0].vval.v_string != NULL
1171 && *argvars[0].vval.v_string != NUL));
1172}
1173
1174/*
1175 * Get the lnum from the first argument.
1176 * Also accepts ".", "$", etc., but that only works for the current buffer.
1177 * Returns -1 on error.
1178 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001179 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001180tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001181{
1182 typval_T rettv;
1183 linenr_T lnum;
1184
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001185 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001186 if (lnum == 0) /* no valid number, try using line() */
1187 {
1188 rettv.v_type = VAR_NUMBER;
1189 f_line(argvars, &rettv);
1190 lnum = (linenr_T)rettv.vval.v_number;
1191 clear_tv(&rettv);
1192 }
1193 return lnum;
1194}
1195
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001196/*
1197 * Get the lnum from the first argument.
1198 * Also accepts "$", then "buf" is used.
1199 * Returns 0 on error.
1200 */
1201 static linenr_T
1202tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1203{
1204 if (argvars[0].v_type == VAR_STRING
1205 && argvars[0].vval.v_string != NULL
1206 && argvars[0].vval.v_string[0] == '$'
1207 && buf != NULL)
1208 return buf->b_ml.ml_line_count;
1209 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1210}
1211
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001212#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001213/*
1214 * Get the float value of "argvars[0]" into "f".
1215 * Returns FAIL when the argument is not a Number or Float.
1216 */
1217 static int
1218get_float_arg(typval_T *argvars, float_T *f)
1219{
1220 if (argvars[0].v_type == VAR_FLOAT)
1221 {
1222 *f = argvars[0].vval.v_float;
1223 return OK;
1224 }
1225 if (argvars[0].v_type == VAR_NUMBER)
1226 {
1227 *f = (float_T)argvars[0].vval.v_number;
1228 return OK;
1229 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001230 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001231 return FAIL;
1232}
1233
1234/*
1235 * "abs(expr)" function
1236 */
1237 static void
1238f_abs(typval_T *argvars, typval_T *rettv)
1239{
1240 if (argvars[0].v_type == VAR_FLOAT)
1241 {
1242 rettv->v_type = VAR_FLOAT;
1243 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1244 }
1245 else
1246 {
1247 varnumber_T n;
1248 int error = FALSE;
1249
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001250 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001251 if (error)
1252 rettv->vval.v_number = -1;
1253 else if (n > 0)
1254 rettv->vval.v_number = n;
1255 else
1256 rettv->vval.v_number = -n;
1257 }
1258}
1259
1260/*
1261 * "acos()" function
1262 */
1263 static void
1264f_acos(typval_T *argvars, typval_T *rettv)
1265{
1266 float_T f = 0.0;
1267
1268 rettv->v_type = VAR_FLOAT;
1269 if (get_float_arg(argvars, &f) == OK)
1270 rettv->vval.v_float = acos(f);
1271 else
1272 rettv->vval.v_float = 0.0;
1273}
1274#endif
1275
1276/*
1277 * "add(list, item)" function
1278 */
1279 static void
1280f_add(typval_T *argvars, typval_T *rettv)
1281{
1282 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001283 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001284
1285 rettv->vval.v_number = 1; /* Default: Failed */
1286 if (argvars[0].v_type == VAR_LIST)
1287 {
1288 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001289 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001290 (char_u *)N_("add() argument"), TRUE)
1291 && list_append_tv(l, &argvars[1]) == OK)
1292 copy_tv(&argvars[0], rettv);
1293 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001294 else if (argvars[0].v_type == VAR_BLOB)
1295 {
1296 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001297 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001298 (char_u *)N_("add() argument"), TRUE))
1299 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001300 int error = FALSE;
1301 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1302
1303 if (!error)
1304 {
1305 ga_append(&b->bv_ga, (int)n);
1306 copy_tv(&argvars[0], rettv);
1307 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001308 }
1309 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001310 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001311 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001312}
1313
1314/*
1315 * "and(expr, expr)" function
1316 */
1317 static void
1318f_and(typval_T *argvars, typval_T *rettv)
1319{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001320 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1321 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001322}
1323
1324/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001325 * If there is a window for "curbuf", make it the current window.
1326 */
1327 static void
1328find_win_for_curbuf(void)
1329{
1330 wininfo_T *wip;
1331
1332 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1333 {
1334 if (wip->wi_win != NULL)
1335 {
1336 curwin = wip->wi_win;
1337 break;
1338 }
1339 }
1340}
1341
1342/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001343 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344 */
1345 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001346set_buffer_lines(
1347 buf_T *buf,
1348 linenr_T lnum_arg,
1349 int append,
1350 typval_T *lines,
1351 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352{
Bram Moolenaarca851592018-06-06 21:04:07 +02001353 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1354 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355 list_T *l = NULL;
1356 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001357 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001358 linenr_T append_lnum;
1359 buf_T *curbuf_save = NULL;
1360 win_T *curwin_save = NULL;
1361 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362
Bram Moolenaarca851592018-06-06 21:04:07 +02001363 /* When using the current buffer ml_mfp will be set if needed. Useful when
1364 * setline() is used on startup. For other buffers the buffer must be
1365 * loaded. */
1366 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001368 rettv->vval.v_number = 1; /* FAIL */
1369 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370 }
1371
Bram Moolenaarca851592018-06-06 21:04:07 +02001372 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001373 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001374 curbuf_save = curbuf;
1375 curwin_save = curwin;
1376 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001377 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001378 }
1379
1380 if (append)
1381 // appendbufline() uses the line number below which we insert
1382 append_lnum = lnum - 1;
1383 else
1384 // setbufline() uses the line number above which we insert, we only
1385 // append if it's below the last line
1386 append_lnum = curbuf->b_ml.ml_line_count;
1387
1388 if (lines->v_type == VAR_LIST)
1389 {
1390 l = lines->vval.v_list;
1391 li = l->lv_first;
1392 }
1393 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001394 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001395
1396 /* default result is zero == OK */
1397 for (;;)
1398 {
1399 if (l != NULL)
1400 {
1401 /* list argument, get next string */
1402 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001403 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001404 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001405 li = li->li_next;
1406 }
1407
Bram Moolenaarca851592018-06-06 21:04:07 +02001408 rettv->vval.v_number = 1; /* FAIL */
1409 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1410 break;
1411
1412 /* When coming here from Insert mode, sync undo, so that this can be
1413 * undone separately from what was previously inserted. */
1414 if (u_sync_once == 2)
1415 {
1416 u_sync_once = 1; /* notify that u_sync() was called */
1417 u_sync(TRUE);
1418 }
1419
1420 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1421 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001422 // Existing line, replace it.
1423 // Removes any existing text properties.
1424 if (u_savesub(lnum) == OK && ml_replace_len(
1425 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001426 {
1427 changed_bytes(lnum, 0);
1428 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1429 check_cursor_col();
1430 rettv->vval.v_number = 0; /* OK */
1431 }
1432 }
1433 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1434 {
1435 /* append the line */
1436 ++added;
1437 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1438 rettv->vval.v_number = 0; /* OK */
1439 }
1440
1441 if (l == NULL) /* only one string argument */
1442 break;
1443 ++lnum;
1444 }
1445
1446 if (added > 0)
1447 {
1448 win_T *wp;
1449 tabpage_T *tp;
1450
1451 appended_lines_mark(append_lnum, added);
1452 FOR_ALL_TAB_WINDOWS(tp, wp)
1453 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1454 wp->w_cursor.lnum += added;
1455 check_cursor_col();
1456
Bram Moolenaarf2732452018-06-03 14:47:35 +02001457#ifdef FEAT_JOB_CHANNEL
1458 if (bt_prompt(curbuf) && (State & INSERT))
1459 // show the line with the prompt
1460 update_topline();
1461#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001462 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001463
1464 if (!is_curbuf)
1465 {
1466 curbuf = curbuf_save;
1467 curwin = curwin_save;
1468 }
1469}
1470
1471/*
1472 * "append(lnum, string/list)" function
1473 */
1474 static void
1475f_append(typval_T *argvars, typval_T *rettv)
1476{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001477 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001478
1479 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1480}
1481
1482/*
1483 * "appendbufline(buf, lnum, string/list)" function
1484 */
1485 static void
1486f_appendbufline(typval_T *argvars, typval_T *rettv)
1487{
1488 linenr_T lnum;
1489 buf_T *buf;
1490
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001491 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001492 if (buf == NULL)
1493 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001494 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001495 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001496 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001497 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1498 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499}
1500
1501/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001502 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503 */
1504 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001505f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001507 win_T *wp;
1508
1509 if (argvars[0].v_type == VAR_UNKNOWN)
1510 // use the current window
1511 rettv->vval.v_number = ARGCOUNT;
1512 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001513 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001514 // use the global argument list
1515 rettv->vval.v_number = GARGCOUNT;
1516 else
1517 {
1518 // use the argument list of the specified window
1519 wp = find_win_by_nr_or_id(&argvars[0]);
1520 if (wp != NULL)
1521 rettv->vval.v_number = WARGCOUNT(wp);
1522 else
1523 rettv->vval.v_number = -1;
1524 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001525}
1526
1527/*
1528 * "argidx()" function
1529 */
1530 static void
1531f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1532{
1533 rettv->vval.v_number = curwin->w_arg_idx;
1534}
1535
1536/*
1537 * "arglistid()" function
1538 */
1539 static void
1540f_arglistid(typval_T *argvars, typval_T *rettv)
1541{
1542 win_T *wp;
1543
1544 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001545 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546 if (wp != NULL)
1547 rettv->vval.v_number = wp->w_alist->id;
1548}
1549
1550/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001551 * Get the argument list for a given window
1552 */
1553 static void
1554get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1555{
1556 int idx;
1557
1558 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1559 for (idx = 0; idx < argcount; ++idx)
1560 list_append_string(rettv->vval.v_list,
1561 alist_name(&arglist[idx]), -1);
1562}
1563
1564/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565 * "argv(nr)" function
1566 */
1567 static void
1568f_argv(typval_T *argvars, typval_T *rettv)
1569{
1570 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001571 aentry_T *arglist = NULL;
1572 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001573
1574 if (argvars[0].v_type != VAR_UNKNOWN)
1575 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001576 if (argvars[1].v_type == VAR_UNKNOWN)
1577 {
1578 arglist = ARGLIST;
1579 argcount = ARGCOUNT;
1580 }
1581 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001582 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001583 {
1584 arglist = GARGLIST;
1585 argcount = GARGCOUNT;
1586 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001587 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001588 {
1589 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1590
1591 if (wp != NULL)
1592 {
1593 /* Use the argument list of the specified window */
1594 arglist = WARGLIST(wp);
1595 argcount = WARGCOUNT(wp);
1596 }
1597 }
1598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001599 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001600 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001601 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001602 if (arglist != NULL && idx >= 0 && idx < argcount)
1603 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1604 else if (idx == -1)
1605 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001607 else
1608 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609}
1610
1611/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001612 * "assert_beeps(cmd [, error])" function
1613 */
1614 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001615f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001616{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001617 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001618}
1619
1620/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001621 * "assert_equal(expected, actual[, msg])" function
1622 */
1623 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001624f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001626 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627}
1628
1629/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001630 * "assert_equalfile(fname-one, fname-two)" function
1631 */
1632 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001633f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001634{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001635 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001636}
1637
1638/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001639 * "assert_notequal(expected, actual[, msg])" function
1640 */
1641 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001642f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001643{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001644 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001645}
1646
1647/*
1648 * "assert_exception(string[, msg])" function
1649 */
1650 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001651f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001653 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001654}
1655
1656/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001657 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001658 */
1659 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001660f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001662 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001663}
1664
1665/*
1666 * "assert_false(actual[, msg])" function
1667 */
1668 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001669f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001670{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001671 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001672}
1673
1674/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001675 * "assert_inrange(lower, upper[, msg])" function
1676 */
1677 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001678f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001679{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001680 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001681}
1682
1683/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684 * "assert_match(pattern, actual[, msg])" function
1685 */
1686 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001687f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001689 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001690}
1691
1692/*
1693 * "assert_notmatch(pattern, actual[, msg])" function
1694 */
1695 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001696f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001698 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001699}
1700
1701/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001702 * "assert_report(msg)" function
1703 */
1704 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001705f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001706{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001707 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001708}
1709
1710/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001711 * "assert_true(actual[, msg])" function
1712 */
1713 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001714f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001715{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001716 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001717}
1718
1719#ifdef FEAT_FLOAT
1720/*
1721 * "asin()" function
1722 */
1723 static void
1724f_asin(typval_T *argvars, typval_T *rettv)
1725{
1726 float_T f = 0.0;
1727
1728 rettv->v_type = VAR_FLOAT;
1729 if (get_float_arg(argvars, &f) == OK)
1730 rettv->vval.v_float = asin(f);
1731 else
1732 rettv->vval.v_float = 0.0;
1733}
1734
1735/*
1736 * "atan()" function
1737 */
1738 static void
1739f_atan(typval_T *argvars, typval_T *rettv)
1740{
1741 float_T f = 0.0;
1742
1743 rettv->v_type = VAR_FLOAT;
1744 if (get_float_arg(argvars, &f) == OK)
1745 rettv->vval.v_float = atan(f);
1746 else
1747 rettv->vval.v_float = 0.0;
1748}
1749
1750/*
1751 * "atan2()" function
1752 */
1753 static void
1754f_atan2(typval_T *argvars, typval_T *rettv)
1755{
1756 float_T fx = 0.0, fy = 0.0;
1757
1758 rettv->v_type = VAR_FLOAT;
1759 if (get_float_arg(argvars, &fx) == OK
1760 && get_float_arg(&argvars[1], &fy) == OK)
1761 rettv->vval.v_float = atan2(fx, fy);
1762 else
1763 rettv->vval.v_float = 0.0;
1764}
1765#endif
1766
1767/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001768 * "balloon_show()" function
1769 */
1770#ifdef FEAT_BEVAL
1771 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001772f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1773{
1774 rettv->v_type = VAR_STRING;
1775 if (balloonEval != NULL)
1776 {
1777 if (balloonEval->msg == NULL)
1778 rettv->vval.v_string = NULL;
1779 else
1780 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1781 }
1782}
1783
1784 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001785f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1786{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001787 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001788 {
1789 if (argvars[0].v_type == VAR_LIST
1790# ifdef FEAT_GUI
1791 && !gui.in_use
1792# endif
1793 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001794 {
1795 list_T *l = argvars[0].vval.v_list;
1796
1797 // empty list removes the balloon
1798 post_balloon(balloonEval, NULL,
1799 l == NULL || l->lv_len == 0 ? NULL : l);
1800 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001801 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001802 {
1803 char_u *mesg = tv_get_string_chk(&argvars[0]);
1804
1805 if (mesg != NULL)
1806 // empty string removes the balloon
1807 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1808 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001809 }
1810}
1811
Bram Moolenaar669a8282017-11-19 20:13:05 +01001812# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001813 static void
1814f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1815{
1816 if (rettv_list_alloc(rettv) == OK)
1817 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001818 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001819
1820 if (msg != NULL)
1821 {
1822 pumitem_T *array;
1823 int size = split_message(msg, &array);
1824 int i;
1825
1826 /* Skip the first and last item, they are always empty. */
1827 for (i = 1; i < size - 1; ++i)
1828 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001829 while (size > 0)
1830 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001831 vim_free(array);
1832 }
1833 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001834}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001835# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001836#endif
1837
1838/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 * "browse(save, title, initdir, default)" function
1840 */
1841 static void
1842f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1843{
1844#ifdef FEAT_BROWSE
1845 int save;
1846 char_u *title;
1847 char_u *initdir;
1848 char_u *defname;
1849 char_u buf[NUMBUFLEN];
1850 char_u buf2[NUMBUFLEN];
1851 int error = FALSE;
1852
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001853 save = (int)tv_get_number_chk(&argvars[0], &error);
1854 title = tv_get_string_chk(&argvars[1]);
1855 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1856 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001857
1858 if (error || title == NULL || initdir == NULL || defname == NULL)
1859 rettv->vval.v_string = NULL;
1860 else
1861 rettv->vval.v_string =
1862 do_browse(save ? BROWSE_SAVE : 0,
1863 title, defname, NULL, initdir, NULL, curbuf);
1864#else
1865 rettv->vval.v_string = NULL;
1866#endif
1867 rettv->v_type = VAR_STRING;
1868}
1869
1870/*
1871 * "browsedir(title, initdir)" function
1872 */
1873 static void
1874f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1875{
1876#ifdef FEAT_BROWSE
1877 char_u *title;
1878 char_u *initdir;
1879 char_u buf[NUMBUFLEN];
1880
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001881 title = tv_get_string_chk(&argvars[0]);
1882 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001883
1884 if (title == NULL || initdir == NULL)
1885 rettv->vval.v_string = NULL;
1886 else
1887 rettv->vval.v_string = do_browse(BROWSE_DIR,
1888 title, NULL, NULL, initdir, NULL, curbuf);
1889#else
1890 rettv->vval.v_string = NULL;
1891#endif
1892 rettv->v_type = VAR_STRING;
1893}
1894
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001895/*
1896 * Find a buffer by number or exact name.
1897 */
1898 static buf_T *
1899find_buffer(typval_T *avar)
1900{
1901 buf_T *buf = NULL;
1902
1903 if (avar->v_type == VAR_NUMBER)
1904 buf = buflist_findnr((int)avar->vval.v_number);
1905 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1906 {
1907 buf = buflist_findname_exp(avar->vval.v_string);
1908 if (buf == NULL)
1909 {
1910 /* No full path name match, try a match with a URL or a "nofile"
1911 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001912 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001913 if (buf->b_fname != NULL
1914 && (path_with_url(buf->b_fname)
1915#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001916 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001917#endif
1918 )
1919 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1920 break;
1921 }
1922 }
1923 return buf;
1924}
1925
1926/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001927 * "bufadd(expr)" function
1928 */
1929 static void
1930f_bufadd(typval_T *argvars, typval_T *rettv)
1931{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001932 char_u *name = tv_get_string(&argvars[0]);
1933
1934 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001935}
1936
1937/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001938 * "bufexists(expr)" function
1939 */
1940 static void
1941f_bufexists(typval_T *argvars, typval_T *rettv)
1942{
1943 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1944}
1945
1946/*
1947 * "buflisted(expr)" function
1948 */
1949 static void
1950f_buflisted(typval_T *argvars, typval_T *rettv)
1951{
1952 buf_T *buf;
1953
1954 buf = find_buffer(&argvars[0]);
1955 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1956}
1957
1958/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001959 * "bufload(expr)" function
1960 */
1961 static void
1962f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1963{
1964 buf_T *buf = get_buf_arg(&argvars[0]);
1965
1966 if (buf != NULL && buf->b_ml.ml_mfp == NULL)
1967 {
1968 aco_save_T aco;
1969
1970 aucmd_prepbuf(&aco, buf);
1971 swap_exists_action = SEA_NONE;
1972 open_buffer(FALSE, NULL, 0);
1973 aucmd_restbuf(&aco);
1974 }
1975}
1976
1977/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 * "bufloaded(expr)" function
1979 */
1980 static void
1981f_bufloaded(typval_T *argvars, typval_T *rettv)
1982{
1983 buf_T *buf;
1984
1985 buf = find_buffer(&argvars[0]);
1986 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1987}
1988
1989 buf_T *
1990buflist_find_by_name(char_u *name, int curtab_only)
1991{
1992 int save_magic;
1993 char_u *save_cpo;
1994 buf_T *buf;
1995
1996 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1997 save_magic = p_magic;
1998 p_magic = TRUE;
1999 save_cpo = p_cpo;
2000 p_cpo = (char_u *)"";
2001
2002 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
2003 TRUE, FALSE, curtab_only));
2004
2005 p_magic = save_magic;
2006 p_cpo = save_cpo;
2007 return buf;
2008}
2009
2010/*
2011 * Get buffer by number or pattern.
2012 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02002013 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002014tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002015{
2016 char_u *name = tv->vval.v_string;
2017 buf_T *buf;
2018
2019 if (tv->v_type == VAR_NUMBER)
2020 return buflist_findnr((int)tv->vval.v_number);
2021 if (tv->v_type != VAR_STRING)
2022 return NULL;
2023 if (name == NULL || *name == NUL)
2024 return curbuf;
2025 if (name[0] == '$' && name[1] == NUL)
2026 return lastbuf;
2027
2028 buf = buflist_find_by_name(name, curtab_only);
2029
2030 /* If not found, try expanding the name, like done for bufexists(). */
2031 if (buf == NULL)
2032 buf = find_buffer(tv);
2033
2034 return buf;
2035}
2036
2037/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002038 * Get the buffer from "arg" and give an error and return NULL if it is not
2039 * valid.
2040 */
Bram Moolenaara3347722019-05-11 21:14:24 +02002041 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002042get_buf_arg(typval_T *arg)
2043{
2044 buf_T *buf;
2045
2046 ++emsg_off;
2047 buf = tv_get_buf(arg, FALSE);
2048 --emsg_off;
2049 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002050 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002051 return buf;
2052}
2053
2054/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002055 * "bufname(expr)" function
2056 */
2057 static void
2058f_bufname(typval_T *argvars, typval_T *rettv)
2059{
2060 buf_T *buf;
2061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002062 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002064 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002065 rettv->v_type = VAR_STRING;
2066 if (buf != NULL && buf->b_fname != NULL)
2067 rettv->vval.v_string = vim_strsave(buf->b_fname);
2068 else
2069 rettv->vval.v_string = NULL;
2070 --emsg_off;
2071}
2072
2073/*
2074 * "bufnr(expr)" function
2075 */
2076 static void
2077f_bufnr(typval_T *argvars, typval_T *rettv)
2078{
2079 buf_T *buf;
2080 int error = FALSE;
2081 char_u *name;
2082
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002083 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002084 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002085 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086 --emsg_off;
2087
2088 /* If the buffer isn't found and the second argument is not zero create a
2089 * new buffer. */
2090 if (buf == NULL
2091 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002092 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002094 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 && !error)
2096 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2097
2098 if (buf != NULL)
2099 rettv->vval.v_number = buf->b_fnum;
2100 else
2101 rettv->vval.v_number = -1;
2102}
2103
2104 static void
2105buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2106{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002107 win_T *wp;
2108 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002109 buf_T *buf;
2110
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002111 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002112 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002113 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002114 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002115 {
2116 ++winnr;
2117 if (wp->w_buffer == buf)
2118 break;
2119 }
2120 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002121 --emsg_off;
2122}
2123
2124/*
2125 * "bufwinid(nr)" function
2126 */
2127 static void
2128f_bufwinid(typval_T *argvars, typval_T *rettv)
2129{
2130 buf_win_common(argvars, rettv, FALSE);
2131}
2132
2133/*
2134 * "bufwinnr(nr)" function
2135 */
2136 static void
2137f_bufwinnr(typval_T *argvars, typval_T *rettv)
2138{
2139 buf_win_common(argvars, rettv, TRUE);
2140}
2141
2142/*
2143 * "byte2line(byte)" function
2144 */
2145 static void
2146f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2147{
2148#ifndef FEAT_BYTEOFF
2149 rettv->vval.v_number = -1;
2150#else
2151 long boff = 0;
2152
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002153 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 if (boff < 0)
2155 rettv->vval.v_number = -1;
2156 else
2157 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2158 (linenr_T)0, &boff);
2159#endif
2160}
2161
2162 static void
2163byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2164{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002165 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 char_u *str;
2167 varnumber_T idx;
2168
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002169 str = tv_get_string_chk(&argvars[0]);
2170 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 rettv->vval.v_number = -1;
2172 if (str == NULL || idx < 0)
2173 return;
2174
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 t = str;
2176 for ( ; idx > 0; idx--)
2177 {
2178 if (*t == NUL) /* EOL reached */
2179 return;
2180 if (enc_utf8 && comp)
2181 t += utf_ptr2len(t);
2182 else
2183 t += (*mb_ptr2len)(t);
2184 }
2185 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002186}
2187
2188/*
2189 * "byteidx()" function
2190 */
2191 static void
2192f_byteidx(typval_T *argvars, typval_T *rettv)
2193{
2194 byteidx(argvars, rettv, FALSE);
2195}
2196
2197/*
2198 * "byteidxcomp()" function
2199 */
2200 static void
2201f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2202{
2203 byteidx(argvars, rettv, TRUE);
2204}
2205
2206/*
2207 * "call(func, arglist [, dict])" function
2208 */
2209 static void
2210f_call(typval_T *argvars, typval_T *rettv)
2211{
2212 char_u *func;
2213 partial_T *partial = NULL;
2214 dict_T *selfdict = NULL;
2215
2216 if (argvars[1].v_type != VAR_LIST)
2217 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002218 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002219 return;
2220 }
2221 if (argvars[1].vval.v_list == NULL)
2222 return;
2223
2224 if (argvars[0].v_type == VAR_FUNC)
2225 func = argvars[0].vval.v_string;
2226 else if (argvars[0].v_type == VAR_PARTIAL)
2227 {
2228 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002229 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002230 }
2231 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002232 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002233 if (*func == NUL)
2234 return; /* type error or empty name */
2235
2236 if (argvars[2].v_type != VAR_UNKNOWN)
2237 {
2238 if (argvars[2].v_type != VAR_DICT)
2239 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002240 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002241 return;
2242 }
2243 selfdict = argvars[2].vval.v_dict;
2244 }
2245
2246 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2247}
2248
2249#ifdef FEAT_FLOAT
2250/*
2251 * "ceil({float})" function
2252 */
2253 static void
2254f_ceil(typval_T *argvars, typval_T *rettv)
2255{
2256 float_T f = 0.0;
2257
2258 rettv->v_type = VAR_FLOAT;
2259 if (get_float_arg(argvars, &f) == OK)
2260 rettv->vval.v_float = ceil(f);
2261 else
2262 rettv->vval.v_float = 0.0;
2263}
2264#endif
2265
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266/*
2267 * "changenr()" function
2268 */
2269 static void
2270f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2271{
2272 rettv->vval.v_number = curbuf->b_u_seq_cur;
2273}
2274
2275/*
2276 * "char2nr(string)" function
2277 */
2278 static void
2279f_char2nr(typval_T *argvars, typval_T *rettv)
2280{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 if (has_mbyte)
2282 {
2283 int utf8 = 0;
2284
2285 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002286 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287
2288 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002289 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002291 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 }
2293 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002294 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295}
2296
2297/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002298 * "chdir(dir)" function
2299 */
2300 static void
2301f_chdir(typval_T *argvars, typval_T *rettv)
2302{
2303 char_u *cwd;
2304 cdscope_T scope = CDSCOPE_GLOBAL;
2305
2306 rettv->v_type = VAR_STRING;
2307 rettv->vval.v_string = NULL;
2308
2309 if (argvars[0].v_type != VAR_STRING)
2310 return;
2311
2312 // Return the current directory
2313 cwd = alloc(MAXPATHL);
2314 if (cwd != NULL)
2315 {
2316 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2317 {
2318#ifdef BACKSLASH_IN_FILENAME
2319 slash_adjust(cwd);
2320#endif
2321 rettv->vval.v_string = vim_strsave(cwd);
2322 }
2323 vim_free(cwd);
2324 }
2325
2326 if (curwin->w_localdir != NULL)
2327 scope = CDSCOPE_WINDOW;
2328 else if (curtab->tp_localdir != NULL)
2329 scope = CDSCOPE_TABPAGE;
2330
2331 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2332 // Directory change failed
2333 VIM_CLEAR(rettv->vval.v_string);
2334}
2335
2336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002337 * "cindent(lnum)" function
2338 */
2339 static void
2340f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2341{
2342#ifdef FEAT_CINDENT
2343 pos_T pos;
2344 linenr_T lnum;
2345
2346 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002347 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002348 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2349 {
2350 curwin->w_cursor.lnum = lnum;
2351 rettv->vval.v_number = get_c_indent();
2352 curwin->w_cursor = pos;
2353 }
2354 else
2355#endif
2356 rettv->vval.v_number = -1;
2357}
2358
Bram Moolenaaraff74912019-03-30 18:11:49 +01002359 static win_T *
2360get_optional_window(typval_T *argvars, int idx)
2361{
2362 win_T *win = curwin;
2363
2364 if (argvars[idx].v_type != VAR_UNKNOWN)
2365 {
2366 win = find_win_by_nr_or_id(&argvars[idx]);
2367 if (win == NULL)
2368 {
2369 emsg(_(e_invalwindow));
2370 return NULL;
2371 }
2372 }
2373 return win;
2374}
2375
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002376/*
2377 * "clearmatches()" function
2378 */
2379 static void
2380f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2381{
2382#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002383 win_T *win = get_optional_window(argvars, 0);
2384
2385 if (win != NULL)
2386 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002387#endif
2388}
2389
2390/*
2391 * "col(string)" function
2392 */
2393 static void
2394f_col(typval_T *argvars, typval_T *rettv)
2395{
2396 colnr_T col = 0;
2397 pos_T *fp;
2398 int fnum = curbuf->b_fnum;
2399
2400 fp = var2fpos(&argvars[0], FALSE, &fnum);
2401 if (fp != NULL && fnum == curbuf->b_fnum)
2402 {
2403 if (fp->col == MAXCOL)
2404 {
2405 /* '> can be MAXCOL, get the length of the line then */
2406 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2407 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2408 else
2409 col = MAXCOL;
2410 }
2411 else
2412 {
2413 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 /* col(".") when the cursor is on the NUL at the end of the line
2415 * because of "coladd" can be seen as an extra column. */
2416 if (virtual_active() && fp == &curwin->w_cursor)
2417 {
2418 char_u *p = ml_get_cursor();
2419
2420 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2421 curwin->w_virtcol - curwin->w_cursor.coladd))
2422 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423 int l;
2424
2425 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2426 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002427 }
2428 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002429 }
2430 }
2431 rettv->vval.v_number = col;
2432}
2433
2434#if defined(FEAT_INS_EXPAND)
2435/*
2436 * "complete()" function
2437 */
2438 static void
2439f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2440{
2441 int startcol;
2442
2443 if ((State & INSERT) == 0)
2444 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002445 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446 return;
2447 }
2448
2449 /* Check for undo allowed here, because if something was already inserted
2450 * the line was already saved for undo and this check isn't done. */
2451 if (!undo_allowed())
2452 return;
2453
2454 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2455 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002456 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 return;
2458 }
2459
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002460 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 if (startcol <= 0)
2462 return;
2463
2464 set_completion(startcol - 1, argvars[1].vval.v_list);
2465}
2466
2467/*
2468 * "complete_add()" function
2469 */
2470 static void
2471f_complete_add(typval_T *argvars, typval_T *rettv)
2472{
2473 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2474}
2475
2476/*
2477 * "complete_check()" function
2478 */
2479 static void
2480f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2481{
2482 int saved = RedrawingDisabled;
2483
2484 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002485 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002486 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002487 RedrawingDisabled = saved;
2488}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002489
2490/*
2491 * "complete_info()" function
2492 */
2493 static void
2494f_complete_info(typval_T *argvars, typval_T *rettv)
2495{
2496 list_T *what_list = NULL;
2497
2498 if (rettv_dict_alloc(rettv) != OK)
2499 return;
2500
2501 if (argvars[0].v_type != VAR_UNKNOWN)
2502 {
2503 if (argvars[0].v_type != VAR_LIST)
2504 {
2505 emsg(_(e_listreq));
2506 return;
2507 }
2508 what_list = argvars[0].vval.v_list;
2509 }
2510 get_complete_info(what_list, rettv->vval.v_dict);
2511}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512#endif
2513
2514/*
2515 * "confirm(message, buttons[, default [, type]])" function
2516 */
2517 static void
2518f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2519{
2520#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2521 char_u *message;
2522 char_u *buttons = NULL;
2523 char_u buf[NUMBUFLEN];
2524 char_u buf2[NUMBUFLEN];
2525 int def = 1;
2526 int type = VIM_GENERIC;
2527 char_u *typestr;
2528 int error = FALSE;
2529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002530 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002531 if (message == NULL)
2532 error = TRUE;
2533 if (argvars[1].v_type != VAR_UNKNOWN)
2534 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002535 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536 if (buttons == NULL)
2537 error = TRUE;
2538 if (argvars[2].v_type != VAR_UNKNOWN)
2539 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002540 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 if (argvars[3].v_type != VAR_UNKNOWN)
2542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002543 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002544 if (typestr == NULL)
2545 error = TRUE;
2546 else
2547 {
2548 switch (TOUPPER_ASC(*typestr))
2549 {
2550 case 'E': type = VIM_ERROR; break;
2551 case 'Q': type = VIM_QUESTION; break;
2552 case 'I': type = VIM_INFO; break;
2553 case 'W': type = VIM_WARNING; break;
2554 case 'G': type = VIM_GENERIC; break;
2555 }
2556 }
2557 }
2558 }
2559 }
2560
2561 if (buttons == NULL || *buttons == NUL)
2562 buttons = (char_u *)_("&Ok");
2563
2564 if (!error)
2565 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2566 def, NULL, FALSE);
2567#endif
2568}
2569
2570/*
2571 * "copy()" function
2572 */
2573 static void
2574f_copy(typval_T *argvars, typval_T *rettv)
2575{
2576 item_copy(&argvars[0], rettv, FALSE, 0);
2577}
2578
2579#ifdef FEAT_FLOAT
2580/*
2581 * "cos()" function
2582 */
2583 static void
2584f_cos(typval_T *argvars, typval_T *rettv)
2585{
2586 float_T f = 0.0;
2587
2588 rettv->v_type = VAR_FLOAT;
2589 if (get_float_arg(argvars, &f) == OK)
2590 rettv->vval.v_float = cos(f);
2591 else
2592 rettv->vval.v_float = 0.0;
2593}
2594
2595/*
2596 * "cosh()" function
2597 */
2598 static void
2599f_cosh(typval_T *argvars, typval_T *rettv)
2600{
2601 float_T f = 0.0;
2602
2603 rettv->v_type = VAR_FLOAT;
2604 if (get_float_arg(argvars, &f) == OK)
2605 rettv->vval.v_float = cosh(f);
2606 else
2607 rettv->vval.v_float = 0.0;
2608}
2609#endif
2610
2611/*
2612 * "count()" function
2613 */
2614 static void
2615f_count(typval_T *argvars, typval_T *rettv)
2616{
2617 long n = 0;
2618 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002619 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620
Bram Moolenaar9966b212017-07-28 16:46:57 +02002621 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002622 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002623
2624 if (argvars[0].v_type == VAR_STRING)
2625 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002626 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002627 char_u *p = argvars[0].vval.v_string;
2628 char_u *next;
2629
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002630 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002631 {
2632 if (ic)
2633 {
2634 size_t len = STRLEN(expr);
2635
2636 while (*p != NUL)
2637 {
2638 if (MB_STRNICMP(p, expr, len) == 0)
2639 {
2640 ++n;
2641 p += len;
2642 }
2643 else
2644 MB_PTR_ADV(p);
2645 }
2646 }
2647 else
2648 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2649 != NULL)
2650 {
2651 ++n;
2652 p = next + STRLEN(expr);
2653 }
2654 }
2655
2656 }
2657 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658 {
2659 listitem_T *li;
2660 list_T *l;
2661 long idx;
2662
2663 if ((l = argvars[0].vval.v_list) != NULL)
2664 {
2665 li = l->lv_first;
2666 if (argvars[2].v_type != VAR_UNKNOWN)
2667 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002668 if (argvars[3].v_type != VAR_UNKNOWN)
2669 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002670 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671 if (!error)
2672 {
2673 li = list_find(l, idx);
2674 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002675 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002676 }
2677 }
2678 if (error)
2679 li = NULL;
2680 }
2681
2682 for ( ; li != NULL; li = li->li_next)
2683 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2684 ++n;
2685 }
2686 }
2687 else if (argvars[0].v_type == VAR_DICT)
2688 {
2689 int todo;
2690 dict_T *d;
2691 hashitem_T *hi;
2692
2693 if ((d = argvars[0].vval.v_dict) != NULL)
2694 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002695 if (argvars[2].v_type != VAR_UNKNOWN)
2696 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002697 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002698 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699 }
2700
2701 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2702 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2703 {
2704 if (!HASHITEM_EMPTY(hi))
2705 {
2706 --todo;
2707 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2708 ++n;
2709 }
2710 }
2711 }
2712 }
2713 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002714 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002715 rettv->vval.v_number = n;
2716}
2717
2718/*
2719 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2720 *
2721 * Checks the existence of a cscope connection.
2722 */
2723 static void
2724f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2725{
2726#ifdef FEAT_CSCOPE
2727 int num = 0;
2728 char_u *dbpath = NULL;
2729 char_u *prepend = NULL;
2730 char_u buf[NUMBUFLEN];
2731
2732 if (argvars[0].v_type != VAR_UNKNOWN
2733 && argvars[1].v_type != VAR_UNKNOWN)
2734 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002735 num = (int)tv_get_number(&argvars[0]);
2736 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002737 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002738 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002739 }
2740
2741 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2742#endif
2743}
2744
2745/*
2746 * "cursor(lnum, col)" function, or
2747 * "cursor(list)"
2748 *
2749 * Moves the cursor to the specified line and column.
2750 * Returns 0 when the position could be set, -1 otherwise.
2751 */
2752 static void
2753f_cursor(typval_T *argvars, typval_T *rettv)
2754{
2755 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002757 int set_curswant = TRUE;
2758
2759 rettv->vval.v_number = -1;
2760 if (argvars[1].v_type == VAR_UNKNOWN)
2761 {
2762 pos_T pos;
2763 colnr_T curswant = -1;
2764
2765 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2766 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002767 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 return;
2769 }
2770 line = pos.lnum;
2771 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002772 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 if (curswant >= 0)
2774 {
2775 curwin->w_curswant = curswant - 1;
2776 set_curswant = FALSE;
2777 }
2778 }
2779 else
2780 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002781 line = tv_get_lnum(argvars);
2782 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002784 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002785 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002786 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 return; /* type error; errmsg already given */
2788 if (line > 0)
2789 curwin->w_cursor.lnum = line;
2790 if (col > 0)
2791 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002793
2794 /* Make sure the cursor is in a valid position. */
2795 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002796 /* Correct cursor for multi-byte character. */
2797 if (has_mbyte)
2798 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799
2800 curwin->w_set_curswant = set_curswant;
2801 rettv->vval.v_number = 0;
2802}
2803
Bram Moolenaar4f974752019-02-17 17:44:42 +01002804#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002805/*
2806 * "debugbreak()" function
2807 */
2808 static void
2809f_debugbreak(typval_T *argvars, typval_T *rettv)
2810{
2811 int pid;
2812
2813 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002814 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002815 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002816 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002817 else
2818 {
2819 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2820
2821 if (hProcess != NULL)
2822 {
2823 DebugBreakProcess(hProcess);
2824 CloseHandle(hProcess);
2825 rettv->vval.v_number = OK;
2826 }
2827 }
2828}
2829#endif
2830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831/*
2832 * "deepcopy()" function
2833 */
2834 static void
2835f_deepcopy(typval_T *argvars, typval_T *rettv)
2836{
2837 int noref = 0;
2838 int copyID;
2839
2840 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002841 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002842 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002843 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002844 else
2845 {
2846 copyID = get_copyID();
2847 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2848 }
2849}
2850
2851/*
2852 * "delete()" function
2853 */
2854 static void
2855f_delete(typval_T *argvars, typval_T *rettv)
2856{
2857 char_u nbuf[NUMBUFLEN];
2858 char_u *name;
2859 char_u *flags;
2860
2861 rettv->vval.v_number = -1;
2862 if (check_restricted() || check_secure())
2863 return;
2864
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002865 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002866 if (name == NULL || *name == NUL)
2867 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002868 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869 return;
2870 }
2871
2872 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002873 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002874 else
2875 flags = (char_u *)"";
2876
2877 if (*flags == NUL)
2878 /* delete a file */
2879 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2880 else if (STRCMP(flags, "d") == 0)
2881 /* delete an empty directory */
2882 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2883 else if (STRCMP(flags, "rf") == 0)
2884 /* delete a directory recursively */
2885 rettv->vval.v_number = delete_recursive(name);
2886 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002887 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002888}
2889
2890/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002891 * "deletebufline()" function
2892 */
2893 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002894f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002895{
2896 buf_T *buf;
2897 linenr_T first, last;
2898 linenr_T lnum;
2899 long count;
2900 int is_curbuf;
2901 buf_T *curbuf_save = NULL;
2902 win_T *curwin_save = NULL;
2903 tabpage_T *tp;
2904 win_T *wp;
2905
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002906 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002907 if (buf == NULL)
2908 {
2909 rettv->vval.v_number = 1; /* FAIL */
2910 return;
2911 }
2912 is_curbuf = buf == curbuf;
2913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002914 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002915 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002916 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002917 else
2918 last = first;
2919
2920 if (buf->b_ml.ml_mfp == NULL || first < 1
2921 || first > buf->b_ml.ml_line_count || last < first)
2922 {
2923 rettv->vval.v_number = 1; /* FAIL */
2924 return;
2925 }
2926
2927 if (!is_curbuf)
2928 {
2929 curbuf_save = curbuf;
2930 curwin_save = curwin;
2931 curbuf = buf;
2932 find_win_for_curbuf();
2933 }
2934 if (last > curbuf->b_ml.ml_line_count)
2935 last = curbuf->b_ml.ml_line_count;
2936 count = last - first + 1;
2937
2938 // When coming here from Insert mode, sync undo, so that this can be
2939 // undone separately from what was previously inserted.
2940 if (u_sync_once == 2)
2941 {
2942 u_sync_once = 1; // notify that u_sync() was called
2943 u_sync(TRUE);
2944 }
2945
2946 if (u_save(first - 1, last + 1) == FAIL)
2947 {
2948 rettv->vval.v_number = 1; /* FAIL */
2949 return;
2950 }
2951
2952 for (lnum = first; lnum <= last; ++lnum)
2953 ml_delete(first, TRUE);
2954
2955 FOR_ALL_TAB_WINDOWS(tp, wp)
2956 if (wp->w_buffer == buf)
2957 {
2958 if (wp->w_cursor.lnum > last)
2959 wp->w_cursor.lnum -= count;
2960 else if (wp->w_cursor.lnum> first)
2961 wp->w_cursor.lnum = first;
2962 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2963 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2964 }
2965 check_cursor_col();
2966 deleted_lines_mark(first, count);
2967
2968 if (!is_curbuf)
2969 {
2970 curbuf = curbuf_save;
2971 curwin = curwin_save;
2972 }
2973}
2974
2975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976 * "did_filetype()" function
2977 */
2978 static void
2979f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2980{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002982}
2983
2984/*
2985 * "diff_filler()" function
2986 */
2987 static void
2988f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2989{
2990#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002991 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002992#endif
2993}
2994
2995/*
2996 * "diff_hlID()" function
2997 */
2998 static void
2999f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3000{
3001#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003002 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003003 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003004 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003005 static int fnum = 0;
3006 static int change_start = 0;
3007 static int change_end = 0;
3008 static hlf_T hlID = (hlf_T)0;
3009 int filler_lines;
3010 int col;
3011
3012 if (lnum < 0) /* ignore type error in {lnum} arg */
3013 lnum = 0;
3014 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003015 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016 || fnum != curbuf->b_fnum)
3017 {
3018 /* New line, buffer, change: need to get the values. */
3019 filler_lines = diff_check(curwin, lnum);
3020 if (filler_lines < 0)
3021 {
3022 if (filler_lines == -1)
3023 {
3024 change_start = MAXCOL;
3025 change_end = -1;
3026 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3027 hlID = HLF_ADD; /* added line */
3028 else
3029 hlID = HLF_CHD; /* changed line */
3030 }
3031 else
3032 hlID = HLF_ADD; /* added line */
3033 }
3034 else
3035 hlID = (hlf_T)0;
3036 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003037 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 fnum = curbuf->b_fnum;
3039 }
3040
3041 if (hlID == HLF_CHD || hlID == HLF_TXD)
3042 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003043 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003044 if (col >= change_start && col <= change_end)
3045 hlID = HLF_TXD; /* changed text */
3046 else
3047 hlID = HLF_CHD; /* changed line */
3048 }
3049 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3050#endif
3051}
3052
3053/*
3054 * "empty({expr})" function
3055 */
3056 static void
3057f_empty(typval_T *argvars, typval_T *rettv)
3058{
3059 int n = FALSE;
3060
3061 switch (argvars[0].v_type)
3062 {
3063 case VAR_STRING:
3064 case VAR_FUNC:
3065 n = argvars[0].vval.v_string == NULL
3066 || *argvars[0].vval.v_string == NUL;
3067 break;
3068 case VAR_PARTIAL:
3069 n = FALSE;
3070 break;
3071 case VAR_NUMBER:
3072 n = argvars[0].vval.v_number == 0;
3073 break;
3074 case VAR_FLOAT:
3075#ifdef FEAT_FLOAT
3076 n = argvars[0].vval.v_float == 0.0;
3077 break;
3078#endif
3079 case VAR_LIST:
3080 n = argvars[0].vval.v_list == NULL
3081 || argvars[0].vval.v_list->lv_first == NULL;
3082 break;
3083 case VAR_DICT:
3084 n = argvars[0].vval.v_dict == NULL
3085 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3086 break;
3087 case VAR_SPECIAL:
3088 n = argvars[0].vval.v_number != VVAL_TRUE;
3089 break;
3090
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003091 case VAR_BLOB:
3092 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003093 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3094 break;
3095
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 case VAR_JOB:
3097#ifdef FEAT_JOB_CHANNEL
3098 n = argvars[0].vval.v_job == NULL
3099 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3100 break;
3101#endif
3102 case VAR_CHANNEL:
3103#ifdef FEAT_JOB_CHANNEL
3104 n = argvars[0].vval.v_channel == NULL
3105 || !channel_is_open(argvars[0].vval.v_channel);
3106 break;
3107#endif
3108 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003109 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003110 n = TRUE;
3111 break;
3112 }
3113
3114 rettv->vval.v_number = n;
3115}
3116
3117/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003118 * "environ()" function
3119 */
3120 static void
3121f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3122{
3123#if !defined(AMIGA)
3124 int i = 0;
3125 char_u *entry, *value;
3126# ifdef MSWIN
3127 extern wchar_t **_wenviron;
3128# else
3129 extern char **environ;
3130# endif
3131
3132 if (rettv_dict_alloc(rettv) != OK)
3133 return;
3134
3135# ifdef MSWIN
3136 if (*_wenviron == NULL)
3137 return;
3138# else
3139 if (*environ == NULL)
3140 return;
3141# endif
3142
3143 for (i = 0; ; ++i)
3144 {
3145# ifdef MSWIN
3146 short_u *p;
3147
3148 if ((p = (short_u *)_wenviron[i]) == NULL)
3149 return;
3150 entry = utf16_to_enc(p, NULL);
3151# else
3152 if ((entry = (char_u *)environ[i]) == NULL)
3153 return;
3154 entry = vim_strsave(entry);
3155# endif
3156 if (entry == NULL) // out of memory
3157 return;
3158 if ((value = vim_strchr(entry, '=')) == NULL)
3159 {
3160 vim_free(entry);
3161 continue;
3162 }
3163 *value++ = NUL;
3164 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3165 vim_free(entry);
3166 }
3167#endif
3168}
3169
3170/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003171 * "escape({string}, {chars})" function
3172 */
3173 static void
3174f_escape(typval_T *argvars, typval_T *rettv)
3175{
3176 char_u buf[NUMBUFLEN];
3177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003178 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3179 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003180 rettv->v_type = VAR_STRING;
3181}
3182
3183/*
3184 * "eval()" function
3185 */
3186 static void
3187f_eval(typval_T *argvars, typval_T *rettv)
3188{
3189 char_u *s, *p;
3190
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003191 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003192 if (s != NULL)
3193 s = skipwhite(s);
3194
3195 p = s;
3196 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3197 {
3198 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003199 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003200 need_clr_eos = FALSE;
3201 rettv->v_type = VAR_NUMBER;
3202 rettv->vval.v_number = 0;
3203 }
3204 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003205 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003206}
3207
3208/*
3209 * "eventhandler()" function
3210 */
3211 static void
3212f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3213{
3214 rettv->vval.v_number = vgetc_busy;
3215}
3216
3217/*
3218 * "executable()" function
3219 */
3220 static void
3221f_executable(typval_T *argvars, typval_T *rettv)
3222{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003223 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003224
3225 /* Check in $PATH and also check directly if there is a directory name. */
3226 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3227 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3228}
3229
3230static garray_T redir_execute_ga;
3231
3232/*
3233 * Append "value[value_len]" to the execute() output.
3234 */
3235 void
3236execute_redir_str(char_u *value, int value_len)
3237{
3238 int len;
3239
3240 if (value_len == -1)
3241 len = (int)STRLEN(value); /* Append the entire string */
3242 else
3243 len = value_len; /* Append only "value_len" characters */
3244 if (ga_grow(&redir_execute_ga, len) == OK)
3245 {
3246 mch_memmove((char *)redir_execute_ga.ga_data
3247 + redir_execute_ga.ga_len, value, len);
3248 redir_execute_ga.ga_len += len;
3249 }
3250}
3251
3252/*
3253 * Get next line from a list.
3254 * Called by do_cmdline() to get the next line.
3255 * Returns allocated string, or NULL for end of function.
3256 */
3257
3258 static char_u *
3259get_list_line(
3260 int c UNUSED,
3261 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003262 int indent UNUSED,
3263 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003264{
3265 listitem_T **p = (listitem_T **)cookie;
3266 listitem_T *item = *p;
3267 char_u buf[NUMBUFLEN];
3268 char_u *s;
3269
3270 if (item == NULL)
3271 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003272 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273 *p = item->li_next;
3274 return s == NULL ? NULL : vim_strsave(s);
3275}
3276
3277/*
3278 * "execute()" function
3279 */
3280 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003281execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003282{
3283 char_u *cmd = NULL;
3284 list_T *list = NULL;
3285 int save_msg_silent = msg_silent;
3286 int save_emsg_silent = emsg_silent;
3287 int save_emsg_noredir = emsg_noredir;
3288 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003289 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003290 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003291 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003292 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293
3294 rettv->vval.v_string = NULL;
3295 rettv->v_type = VAR_STRING;
3296
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003297 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003298 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003299 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003300 if (list == NULL || list->lv_first == NULL)
3301 /* empty list, no commands, empty output */
3302 return;
3303 ++list->lv_refcount;
3304 }
3305 else
3306 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003307 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 if (cmd == NULL)
3309 return;
3310 }
3311
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003312 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003313 {
3314 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003315 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316
3317 if (s == NULL)
3318 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003319 if (*s == NUL)
3320 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321 if (STRNCMP(s, "silent", 6) == 0)
3322 ++msg_silent;
3323 if (STRCMP(s, "silent!") == 0)
3324 {
3325 emsg_silent = TRUE;
3326 emsg_noredir = TRUE;
3327 }
3328 }
3329 else
3330 ++msg_silent;
3331
3332 if (redir_execute)
3333 save_ga = redir_execute_ga;
3334 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3335 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003336 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003337 if (!echo_output)
3338 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003339
3340 if (cmd != NULL)
3341 do_cmdline_cmd(cmd);
3342 else
3343 {
3344 listitem_T *item = list->lv_first;
3345
3346 do_cmdline(NULL, get_list_line, (void *)&item,
3347 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3348 --list->lv_refcount;
3349 }
3350
Bram Moolenaard297f352017-01-29 20:31:21 +01003351 /* Need to append a NUL to the result. */
3352 if (ga_grow(&redir_execute_ga, 1) == OK)
3353 {
3354 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3355 rettv->vval.v_string = redir_execute_ga.ga_data;
3356 }
3357 else
3358 {
3359 ga_clear(&redir_execute_ga);
3360 rettv->vval.v_string = NULL;
3361 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362 msg_silent = save_msg_silent;
3363 emsg_silent = save_emsg_silent;
3364 emsg_noredir = save_emsg_noredir;
3365
3366 redir_execute = save_redir_execute;
3367 if (redir_execute)
3368 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003369 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003371 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003372 if (echo_output)
3373 // When not working silently: put it in column zero. A following
3374 // "echon" will overwrite the message, unavoidably.
3375 msg_col = 0;
3376 else
3377 // When working silently: Put it back where it was, since nothing
3378 // should have been written.
3379 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380}
3381
3382/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003383 * "execute()" function
3384 */
3385 static void
3386f_execute(typval_T *argvars, typval_T *rettv)
3387{
3388 execute_common(argvars, rettv, 0);
3389}
3390
3391/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 * "exepath()" function
3393 */
3394 static void
3395f_exepath(typval_T *argvars, typval_T *rettv)
3396{
3397 char_u *p = NULL;
3398
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003399 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 rettv->v_type = VAR_STRING;
3401 rettv->vval.v_string = p;
3402}
3403
3404/*
3405 * "exists()" function
3406 */
3407 static void
3408f_exists(typval_T *argvars, typval_T *rettv)
3409{
3410 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003411 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003413 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414 if (*p == '$') /* environment variable */
3415 {
3416 /* first try "normal" environment variables (fast) */
3417 if (mch_getenv(p + 1) != NULL)
3418 n = TRUE;
3419 else
3420 {
3421 /* try expanding things like $VIM and ${HOME} */
3422 p = expand_env_save(p);
3423 if (p != NULL && *p != '$')
3424 n = TRUE;
3425 vim_free(p);
3426 }
3427 }
3428 else if (*p == '&' || *p == '+') /* option */
3429 {
3430 n = (get_option_tv(&p, NULL, TRUE) == OK);
3431 if (*skipwhite(p) != NUL)
3432 n = FALSE; /* trailing garbage */
3433 }
3434 else if (*p == '*') /* internal or user defined function */
3435 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003436 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003437 }
3438 else if (*p == ':')
3439 {
3440 n = cmd_exists(p + 1);
3441 }
3442 else if (*p == '#')
3443 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003444 if (p[1] == '#')
3445 n = autocmd_supported(p + 2);
3446 else
3447 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003448 }
3449 else /* internal variable */
3450 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003451 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003452 }
3453
3454 rettv->vval.v_number = n;
3455}
3456
3457#ifdef FEAT_FLOAT
3458/*
3459 * "exp()" function
3460 */
3461 static void
3462f_exp(typval_T *argvars, typval_T *rettv)
3463{
3464 float_T f = 0.0;
3465
3466 rettv->v_type = VAR_FLOAT;
3467 if (get_float_arg(argvars, &f) == OK)
3468 rettv->vval.v_float = exp(f);
3469 else
3470 rettv->vval.v_float = 0.0;
3471}
3472#endif
3473
3474/*
3475 * "expand()" function
3476 */
3477 static void
3478f_expand(typval_T *argvars, typval_T *rettv)
3479{
3480 char_u *s;
3481 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003482 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3484 expand_T xpc;
3485 int error = FALSE;
3486 char_u *result;
3487
3488 rettv->v_type = VAR_STRING;
3489 if (argvars[1].v_type != VAR_UNKNOWN
3490 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003491 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003493 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003495 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003496 if (*s == '%' || *s == '#' || *s == '<')
3497 {
3498 ++emsg_off;
3499 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3500 --emsg_off;
3501 if (rettv->v_type == VAR_LIST)
3502 {
3503 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3504 list_append_string(rettv->vval.v_list, result, -1);
3505 else
3506 vim_free(result);
3507 }
3508 else
3509 rettv->vval.v_string = result;
3510 }
3511 else
3512 {
3513 /* When the optional second argument is non-zero, don't remove matches
3514 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3515 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003516 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517 options |= WILD_KEEP_ALL;
3518 if (!error)
3519 {
3520 ExpandInit(&xpc);
3521 xpc.xp_context = EXPAND_FILES;
3522 if (p_wic)
3523 options += WILD_ICASE;
3524 if (rettv->v_type == VAR_STRING)
3525 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3526 options, WILD_ALL);
3527 else if (rettv_list_alloc(rettv) != FAIL)
3528 {
3529 int i;
3530
3531 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3532 for (i = 0; i < xpc.xp_numfiles; i++)
3533 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3534 ExpandCleanup(&xpc);
3535 }
3536 }
3537 else
3538 rettv->vval.v_string = NULL;
3539 }
3540}
3541
3542/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003543 * "expandcmd()" function
3544 * Expand all the special characters in a command string.
3545 */
3546 static void
3547f_expandcmd(typval_T *argvars, typval_T *rettv)
3548{
3549 exarg_T eap;
3550 char_u *cmdstr;
3551 char *errormsg = NULL;
3552
3553 rettv->v_type = VAR_STRING;
3554 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3555
3556 memset(&eap, 0, sizeof(eap));
3557 eap.cmd = cmdstr;
3558 eap.arg = cmdstr;
3559 eap.argt |= NOSPC;
3560 eap.usefilter = FALSE;
3561 eap.nextcmd = NULL;
3562 eap.cmdidx = CMD_USER;
3563
3564 expand_filename(&eap, &cmdstr, &errormsg);
3565 if (errormsg != NULL && *errormsg != NUL)
3566 emsg(errormsg);
3567
3568 rettv->vval.v_string = cmdstr;
3569}
3570
3571/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572 * "extend(list, list [, idx])" function
3573 * "extend(dict, dict [, action])" function
3574 */
3575 static void
3576f_extend(typval_T *argvars, typval_T *rettv)
3577{
3578 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3579
3580 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3581 {
3582 list_T *l1, *l2;
3583 listitem_T *item;
3584 long before;
3585 int error = FALSE;
3586
3587 l1 = argvars[0].vval.v_list;
3588 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003589 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590 && l2 != NULL)
3591 {
3592 if (argvars[2].v_type != VAR_UNKNOWN)
3593 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003594 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003595 if (error)
3596 return; /* type error; errmsg already given */
3597
3598 if (before == l1->lv_len)
3599 item = NULL;
3600 else
3601 {
3602 item = list_find(l1, before);
3603 if (item == NULL)
3604 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003605 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003606 return;
3607 }
3608 }
3609 }
3610 else
3611 item = NULL;
3612 list_extend(l1, l2, item);
3613
3614 copy_tv(&argvars[0], rettv);
3615 }
3616 }
3617 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3618 {
3619 dict_T *d1, *d2;
3620 char_u *action;
3621 int i;
3622
3623 d1 = argvars[0].vval.v_dict;
3624 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003625 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003626 && d2 != NULL)
3627 {
3628 /* Check the third argument. */
3629 if (argvars[2].v_type != VAR_UNKNOWN)
3630 {
3631 static char *(av[]) = {"keep", "force", "error"};
3632
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003633 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634 if (action == NULL)
3635 return; /* type error; errmsg already given */
3636 for (i = 0; i < 3; ++i)
3637 if (STRCMP(action, av[i]) == 0)
3638 break;
3639 if (i == 3)
3640 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003641 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642 return;
3643 }
3644 }
3645 else
3646 action = (char_u *)"force";
3647
3648 dict_extend(d1, d2, action);
3649
3650 copy_tv(&argvars[0], rettv);
3651 }
3652 }
3653 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003654 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003655}
3656
3657/*
3658 * "feedkeys()" function
3659 */
3660 static void
3661f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3662{
3663 int remap = TRUE;
3664 int insert = FALSE;
3665 char_u *keys, *flags;
3666 char_u nbuf[NUMBUFLEN];
3667 int typed = FALSE;
3668 int execute = FALSE;
3669 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003670 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003671 char_u *keys_esc;
3672
3673 /* This is not allowed in the sandbox. If the commands would still be
3674 * executed in the sandbox it would be OK, but it probably happens later,
3675 * when "sandbox" is no longer set. */
3676 if (check_secure())
3677 return;
3678
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003679 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003680
3681 if (argvars[1].v_type != VAR_UNKNOWN)
3682 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003683 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003684 for ( ; *flags != NUL; ++flags)
3685 {
3686 switch (*flags)
3687 {
3688 case 'n': remap = FALSE; break;
3689 case 'm': remap = TRUE; break;
3690 case 't': typed = TRUE; break;
3691 case 'i': insert = TRUE; break;
3692 case 'x': execute = TRUE; break;
3693 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003694 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695 }
3696 }
3697 }
3698
3699 if (*keys != NUL || execute)
3700 {
3701 /* Need to escape K_SPECIAL and CSI before putting the string in the
3702 * typeahead buffer. */
3703 keys_esc = vim_strsave_escape_csi(keys);
3704 if (keys_esc != NULL)
3705 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003706 if (lowlevel)
3707 {
3708#ifdef USE_INPUT_BUF
3709 add_to_input_buf(keys, (int)STRLEN(keys));
3710#else
3711 emsg(_("E980: lowlevel input not supported"));
3712#endif
3713 }
3714 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003715 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003716 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003717 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003718 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003719#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003720 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003721#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003722 )
3723 typebuf_was_filled = TRUE;
3724 }
3725 vim_free(keys_esc);
3726
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 if (execute)
3728 {
3729 int save_msg_scroll = msg_scroll;
3730
3731 /* Avoid a 1 second delay when the keys start Insert mode. */
3732 msg_scroll = FALSE;
3733
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003734 if (!dangerous)
3735 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003736 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003737 if (!dangerous)
3738 --ex_normal_busy;
3739
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 msg_scroll |= save_msg_scroll;
3741 }
3742 }
3743 }
3744}
3745
3746/*
3747 * "filereadable()" function
3748 */
3749 static void
3750f_filereadable(typval_T *argvars, typval_T *rettv)
3751{
3752 int fd;
3753 char_u *p;
3754 int n;
3755
3756#ifndef O_NONBLOCK
3757# define O_NONBLOCK 0
3758#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003759 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003760 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3761 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3762 {
3763 n = TRUE;
3764 close(fd);
3765 }
3766 else
3767 n = FALSE;
3768
3769 rettv->vval.v_number = n;
3770}
3771
3772/*
3773 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3774 * rights to write into.
3775 */
3776 static void
3777f_filewritable(typval_T *argvars, typval_T *rettv)
3778{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003779 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003780}
3781
3782 static void
3783findfilendir(
3784 typval_T *argvars UNUSED,
3785 typval_T *rettv,
3786 int find_what UNUSED)
3787{
3788#ifdef FEAT_SEARCHPATH
3789 char_u *fname;
3790 char_u *fresult = NULL;
3791 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3792 char_u *p;
3793 char_u pathbuf[NUMBUFLEN];
3794 int count = 1;
3795 int first = TRUE;
3796 int error = FALSE;
3797#endif
3798
3799 rettv->vval.v_string = NULL;
3800 rettv->v_type = VAR_STRING;
3801
3802#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003803 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003804
3805 if (argvars[1].v_type != VAR_UNKNOWN)
3806 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003807 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808 if (p == NULL)
3809 error = TRUE;
3810 else
3811 {
3812 if (*p != NUL)
3813 path = p;
3814
3815 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003816 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003817 }
3818 }
3819
3820 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3821 error = TRUE;
3822
3823 if (*fname != NUL && !error)
3824 {
3825 do
3826 {
3827 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3828 vim_free(fresult);
3829 fresult = find_file_in_path_option(first ? fname : NULL,
3830 first ? (int)STRLEN(fname) : 0,
3831 0, first, path,
3832 find_what,
3833 curbuf->b_ffname,
3834 find_what == FINDFILE_DIR
3835 ? (char_u *)"" : curbuf->b_p_sua);
3836 first = FALSE;
3837
3838 if (fresult != NULL && rettv->v_type == VAR_LIST)
3839 list_append_string(rettv->vval.v_list, fresult, -1);
3840
3841 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3842 }
3843
3844 if (rettv->v_type == VAR_STRING)
3845 rettv->vval.v_string = fresult;
3846#endif
3847}
3848
3849/*
3850 * "filter()" function
3851 */
3852 static void
3853f_filter(typval_T *argvars, typval_T *rettv)
3854{
3855 filter_map(argvars, rettv, FALSE);
3856}
3857
3858/*
3859 * "finddir({fname}[, {path}[, {count}]])" function
3860 */
3861 static void
3862f_finddir(typval_T *argvars, typval_T *rettv)
3863{
3864 findfilendir(argvars, rettv, FINDFILE_DIR);
3865}
3866
3867/*
3868 * "findfile({fname}[, {path}[, {count}]])" function
3869 */
3870 static void
3871f_findfile(typval_T *argvars, typval_T *rettv)
3872{
3873 findfilendir(argvars, rettv, FINDFILE_FILE);
3874}
3875
3876#ifdef FEAT_FLOAT
3877/*
3878 * "float2nr({float})" function
3879 */
3880 static void
3881f_float2nr(typval_T *argvars, typval_T *rettv)
3882{
3883 float_T f = 0.0;
3884
3885 if (get_float_arg(argvars, &f) == OK)
3886 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003887 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003888 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003889 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003890 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003891 else
3892 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003893 }
3894}
3895
3896/*
3897 * "floor({float})" function
3898 */
3899 static void
3900f_floor(typval_T *argvars, typval_T *rettv)
3901{
3902 float_T f = 0.0;
3903
3904 rettv->v_type = VAR_FLOAT;
3905 if (get_float_arg(argvars, &f) == OK)
3906 rettv->vval.v_float = floor(f);
3907 else
3908 rettv->vval.v_float = 0.0;
3909}
3910
3911/*
3912 * "fmod()" function
3913 */
3914 static void
3915f_fmod(typval_T *argvars, typval_T *rettv)
3916{
3917 float_T fx = 0.0, fy = 0.0;
3918
3919 rettv->v_type = VAR_FLOAT;
3920 if (get_float_arg(argvars, &fx) == OK
3921 && get_float_arg(&argvars[1], &fy) == OK)
3922 rettv->vval.v_float = fmod(fx, fy);
3923 else
3924 rettv->vval.v_float = 0.0;
3925}
3926#endif
3927
3928/*
3929 * "fnameescape({string})" function
3930 */
3931 static void
3932f_fnameescape(typval_T *argvars, typval_T *rettv)
3933{
3934 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003935 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003936 rettv->v_type = VAR_STRING;
3937}
3938
3939/*
3940 * "fnamemodify({fname}, {mods})" function
3941 */
3942 static void
3943f_fnamemodify(typval_T *argvars, typval_T *rettv)
3944{
3945 char_u *fname;
3946 char_u *mods;
3947 int usedlen = 0;
3948 int len;
3949 char_u *fbuf = NULL;
3950 char_u buf[NUMBUFLEN];
3951
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003952 fname = tv_get_string_chk(&argvars[0]);
3953 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954 if (fname == NULL || mods == NULL)
3955 fname = NULL;
3956 else
3957 {
3958 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003959 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003960 }
3961
3962 rettv->v_type = VAR_STRING;
3963 if (fname == NULL)
3964 rettv->vval.v_string = NULL;
3965 else
3966 rettv->vval.v_string = vim_strnsave(fname, len);
3967 vim_free(fbuf);
3968}
3969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003970/*
3971 * "foldclosed()" function
3972 */
3973 static void
3974foldclosed_both(
3975 typval_T *argvars UNUSED,
3976 typval_T *rettv,
3977 int end UNUSED)
3978{
3979#ifdef FEAT_FOLDING
3980 linenr_T lnum;
3981 linenr_T first, last;
3982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003983 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3985 {
3986 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3987 {
3988 if (end)
3989 rettv->vval.v_number = (varnumber_T)last;
3990 else
3991 rettv->vval.v_number = (varnumber_T)first;
3992 return;
3993 }
3994 }
3995#endif
3996 rettv->vval.v_number = -1;
3997}
3998
3999/*
4000 * "foldclosed()" function
4001 */
4002 static void
4003f_foldclosed(typval_T *argvars, typval_T *rettv)
4004{
4005 foldclosed_both(argvars, rettv, FALSE);
4006}
4007
4008/*
4009 * "foldclosedend()" function
4010 */
4011 static void
4012f_foldclosedend(typval_T *argvars, typval_T *rettv)
4013{
4014 foldclosed_both(argvars, rettv, TRUE);
4015}
4016
4017/*
4018 * "foldlevel()" function
4019 */
4020 static void
4021f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4022{
4023#ifdef FEAT_FOLDING
4024 linenr_T lnum;
4025
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004026 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4028 rettv->vval.v_number = foldLevel(lnum);
4029#endif
4030}
4031
4032/*
4033 * "foldtext()" function
4034 */
4035 static void
4036f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4037{
4038#ifdef FEAT_FOLDING
4039 linenr_T foldstart;
4040 linenr_T foldend;
4041 char_u *dashes;
4042 linenr_T lnum;
4043 char_u *s;
4044 char_u *r;
4045 int len;
4046 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004047 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048#endif
4049
4050 rettv->v_type = VAR_STRING;
4051 rettv->vval.v_string = NULL;
4052#ifdef FEAT_FOLDING
4053 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4054 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4055 dashes = get_vim_var_str(VV_FOLDDASHES);
4056 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4057 && dashes != NULL)
4058 {
4059 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004060 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004061 if (!linewhite(lnum))
4062 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004063
4064 /* Find interesting text in this line. */
4065 s = skipwhite(ml_get(lnum));
4066 /* skip C comment-start */
4067 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4068 {
4069 s = skipwhite(s + 2);
4070 if (*skipwhite(s) == NUL
4071 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4072 {
4073 s = skipwhite(ml_get(lnum + 1));
4074 if (*s == '*')
4075 s = skipwhite(s + 1);
4076 }
4077 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004078 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004079 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02004080 r = alloc(STRLEN(txt)
4081 + STRLEN(dashes) // for %s
4082 + 20 // for %3ld
4083 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084 if (r != NULL)
4085 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004086 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004087 len = (int)STRLEN(r);
4088 STRCAT(r, s);
4089 /* remove 'foldmarker' and 'commentstring' */
4090 foldtext_cleanup(r + len);
4091 rettv->vval.v_string = r;
4092 }
4093 }
4094#endif
4095}
4096
4097/*
4098 * "foldtextresult(lnum)" function
4099 */
4100 static void
4101f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4102{
4103#ifdef FEAT_FOLDING
4104 linenr_T lnum;
4105 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004106 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107 foldinfo_T foldinfo;
4108 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004109 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004110#endif
4111
4112 rettv->v_type = VAR_STRING;
4113 rettv->vval.v_string = NULL;
4114#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004115 if (entered)
4116 return; /* reject recursive use */
4117 entered = TRUE;
4118
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004119 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004120 /* treat illegal types and illegal string values for {lnum} the same */
4121 if (lnum < 0)
4122 lnum = 0;
4123 fold_count = foldedCount(curwin, lnum, &foldinfo);
4124 if (fold_count > 0)
4125 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004126 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4127 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004128 if (text == buf)
4129 text = vim_strsave(text);
4130 rettv->vval.v_string = text;
4131 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004132
4133 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134#endif
4135}
4136
4137/*
4138 * "foreground()" function
4139 */
4140 static void
4141f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4142{
4143#ifdef FEAT_GUI
4144 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004145 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004147 return;
4148 }
4149#endif
4150#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004151 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004152#endif
4153}
4154
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004155 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004156common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004157{
4158 char_u *s;
4159 char_u *name;
4160 int use_string = FALSE;
4161 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004162 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004163
4164 if (argvars[0].v_type == VAR_FUNC)
4165 {
4166 /* function(MyFunc, [arg], dict) */
4167 s = argvars[0].vval.v_string;
4168 }
4169 else if (argvars[0].v_type == VAR_PARTIAL
4170 && argvars[0].vval.v_partial != NULL)
4171 {
4172 /* function(dict.MyFunc, [arg]) */
4173 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004174 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004175 }
4176 else
4177 {
4178 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004179 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004180 use_string = TRUE;
4181 }
4182
Bram Moolenaar843b8842016-08-21 14:36:15 +02004183 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004184 {
4185 name = s;
4186 trans_name = trans_function_name(&name, FALSE,
4187 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4188 if (*name != NUL)
4189 s = NULL;
4190 }
4191
Bram Moolenaar843b8842016-08-21 14:36:15 +02004192 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4193 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004194 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004195 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004196 else if (trans_name != NULL && (is_funcref
4197 ? find_func(trans_name) == NULL
4198 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004199 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004200 else
4201 {
4202 int dict_idx = 0;
4203 int arg_idx = 0;
4204 list_T *list = NULL;
4205
4206 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4207 {
4208 char sid_buf[25];
4209 int off = *s == 's' ? 2 : 5;
4210
4211 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4212 * also be called from another script. Using trans_function_name()
4213 * would also work, but some plugins depend on the name being
4214 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004215 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004216 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004217 if (name != NULL)
4218 {
4219 STRCPY(name, sid_buf);
4220 STRCAT(name, s + off);
4221 }
4222 }
4223 else
4224 name = vim_strsave(s);
4225
4226 if (argvars[1].v_type != VAR_UNKNOWN)
4227 {
4228 if (argvars[2].v_type != VAR_UNKNOWN)
4229 {
4230 /* function(name, [args], dict) */
4231 arg_idx = 1;
4232 dict_idx = 2;
4233 }
4234 else if (argvars[1].v_type == VAR_DICT)
4235 /* function(name, dict) */
4236 dict_idx = 1;
4237 else
4238 /* function(name, [args]) */
4239 arg_idx = 1;
4240 if (dict_idx > 0)
4241 {
4242 if (argvars[dict_idx].v_type != VAR_DICT)
4243 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004244 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004246 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 }
4248 if (argvars[dict_idx].vval.v_dict == NULL)
4249 dict_idx = 0;
4250 }
4251 if (arg_idx > 0)
4252 {
4253 if (argvars[arg_idx].v_type != VAR_LIST)
4254 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004255 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004257 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004258 }
4259 list = argvars[arg_idx].vval.v_list;
4260 if (list == NULL || list->lv_len == 0)
4261 arg_idx = 0;
4262 }
4263 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004264 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004266 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004267
4268 /* result is a VAR_PARTIAL */
4269 if (pt == NULL)
4270 vim_free(name);
4271 else
4272 {
4273 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4274 {
4275 listitem_T *li;
4276 int i = 0;
4277 int arg_len = 0;
4278 int lv_len = 0;
4279
4280 if (arg_pt != NULL)
4281 arg_len = arg_pt->pt_argc;
4282 if (list != NULL)
4283 lv_len = list->lv_len;
4284 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004285 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 if (pt->pt_argv == NULL)
4287 {
4288 vim_free(pt);
4289 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004290 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004291 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004292 for (i = 0; i < arg_len; i++)
4293 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4294 if (lv_len > 0)
4295 for (li = list->lv_first; li != NULL;
4296 li = li->li_next)
4297 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 }
4299
4300 /* For "function(dict.func, [], dict)" and "func" is a partial
4301 * use "dict". That is backwards compatible. */
4302 if (dict_idx > 0)
4303 {
4304 /* The dict is bound explicitly, pt_auto is FALSE. */
4305 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4306 ++pt->pt_dict->dv_refcount;
4307 }
4308 else if (arg_pt != NULL)
4309 {
4310 /* If the dict was bound automatically the result is also
4311 * bound automatically. */
4312 pt->pt_dict = arg_pt->pt_dict;
4313 pt->pt_auto = arg_pt->pt_auto;
4314 if (pt->pt_dict != NULL)
4315 ++pt->pt_dict->dv_refcount;
4316 }
4317
4318 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004319 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4320 {
4321 pt->pt_func = arg_pt->pt_func;
4322 func_ptr_ref(pt->pt_func);
4323 vim_free(name);
4324 }
4325 else if (is_funcref)
4326 {
4327 pt->pt_func = find_func(trans_name);
4328 func_ptr_ref(pt->pt_func);
4329 vim_free(name);
4330 }
4331 else
4332 {
4333 pt->pt_name = name;
4334 func_ref(name);
4335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336 }
4337 rettv->v_type = VAR_PARTIAL;
4338 rettv->vval.v_partial = pt;
4339 }
4340 else
4341 {
4342 /* result is a VAR_FUNC */
4343 rettv->v_type = VAR_FUNC;
4344 rettv->vval.v_string = name;
4345 func_ref(name);
4346 }
4347 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004348theend:
4349 vim_free(trans_name);
4350}
4351
4352/*
4353 * "funcref()" function
4354 */
4355 static void
4356f_funcref(typval_T *argvars, typval_T *rettv)
4357{
4358 common_function(argvars, rettv, TRUE);
4359}
4360
4361/*
4362 * "function()" function
4363 */
4364 static void
4365f_function(typval_T *argvars, typval_T *rettv)
4366{
4367 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004368}
4369
4370/*
4371 * "garbagecollect()" function
4372 */
4373 static void
4374f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4375{
4376 /* This is postponed until we are back at the toplevel, because we may be
4377 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4378 want_garbage_collect = TRUE;
4379
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004380 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004381 garbage_collect_at_exit = TRUE;
4382}
4383
4384/*
4385 * "get()" function
4386 */
4387 static void
4388f_get(typval_T *argvars, typval_T *rettv)
4389{
4390 listitem_T *li;
4391 list_T *l;
4392 dictitem_T *di;
4393 dict_T *d;
4394 typval_T *tv = NULL;
4395
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004396 if (argvars[0].v_type == VAR_BLOB)
4397 {
4398 int error = FALSE;
4399 int idx = tv_get_number_chk(&argvars[1], &error);
4400
4401 if (!error)
4402 {
4403 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004404 if (idx < 0)
4405 idx = blob_len(argvars[0].vval.v_blob) + idx;
4406 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4407 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004408 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004409 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004410 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004411 tv = rettv;
4412 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004413 }
4414 }
4415 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 {
4417 if ((l = argvars[0].vval.v_list) != NULL)
4418 {
4419 int error = FALSE;
4420
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004421 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004422 if (!error && li != NULL)
4423 tv = &li->li_tv;
4424 }
4425 }
4426 else if (argvars[0].v_type == VAR_DICT)
4427 {
4428 if ((d = argvars[0].vval.v_dict) != NULL)
4429 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004430 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004431 if (di != NULL)
4432 tv = &di->di_tv;
4433 }
4434 }
4435 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4436 {
4437 partial_T *pt;
4438 partial_T fref_pt;
4439
4440 if (argvars[0].v_type == VAR_PARTIAL)
4441 pt = argvars[0].vval.v_partial;
4442 else
4443 {
4444 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4445 fref_pt.pt_name = argvars[0].vval.v_string;
4446 pt = &fref_pt;
4447 }
4448
4449 if (pt != NULL)
4450 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004451 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004452 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453
4454 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4455 {
4456 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004457 n = partial_name(pt);
4458 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459 rettv->vval.v_string = NULL;
4460 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004461 {
4462 rettv->vval.v_string = vim_strsave(n);
4463 if (rettv->v_type == VAR_FUNC)
4464 func_ref(rettv->vval.v_string);
4465 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466 }
4467 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004468 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469 else if (STRCMP(what, "args") == 0)
4470 {
4471 rettv->v_type = VAR_LIST;
4472 if (rettv_list_alloc(rettv) == OK)
4473 {
4474 int i;
4475
4476 for (i = 0; i < pt->pt_argc; ++i)
4477 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4478 }
4479 }
4480 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004481 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004482 return;
4483 }
4484 }
4485 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004486 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487
4488 if (tv == NULL)
4489 {
4490 if (argvars[2].v_type != VAR_UNKNOWN)
4491 copy_tv(&argvars[2], rettv);
4492 }
4493 else
4494 copy_tv(tv, rettv);
4495}
4496
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004497/*
4498 * Returns buffer options, variables and other attributes in a dictionary.
4499 */
4500 static dict_T *
4501get_buffer_info(buf_T *buf)
4502{
4503 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004504 tabpage_T *tp;
4505 win_T *wp;
4506 list_T *windows;
4507
4508 dict = dict_alloc();
4509 if (dict == NULL)
4510 return NULL;
4511
Bram Moolenaare0be1672018-07-08 16:50:37 +02004512 dict_add_number(dict, "bufnr", buf->b_fnum);
4513 dict_add_string(dict, "name", buf->b_ffname);
4514 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4515 : buflist_findlnum(buf));
4516 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4517 dict_add_number(dict, "listed", buf->b_p_bl);
4518 dict_add_number(dict, "changed", bufIsChanged(buf));
4519 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4520 dict_add_number(dict, "hidden",
4521 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004522
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004523 /* Get a reference to buffer variables */
4524 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004525
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004526 /* List of windows displaying this buffer */
4527 windows = list_alloc();
4528 if (windows != NULL)
4529 {
4530 FOR_ALL_TAB_WINDOWS(tp, wp)
4531 if (wp->w_buffer == buf)
4532 list_append_number(windows, (varnumber_T)wp->w_id);
4533 dict_add_list(dict, "windows", windows);
4534 }
4535
4536#ifdef FEAT_SIGNS
4537 if (buf->b_signlist != NULL)
4538 {
4539 /* List of signs placed in this buffer */
4540 list_T *signs = list_alloc();
4541 if (signs != NULL)
4542 {
4543 get_buffer_signs(buf, signs);
4544 dict_add_list(dict, "signs", signs);
4545 }
4546 }
4547#endif
4548
4549 return dict;
4550}
4551
4552/*
4553 * "getbufinfo()" function
4554 */
4555 static void
4556f_getbufinfo(typval_T *argvars, typval_T *rettv)
4557{
4558 buf_T *buf = NULL;
4559 buf_T *argbuf = NULL;
4560 dict_T *d;
4561 int filtered = FALSE;
4562 int sel_buflisted = FALSE;
4563 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004564 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004565
4566 if (rettv_list_alloc(rettv) != OK)
4567 return;
4568
4569 /* List of all the buffers or selected buffers */
4570 if (argvars[0].v_type == VAR_DICT)
4571 {
4572 dict_T *sel_d = argvars[0].vval.v_dict;
4573
4574 if (sel_d != NULL)
4575 {
4576 dictitem_T *di;
4577
4578 filtered = TRUE;
4579
4580 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004581 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004582 sel_buflisted = TRUE;
4583
4584 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004585 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004586 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004587
4588 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004589 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004590 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004591 }
4592 }
4593 else if (argvars[0].v_type != VAR_UNKNOWN)
4594 {
4595 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004596 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004597 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004598 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004599 --emsg_off;
4600 if (argbuf == NULL)
4601 return;
4602 }
4603
4604 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004605 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004606 {
4607 if (argbuf != NULL && argbuf != buf)
4608 continue;
4609 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004610 || (sel_buflisted && !buf->b_p_bl)
4611 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004612 continue;
4613
4614 d = get_buffer_info(buf);
4615 if (d != NULL)
4616 list_append_dict(rettv->vval.v_list, d);
4617 if (argbuf != NULL)
4618 return;
4619 }
4620}
4621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622/*
4623 * Get line or list of lines from buffer "buf" into "rettv".
4624 * Return a range (from start to end) of lines in rettv from the specified
4625 * buffer.
4626 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4627 */
4628 static void
4629get_buffer_lines(
4630 buf_T *buf,
4631 linenr_T start,
4632 linenr_T end,
4633 int retlist,
4634 typval_T *rettv)
4635{
4636 char_u *p;
4637
4638 rettv->v_type = VAR_STRING;
4639 rettv->vval.v_string = NULL;
4640 if (retlist && rettv_list_alloc(rettv) == FAIL)
4641 return;
4642
4643 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4644 return;
4645
4646 if (!retlist)
4647 {
4648 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4649 p = ml_get_buf(buf, start, FALSE);
4650 else
4651 p = (char_u *)"";
4652 rettv->vval.v_string = vim_strsave(p);
4653 }
4654 else
4655 {
4656 if (end < start)
4657 return;
4658
4659 if (start < 1)
4660 start = 1;
4661 if (end > buf->b_ml.ml_line_count)
4662 end = buf->b_ml.ml_line_count;
4663 while (start <= end)
4664 if (list_append_string(rettv->vval.v_list,
4665 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4666 break;
4667 }
4668}
4669
4670/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004671 * "getbufline()" function
4672 */
4673 static void
4674f_getbufline(typval_T *argvars, typval_T *rettv)
4675{
4676 linenr_T lnum;
4677 linenr_T end;
4678 buf_T *buf;
4679
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004680 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004682 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683 --emsg_off;
4684
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004685 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686 if (argvars[2].v_type == VAR_UNKNOWN)
4687 end = lnum;
4688 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004689 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004690
4691 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4692}
4693
4694/*
4695 * "getbufvar()" function
4696 */
4697 static void
4698f_getbufvar(typval_T *argvars, typval_T *rettv)
4699{
4700 buf_T *buf;
4701 buf_T *save_curbuf;
4702 char_u *varname;
4703 dictitem_T *v;
4704 int done = FALSE;
4705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004706 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4707 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004709 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710
4711 rettv->v_type = VAR_STRING;
4712 rettv->vval.v_string = NULL;
4713
4714 if (buf != NULL && varname != NULL)
4715 {
4716 /* set curbuf to be our buf, temporarily */
4717 save_curbuf = curbuf;
4718 curbuf = buf;
4719
Bram Moolenaar30567352016-08-27 21:25:44 +02004720 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004722 if (varname[1] == NUL)
4723 {
4724 /* get all buffer-local options in a dict */
4725 dict_T *opts = get_winbuf_options(TRUE);
4726
4727 if (opts != NULL)
4728 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004729 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004730 done = TRUE;
4731 }
4732 }
4733 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4734 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 done = TRUE;
4736 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 else
4738 {
4739 /* Look up the variable. */
4740 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4741 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4742 'b', varname, FALSE);
4743 if (v != NULL)
4744 {
4745 copy_tv(&v->di_tv, rettv);
4746 done = TRUE;
4747 }
4748 }
4749
4750 /* restore previous notion of curbuf */
4751 curbuf = save_curbuf;
4752 }
4753
4754 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4755 /* use the default value */
4756 copy_tv(&argvars[2], rettv);
4757
4758 --emsg_off;
4759}
4760
4761/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004762 * "getchangelist()" function
4763 */
4764 static void
4765f_getchangelist(typval_T *argvars, typval_T *rettv)
4766{
4767#ifdef FEAT_JUMPLIST
4768 buf_T *buf;
4769 int i;
4770 list_T *l;
4771 dict_T *d;
4772#endif
4773
4774 if (rettv_list_alloc(rettv) != OK)
4775 return;
4776
4777#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004778 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004779 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004780 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004781 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004782 if (buf == NULL)
4783 return;
4784
4785 l = list_alloc();
4786 if (l == NULL)
4787 return;
4788
4789 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4790 return;
4791 /*
4792 * The current window change list index tracks only the position in the
4793 * current buffer change list. For other buffers, use the change list
4794 * length as the current index.
4795 */
4796 list_append_number(rettv->vval.v_list,
4797 (varnumber_T)((buf == curwin->w_buffer)
4798 ? curwin->w_changelistidx : buf->b_changelistlen));
4799
4800 for (i = 0; i < buf->b_changelistlen; ++i)
4801 {
4802 if (buf->b_changelist[i].lnum == 0)
4803 continue;
4804 if ((d = dict_alloc()) == NULL)
4805 return;
4806 if (list_append_dict(l, d) == FAIL)
4807 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004808 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4809 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004810 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004811 }
4812#endif
4813}
4814/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815 * "getchar()" function
4816 */
4817 static void
4818f_getchar(typval_T *argvars, typval_T *rettv)
4819{
4820 varnumber_T n;
4821 int error = FALSE;
4822
Bram Moolenaar84d93902018-09-11 20:10:20 +02004823#ifdef MESSAGE_QUEUE
4824 // vpeekc() used to check for messages, but that caused problems, invoking
4825 // a callback where it was not expected. Some plugins use getchar(1) in a
4826 // loop to await a message, therefore make sure we check for messages here.
4827 parse_queued_messages();
4828#endif
4829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830 /* Position the cursor. Needed after a message that ends in a space. */
4831 windgoto(msg_row, msg_col);
4832
4833 ++no_mapping;
4834 ++allow_keys;
4835 for (;;)
4836 {
4837 if (argvars[0].v_type == VAR_UNKNOWN)
4838 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004839 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004840 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841 /* getchar(1): only check if char avail */
4842 n = vpeekc_any();
4843 else if (error || vpeekc_any() == NUL)
4844 /* illegal argument or getchar(0) and no char avail: return zero */
4845 n = 0;
4846 else
4847 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004848 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004849
4850 if (n == K_IGNORE)
4851 continue;
4852 break;
4853 }
4854 --no_mapping;
4855 --allow_keys;
4856
4857 set_vim_var_nr(VV_MOUSE_WIN, 0);
4858 set_vim_var_nr(VV_MOUSE_WINID, 0);
4859 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4860 set_vim_var_nr(VV_MOUSE_COL, 0);
4861
4862 rettv->vval.v_number = n;
4863 if (IS_SPECIAL(n) || mod_mask != 0)
4864 {
4865 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4866 int i = 0;
4867
4868 /* Turn a special key into three bytes, plus modifier. */
4869 if (mod_mask != 0)
4870 {
4871 temp[i++] = K_SPECIAL;
4872 temp[i++] = KS_MODIFIER;
4873 temp[i++] = mod_mask;
4874 }
4875 if (IS_SPECIAL(n))
4876 {
4877 temp[i++] = K_SPECIAL;
4878 temp[i++] = K_SECOND(n);
4879 temp[i++] = K_THIRD(n);
4880 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004881 else if (has_mbyte)
4882 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004883 else
4884 temp[i++] = n;
4885 temp[i++] = NUL;
4886 rettv->v_type = VAR_STRING;
4887 rettv->vval.v_string = vim_strsave(temp);
4888
4889#ifdef FEAT_MOUSE
4890 if (is_mouse_key(n))
4891 {
4892 int row = mouse_row;
4893 int col = mouse_col;
4894 win_T *win;
4895 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004896 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004897 int winnr = 1;
4898
4899 if (row >= 0 && col >= 0)
4900 {
4901 /* Find the window at the mouse coordinates and compute the
4902 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004903 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004904 if (win == NULL)
4905 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004907# ifdef FEAT_TEXT_PROP
4908 if (bt_popup(win->w_buffer))
4909 winnr = 0;
4910 else
4911# endif
4912 for (wp = firstwin; wp != win && wp != NULL;
4913 wp = wp->w_next)
4914 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4916 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4917 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4918 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4919 }
4920 }
4921#endif
4922 }
4923}
4924
4925/*
4926 * "getcharmod()" function
4927 */
4928 static void
4929f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4930{
4931 rettv->vval.v_number = mod_mask;
4932}
4933
4934/*
4935 * "getcharsearch()" function
4936 */
4937 static void
4938f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4939{
4940 if (rettv_dict_alloc(rettv) != FAIL)
4941 {
4942 dict_T *dict = rettv->vval.v_dict;
4943
Bram Moolenaare0be1672018-07-08 16:50:37 +02004944 dict_add_string(dict, "char", last_csearch());
4945 dict_add_number(dict, "forward", last_csearch_forward());
4946 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 }
4948}
4949
4950/*
4951 * "getcmdline()" function
4952 */
4953 static void
4954f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4955{
4956 rettv->v_type = VAR_STRING;
4957 rettv->vval.v_string = get_cmdline_str();
4958}
4959
4960/*
4961 * "getcmdpos()" function
4962 */
4963 static void
4964f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4965{
4966 rettv->vval.v_number = get_cmdline_pos() + 1;
4967}
4968
4969/*
4970 * "getcmdtype()" function
4971 */
4972 static void
4973f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4974{
4975 rettv->v_type = VAR_STRING;
4976 rettv->vval.v_string = alloc(2);
4977 if (rettv->vval.v_string != NULL)
4978 {
4979 rettv->vval.v_string[0] = get_cmdline_type();
4980 rettv->vval.v_string[1] = NUL;
4981 }
4982}
4983
4984/*
4985 * "getcmdwintype()" function
4986 */
4987 static void
4988f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4989{
4990 rettv->v_type = VAR_STRING;
4991 rettv->vval.v_string = NULL;
4992#ifdef FEAT_CMDWIN
4993 rettv->vval.v_string = alloc(2);
4994 if (rettv->vval.v_string != NULL)
4995 {
4996 rettv->vval.v_string[0] = cmdwin_type;
4997 rettv->vval.v_string[1] = NUL;
4998 }
4999#endif
5000}
5001
5002#if defined(FEAT_CMDL_COMPL)
5003/*
5004 * "getcompletion()" function
5005 */
5006 static void
5007f_getcompletion(typval_T *argvars, typval_T *rettv)
5008{
5009 char_u *pat;
5010 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005011 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005012 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5013 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005015 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005016 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005017
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005018 if (p_wic)
5019 options |= WILD_ICASE;
5020
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005021 /* For filtered results, 'wildignore' is used */
5022 if (!filtered)
5023 options |= WILD_KEEP_ALL;
5024
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005026 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005027 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005028 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005029 if (xpc.xp_context == EXPAND_NOTHING)
5030 {
5031 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005032 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005033 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005034 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035 return;
5036 }
5037
5038# if defined(FEAT_MENU)
5039 if (xpc.xp_context == EXPAND_MENUS)
5040 {
5041 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5042 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5043 }
5044# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005045#ifdef FEAT_CSCOPE
5046 if (xpc.xp_context == EXPAND_CSCOPE)
5047 {
5048 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5049 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5050 }
5051#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005052#ifdef FEAT_SIGNS
5053 if (xpc.xp_context == EXPAND_SIGN)
5054 {
5055 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5056 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5057 }
5058#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059
5060 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5061 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5062 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005063 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005064
5065 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5066
5067 for (i = 0; i < xpc.xp_numfiles; i++)
5068 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5069 }
5070 vim_free(pat);
5071 ExpandCleanup(&xpc);
5072}
5073#endif
5074
5075/*
5076 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005077 *
5078 * Return the current working directory of a window in a tab page.
5079 * First optional argument 'winnr' is the window number or -1 and the second
5080 * optional argument 'tabnr' is the tab page number.
5081 *
5082 * If no arguments are supplied, then return the directory of the current
5083 * window.
5084 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
5085 * the specified window.
5086 * If 'winnr' is 0 then return the directory of the current window.
5087 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
5088 * directory of the specified tab page. Otherwise return the directory of the
5089 * specified window in the specified tab page.
5090 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005091 */
5092 static void
5093f_getcwd(typval_T *argvars, typval_T *rettv)
5094{
5095 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005096 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005098 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099
5100 rettv->v_type = VAR_STRING;
5101 rettv->vval.v_string = NULL;
5102
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005103 if (argvars[0].v_type == VAR_NUMBER
5104 && argvars[0].vval.v_number == -1
5105 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01005106 global = TRUE;
5107 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005108 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01005109
5110 if (wp != NULL && wp->w_localdir != NULL)
5111 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005112 else if (tp != NULL && tp->tp_localdir != NULL)
5113 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
5114 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005116 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 rettv->vval.v_string = vim_strsave(globaldir);
5118 else
5119 {
5120 cwd = alloc(MAXPATHL);
5121 if (cwd != NULL)
5122 {
5123 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5124 rettv->vval.v_string = vim_strsave(cwd);
5125 vim_free(cwd);
5126 }
5127 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005128 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005129#ifdef BACKSLASH_IN_FILENAME
5130 if (rettv->vval.v_string != NULL)
5131 slash_adjust(rettv->vval.v_string);
5132#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005133}
5134
5135/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02005136 * "getenv()" function
5137 */
5138 static void
5139f_getenv(typval_T *argvars, typval_T *rettv)
5140{
5141 int mustfree = FALSE;
5142 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
5143
5144 if (p == NULL)
5145 {
5146 rettv->v_type = VAR_SPECIAL;
5147 rettv->vval.v_number = VVAL_NULL;
5148 return;
5149 }
5150 if (!mustfree)
5151 p = vim_strsave(p);
5152 rettv->vval.v_string = p;
5153 rettv->v_type = VAR_STRING;
5154}
5155
5156/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005157 * "getfontname()" function
5158 */
5159 static void
5160f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5161{
5162 rettv->v_type = VAR_STRING;
5163 rettv->vval.v_string = NULL;
5164#ifdef FEAT_GUI
5165 if (gui.in_use)
5166 {
5167 GuiFont font;
5168 char_u *name = NULL;
5169
5170 if (argvars[0].v_type == VAR_UNKNOWN)
5171 {
5172 /* Get the "Normal" font. Either the name saved by
5173 * hl_set_font_name() or from the font ID. */
5174 font = gui.norm_font;
5175 name = hl_get_font_name();
5176 }
5177 else
5178 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005179 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5181 return;
5182 font = gui_mch_get_font(name, FALSE);
5183 if (font == NOFONT)
5184 return; /* Invalid font name, return empty string. */
5185 }
5186 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5187 if (argvars[0].v_type != VAR_UNKNOWN)
5188 gui_mch_free_font(font);
5189 }
5190#endif
5191}
5192
5193/*
5194 * "getfperm({fname})" function
5195 */
5196 static void
5197f_getfperm(typval_T *argvars, typval_T *rettv)
5198{
5199 char_u *fname;
5200 stat_T st;
5201 char_u *perm = NULL;
5202 char_u flags[] = "rwx";
5203 int i;
5204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005205 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005206
5207 rettv->v_type = VAR_STRING;
5208 if (mch_stat((char *)fname, &st) >= 0)
5209 {
5210 perm = vim_strsave((char_u *)"---------");
5211 if (perm != NULL)
5212 {
5213 for (i = 0; i < 9; i++)
5214 {
5215 if (st.st_mode & (1 << (8 - i)))
5216 perm[i] = flags[i % 3];
5217 }
5218 }
5219 }
5220 rettv->vval.v_string = perm;
5221}
5222
5223/*
5224 * "getfsize({fname})" function
5225 */
5226 static void
5227f_getfsize(typval_T *argvars, typval_T *rettv)
5228{
5229 char_u *fname;
5230 stat_T st;
5231
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005232 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233
5234 rettv->v_type = VAR_NUMBER;
5235
5236 if (mch_stat((char *)fname, &st) >= 0)
5237 {
5238 if (mch_isdir(fname))
5239 rettv->vval.v_number = 0;
5240 else
5241 {
5242 rettv->vval.v_number = (varnumber_T)st.st_size;
5243
5244 /* non-perfect check for overflow */
5245 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5246 rettv->vval.v_number = -2;
5247 }
5248 }
5249 else
5250 rettv->vval.v_number = -1;
5251}
5252
5253/*
5254 * "getftime({fname})" function
5255 */
5256 static void
5257f_getftime(typval_T *argvars, typval_T *rettv)
5258{
5259 char_u *fname;
5260 stat_T st;
5261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005262 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005263
5264 if (mch_stat((char *)fname, &st) >= 0)
5265 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5266 else
5267 rettv->vval.v_number = -1;
5268}
5269
5270/*
5271 * "getftype({fname})" function
5272 */
5273 static void
5274f_getftype(typval_T *argvars, typval_T *rettv)
5275{
5276 char_u *fname;
5277 stat_T st;
5278 char_u *type = NULL;
5279 char *t;
5280
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005281 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005282
5283 rettv->v_type = VAR_STRING;
5284 if (mch_lstat((char *)fname, &st) >= 0)
5285 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286 if (S_ISREG(st.st_mode))
5287 t = "file";
5288 else if (S_ISDIR(st.st_mode))
5289 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290 else if (S_ISLNK(st.st_mode))
5291 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 else if (S_ISBLK(st.st_mode))
5293 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 else if (S_ISCHR(st.st_mode))
5295 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 else if (S_ISFIFO(st.st_mode))
5297 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005299 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300 else
5301 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005302 type = vim_strsave((char_u *)t);
5303 }
5304 rettv->vval.v_string = type;
5305}
5306
5307/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005308 * "getjumplist()" function
5309 */
5310 static void
5311f_getjumplist(typval_T *argvars, typval_T *rettv)
5312{
5313#ifdef FEAT_JUMPLIST
5314 win_T *wp;
5315 int i;
5316 list_T *l;
5317 dict_T *d;
5318#endif
5319
5320 if (rettv_list_alloc(rettv) != OK)
5321 return;
5322
5323#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005324 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005325 if (wp == NULL)
5326 return;
5327
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005328 cleanup_jumplist(wp, TRUE);
5329
Bram Moolenaar4f505882018-02-10 21:06:32 +01005330 l = list_alloc();
5331 if (l == NULL)
5332 return;
5333
5334 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5335 return;
5336 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5337
5338 for (i = 0; i < wp->w_jumplistlen; ++i)
5339 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005340 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5341 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005342 if ((d = dict_alloc()) == NULL)
5343 return;
5344 if (list_append_dict(l, d) == FAIL)
5345 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005346 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5347 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005348 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005349 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005350 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005351 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005352 }
5353#endif
5354}
5355
5356/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005357 * "getline(lnum, [end])" function
5358 */
5359 static void
5360f_getline(typval_T *argvars, typval_T *rettv)
5361{
5362 linenr_T lnum;
5363 linenr_T end;
5364 int retlist;
5365
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005366 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005367 if (argvars[1].v_type == VAR_UNKNOWN)
5368 {
5369 end = 0;
5370 retlist = FALSE;
5371 }
5372 else
5373 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005374 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005375 retlist = TRUE;
5376 }
5377
5378 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5379}
5380
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005381#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005382 static void
5383get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5384{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005385 if (what_arg->v_type == VAR_UNKNOWN)
5386 {
5387 if (rettv_list_alloc(rettv) == OK)
5388 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005389 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005390 }
5391 else
5392 {
5393 if (rettv_dict_alloc(rettv) == OK)
5394 if (is_qf || (wp != NULL))
5395 {
5396 if (what_arg->v_type == VAR_DICT)
5397 {
5398 dict_T *d = what_arg->vval.v_dict;
5399
5400 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005401 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005402 }
5403 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005404 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005405 }
5406 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005407}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005408#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005409
5410/*
5411 * "getloclist()" function
5412 */
5413 static void
5414f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5415{
5416#ifdef FEAT_QUICKFIX
5417 win_T *wp;
5418
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005419 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005420 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5421#endif
5422}
5423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005424/*
5425 * "getmatches()" function
5426 */
5427 static void
5428f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5429{
5430#ifdef FEAT_SEARCH_EXTRA
5431 dict_T *dict;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005432 matchitem_T *cur;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005433 int i;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005434 win_T *win = get_optional_window(argvars, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005435
Bram Moolenaaraff74912019-03-30 18:11:49 +01005436 if (rettv_list_alloc(rettv) == FAIL || win == NULL)
5437 return;
5438
5439 cur = win->w_match_head;
5440 while (cur != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005441 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005442 dict = dict_alloc();
5443 if (dict == NULL)
5444 return;
5445 if (cur->match.regprog == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005446 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005447 /* match added with matchaddpos() */
5448 for (i = 0; i < MAXPOSMATCH; ++i)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005449 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005450 llpos_T *llpos;
Bram Moolenaar54315892019-04-26 22:33:49 +02005451 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaaraff74912019-03-30 18:11:49 +01005452 list_T *l;
5453
5454 llpos = &cur->pos.pos[i];
5455 if (llpos->lnum == 0)
5456 break;
5457 l = list_alloc();
5458 if (l == NULL)
5459 break;
5460 list_append_number(l, (varnumber_T)llpos->lnum);
5461 if (llpos->col > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005462 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005463 list_append_number(l, (varnumber_T)llpos->col);
5464 list_append_number(l, (varnumber_T)llpos->len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005465 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005466 sprintf(buf, "pos%d", i + 1);
5467 dict_add_list(dict, buf, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005468 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005469 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005470 else
5471 {
5472 dict_add_string(dict, "pattern", cur->pattern);
5473 }
5474 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5475 dict_add_number(dict, "priority", (long)cur->priority);
5476 dict_add_number(dict, "id", (long)cur->id);
5477# if defined(FEAT_CONCEAL)
5478 if (cur->conceal_char)
5479 {
5480 char_u buf[MB_MAXBYTES + 1];
5481
5482 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5483 dict_add_string(dict, "conceal", (char_u *)&buf);
5484 }
5485# endif
5486 list_append_dict(rettv->vval.v_list, dict);
5487 cur = cur->next;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005488 }
5489#endif
5490}
5491
5492/*
5493 * "getpid()" function
5494 */
5495 static void
5496f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5497{
5498 rettv->vval.v_number = mch_get_pid();
5499}
5500
5501 static void
5502getpos_both(
5503 typval_T *argvars,
5504 typval_T *rettv,
5505 int getcurpos)
5506{
5507 pos_T *fp;
5508 list_T *l;
5509 int fnum = -1;
5510
5511 if (rettv_list_alloc(rettv) == OK)
5512 {
5513 l = rettv->vval.v_list;
5514 if (getcurpos)
5515 fp = &curwin->w_cursor;
5516 else
5517 fp = var2fpos(&argvars[0], TRUE, &fnum);
5518 if (fnum != -1)
5519 list_append_number(l, (varnumber_T)fnum);
5520 else
5521 list_append_number(l, (varnumber_T)0);
5522 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5523 : (varnumber_T)0);
5524 list_append_number(l, (fp != NULL)
5525 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5526 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005527 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528 (varnumber_T)0);
5529 if (getcurpos)
5530 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005531 int save_set_curswant = curwin->w_set_curswant;
5532 colnr_T save_curswant = curwin->w_curswant;
5533 colnr_T save_virtcol = curwin->w_virtcol;
5534
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005535 update_curswant();
5536 list_append_number(l, curwin->w_curswant == MAXCOL ?
5537 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005538
5539 // Do not change "curswant", as it is unexpected that a get
5540 // function has a side effect.
5541 if (save_set_curswant)
5542 {
5543 curwin->w_set_curswant = save_set_curswant;
5544 curwin->w_curswant = save_curswant;
5545 curwin->w_virtcol = save_virtcol;
5546 curwin->w_valid &= ~VALID_VIRTCOL;
5547 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 }
5549 }
5550 else
5551 rettv->vval.v_number = FALSE;
5552}
5553
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554/*
5555 * "getcurpos()" function
5556 */
5557 static void
5558f_getcurpos(typval_T *argvars, typval_T *rettv)
5559{
5560 getpos_both(argvars, rettv, TRUE);
5561}
5562
5563/*
5564 * "getpos(string)" function
5565 */
5566 static void
5567f_getpos(typval_T *argvars, typval_T *rettv)
5568{
5569 getpos_both(argvars, rettv, FALSE);
5570}
5571
5572/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005573 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005574 */
5575 static void
5576f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5577{
5578#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005579 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580#endif
5581}
5582
5583/*
5584 * "getreg()" function
5585 */
5586 static void
5587f_getreg(typval_T *argvars, typval_T *rettv)
5588{
5589 char_u *strregname;
5590 int regname;
5591 int arg2 = FALSE;
5592 int return_list = FALSE;
5593 int error = FALSE;
5594
5595 if (argvars[0].v_type != VAR_UNKNOWN)
5596 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005597 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 error = strregname == NULL;
5599 if (argvars[1].v_type != VAR_UNKNOWN)
5600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005601 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 }
5605 }
5606 else
5607 strregname = get_vim_var_str(VV_REG);
5608
5609 if (error)
5610 return;
5611
5612 regname = (strregname == NULL ? '"' : *strregname);
5613 if (regname == 0)
5614 regname = '"';
5615
5616 if (return_list)
5617 {
5618 rettv->v_type = VAR_LIST;
5619 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5620 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5621 if (rettv->vval.v_list == NULL)
5622 (void)rettv_list_alloc(rettv);
5623 else
5624 ++rettv->vval.v_list->lv_refcount;
5625 }
5626 else
5627 {
5628 rettv->v_type = VAR_STRING;
5629 rettv->vval.v_string = get_reg_contents(regname,
5630 arg2 ? GREG_EXPR_SRC : 0);
5631 }
5632}
5633
5634/*
5635 * "getregtype()" function
5636 */
5637 static void
5638f_getregtype(typval_T *argvars, typval_T *rettv)
5639{
5640 char_u *strregname;
5641 int regname;
5642 char_u buf[NUMBUFLEN + 2];
5643 long reglen = 0;
5644
5645 if (argvars[0].v_type != VAR_UNKNOWN)
5646 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005647 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 if (strregname == NULL) /* type error; errmsg already given */
5649 {
5650 rettv->v_type = VAR_STRING;
5651 rettv->vval.v_string = NULL;
5652 return;
5653 }
5654 }
5655 else
5656 /* Default to v:register */
5657 strregname = get_vim_var_str(VV_REG);
5658
5659 regname = (strregname == NULL ? '"' : *strregname);
5660 if (regname == 0)
5661 regname = '"';
5662
5663 buf[0] = NUL;
5664 buf[1] = NUL;
5665 switch (get_reg_type(regname, &reglen))
5666 {
5667 case MLINE: buf[0] = 'V'; break;
5668 case MCHAR: buf[0] = 'v'; break;
5669 case MBLOCK:
5670 buf[0] = Ctrl_V;
5671 sprintf((char *)buf + 1, "%ld", reglen + 1);
5672 break;
5673 }
5674 rettv->v_type = VAR_STRING;
5675 rettv->vval.v_string = vim_strsave(buf);
5676}
5677
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005678/*
5679 * Returns information (variables, options, etc.) about a tab page
5680 * as a dictionary.
5681 */
5682 static dict_T *
5683get_tabpage_info(tabpage_T *tp, int tp_idx)
5684{
5685 win_T *wp;
5686 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005687 list_T *l;
5688
5689 dict = dict_alloc();
5690 if (dict == NULL)
5691 return NULL;
5692
Bram Moolenaare0be1672018-07-08 16:50:37 +02005693 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005694
5695 l = list_alloc();
5696 if (l != NULL)
5697 {
5698 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5699 wp; wp = wp->w_next)
5700 list_append_number(l, (varnumber_T)wp->w_id);
5701 dict_add_list(dict, "windows", l);
5702 }
5703
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005704 /* Make a reference to tabpage variables */
5705 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005706
5707 return dict;
5708}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005709
5710/*
5711 * "gettabinfo()" function
5712 */
5713 static void
5714f_gettabinfo(typval_T *argvars, typval_T *rettv)
5715{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005716 tabpage_T *tp, *tparg = NULL;
5717 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005718 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005719
5720 if (rettv_list_alloc(rettv) != OK)
5721 return;
5722
5723 if (argvars[0].v_type != VAR_UNKNOWN)
5724 {
5725 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005726 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005727 if (tparg == NULL)
5728 return;
5729 }
5730
5731 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005732 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005733 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005734 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005735 if (tparg != NULL && tp != tparg)
5736 continue;
5737 d = get_tabpage_info(tp, tpnr);
5738 if (d != NULL)
5739 list_append_dict(rettv->vval.v_list, d);
5740 if (tparg != NULL)
5741 return;
5742 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005743}
5744
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005745/*
5746 * "gettabvar()" function
5747 */
5748 static void
5749f_gettabvar(typval_T *argvars, typval_T *rettv)
5750{
5751 win_T *oldcurwin;
5752 tabpage_T *tp, *oldtabpage;
5753 dictitem_T *v;
5754 char_u *varname;
5755 int done = FALSE;
5756
5757 rettv->v_type = VAR_STRING;
5758 rettv->vval.v_string = NULL;
5759
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005760 varname = tv_get_string_chk(&argvars[1]);
5761 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005762 if (tp != NULL && varname != NULL)
5763 {
5764 /* Set tp to be our tabpage, temporarily. Also set the window to the
5765 * first window in the tabpage, otherwise the window is not valid. */
5766 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005767 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5768 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005769 {
5770 /* look up the variable */
5771 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5772 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5773 if (v != NULL)
5774 {
5775 copy_tv(&v->di_tv, rettv);
5776 done = TRUE;
5777 }
5778 }
5779
5780 /* restore previous notion of curwin */
5781 restore_win(oldcurwin, oldtabpage, TRUE);
5782 }
5783
5784 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5785 copy_tv(&argvars[2], rettv);
5786}
5787
5788/*
5789 * "gettabwinvar()" function
5790 */
5791 static void
5792f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5793{
5794 getwinvar(argvars, rettv, 1);
5795}
5796
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005797/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005798 * "gettagstack()" function
5799 */
5800 static void
5801f_gettagstack(typval_T *argvars, typval_T *rettv)
5802{
5803 win_T *wp = curwin; // default is current window
5804
5805 if (rettv_dict_alloc(rettv) != OK)
5806 return;
5807
5808 if (argvars[0].v_type != VAR_UNKNOWN)
5809 {
5810 wp = find_win_by_nr_or_id(&argvars[0]);
5811 if (wp == NULL)
5812 return;
5813 }
5814
5815 get_tagstack(wp, rettv->vval.v_dict);
5816}
5817
5818/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005819 * Returns information about a window as a dictionary.
5820 */
5821 static dict_T *
5822get_win_info(win_T *wp, short tpnr, short winnr)
5823{
5824 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005825
5826 dict = dict_alloc();
5827 if (dict == NULL)
5828 return NULL;
5829
Bram Moolenaare0be1672018-07-08 16:50:37 +02005830 dict_add_number(dict, "tabnr", tpnr);
5831 dict_add_number(dict, "winnr", winnr);
5832 dict_add_number(dict, "winid", wp->w_id);
5833 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005834 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005835 dict_add_number(dict, "topline", wp->w_topline);
5836 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005837#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005838 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005839#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005840 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005841 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005842 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005843
Bram Moolenaar69905d12017-08-13 18:14:47 +02005844#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005845 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005846#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005847#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005848 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5849 dict_add_number(dict, "loclist",
5850 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005851#endif
5852
Bram Moolenaar30567352016-08-27 21:25:44 +02005853 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005854 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005855
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005856 return dict;
5857}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005858
5859/*
5860 * "getwininfo()" function
5861 */
5862 static void
5863f_getwininfo(typval_T *argvars, typval_T *rettv)
5864{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005865 tabpage_T *tp;
5866 win_T *wp = NULL, *wparg = NULL;
5867 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005868 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005869
5870 if (rettv_list_alloc(rettv) != OK)
5871 return;
5872
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005873 if (argvars[0].v_type != VAR_UNKNOWN)
5874 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005875 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005876 if (wparg == NULL)
5877 return;
5878 }
5879
5880 /* Collect information about either all the windows across all the tab
5881 * pages or one particular window.
5882 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005883 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005884 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005885 tabnr++;
5886 winnr = 0;
5887 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005888 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005889 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005890 if (wparg != NULL && wp != wparg)
5891 continue;
5892 d = get_win_info(wp, tabnr, winnr);
5893 if (d != NULL)
5894 list_append_dict(rettv->vval.v_list, d);
5895 if (wparg != NULL)
5896 /* found information about a specific window */
5897 return;
5898 }
5899 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005900}
5901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005902/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005903 * "win_execute()" function
5904 */
5905 static void
5906f_win_execute(typval_T *argvars, typval_T *rettv)
5907{
5908 int id = (int)tv_get_number(argvars);
5909 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005910 win_T *save_curwin;
5911 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005912
5913 if (wp != NULL)
5914 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005915 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5916 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005917 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005918 check_cursor();
5919 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005920 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005921 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005922 }
5923}
5924
5925/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005926 * "win_findbuf()" function
5927 */
5928 static void
5929f_win_findbuf(typval_T *argvars, typval_T *rettv)
5930{
5931 if (rettv_list_alloc(rettv) != FAIL)
5932 win_findbuf(argvars, rettv->vval.v_list);
5933}
5934
5935/*
5936 * "win_getid()" function
5937 */
5938 static void
5939f_win_getid(typval_T *argvars, typval_T *rettv)
5940{
5941 rettv->vval.v_number = win_getid(argvars);
5942}
5943
5944/*
5945 * "win_gotoid()" function
5946 */
5947 static void
5948f_win_gotoid(typval_T *argvars, typval_T *rettv)
5949{
5950 rettv->vval.v_number = win_gotoid(argvars);
5951}
5952
5953/*
5954 * "win_id2tabwin()" function
5955 */
5956 static void
5957f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5958{
5959 if (rettv_list_alloc(rettv) != FAIL)
5960 win_id2tabwin(argvars, rettv->vval.v_list);
5961}
5962
5963/*
5964 * "win_id2win()" function
5965 */
5966 static void
5967f_win_id2win(typval_T *argvars, typval_T *rettv)
5968{
5969 rettv->vval.v_number = win_id2win(argvars);
5970}
5971
5972/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005973 * "win_screenpos()" function
5974 */
5975 static void
5976f_win_screenpos(typval_T *argvars, typval_T *rettv)
5977{
5978 win_T *wp;
5979
5980 if (rettv_list_alloc(rettv) == FAIL)
5981 return;
5982
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005983 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005984 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5985 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5986}
5987
5988/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005989 * "getwinpos({timeout})" function
5990 */
5991 static void
5992f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5993{
5994 int x = -1;
5995 int y = -1;
5996
5997 if (rettv_list_alloc(rettv) == FAIL)
5998 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005999#if defined(FEAT_GUI) \
6000 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6001 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006002 {
6003 varnumber_T timeout = 100;
6004
6005 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006006 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006007
6008 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006009 }
6010#endif
6011 list_append_number(rettv->vval.v_list, (varnumber_T)x);
6012 list_append_number(rettv->vval.v_list, (varnumber_T)y);
6013}
6014
6015
6016/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006017 * "getwinposx()" function
6018 */
6019 static void
6020f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
6021{
6022 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006023#if defined(FEAT_GUI) \
6024 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6025 || defined(MSWIN)
6026
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006027 {
6028 int x, y;
6029
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006030 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006031 rettv->vval.v_number = x;
6032 }
6033#endif
6034}
6035
6036/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006037 * "getwinposy()" function
6038 */
6039 static void
6040f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6041{
6042 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02006043#if defined(FEAT_GUI) \
6044 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
6045 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006046 {
6047 int x, y;
6048
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02006049 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006050 rettv->vval.v_number = y;
6051 }
6052#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006053}
6054
6055/*
6056 * "getwinvar()" function
6057 */
6058 static void
6059f_getwinvar(typval_T *argvars, typval_T *rettv)
6060{
6061 getwinvar(argvars, rettv, 0);
6062}
6063
6064/*
6065 * "glob()" function
6066 */
6067 static void
6068f_glob(typval_T *argvars, typval_T *rettv)
6069{
6070 int options = WILD_SILENT|WILD_USE_NL;
6071 expand_T xpc;
6072 int error = FALSE;
6073
6074 /* When the optional second argument is non-zero, don't remove matches
6075 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6076 rettv->v_type = VAR_STRING;
6077 if (argvars[1].v_type != VAR_UNKNOWN)
6078 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006079 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080 options |= WILD_KEEP_ALL;
6081 if (argvars[2].v_type != VAR_UNKNOWN)
6082 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006083 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006084 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006085 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006086 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087 options |= WILD_ALLLINKS;
6088 }
6089 }
6090 if (!error)
6091 {
6092 ExpandInit(&xpc);
6093 xpc.xp_context = EXPAND_FILES;
6094 if (p_wic)
6095 options += WILD_ICASE;
6096 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006097 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006098 NULL, options, WILD_ALL);
6099 else if (rettv_list_alloc(rettv) != FAIL)
6100 {
6101 int i;
6102
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006103 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006104 NULL, options, WILD_ALL_KEEP);
6105 for (i = 0; i < xpc.xp_numfiles; i++)
6106 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6107
6108 ExpandCleanup(&xpc);
6109 }
6110 }
6111 else
6112 rettv->vval.v_string = NULL;
6113}
6114
6115/*
6116 * "globpath()" function
6117 */
6118 static void
6119f_globpath(typval_T *argvars, typval_T *rettv)
6120{
6121 int flags = 0;
6122 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006123 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006124 int error = FALSE;
6125 garray_T ga;
6126 int i;
6127
6128 /* When the optional second argument is non-zero, don't remove matches
6129 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6130 rettv->v_type = VAR_STRING;
6131 if (argvars[2].v_type != VAR_UNKNOWN)
6132 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006133 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006134 flags |= WILD_KEEP_ALL;
6135 if (argvars[3].v_type != VAR_UNKNOWN)
6136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006137 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006138 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006139 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006140 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006141 flags |= WILD_ALLLINKS;
6142 }
6143 }
6144 if (file != NULL && !error)
6145 {
6146 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006147 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006148 if (rettv->v_type == VAR_STRING)
6149 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6150 else if (rettv_list_alloc(rettv) != FAIL)
6151 for (i = 0; i < ga.ga_len; ++i)
6152 list_append_string(rettv->vval.v_list,
6153 ((char_u **)(ga.ga_data))[i], -1);
6154 ga_clear_strings(&ga);
6155 }
6156 else
6157 rettv->vval.v_string = NULL;
6158}
6159
6160/*
6161 * "glob2regpat()" function
6162 */
6163 static void
6164f_glob2regpat(typval_T *argvars, typval_T *rettv)
6165{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006166 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006167
6168 rettv->v_type = VAR_STRING;
6169 rettv->vval.v_string = (pat == NULL)
6170 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6171}
6172
6173/* for VIM_VERSION_ defines */
6174#include "version.h"
6175
6176/*
6177 * "has()" function
6178 */
6179 static void
6180f_has(typval_T *argvars, typval_T *rettv)
6181{
6182 int i;
6183 char_u *name;
6184 int n = FALSE;
6185 static char *(has_list[]) =
6186 {
6187#ifdef AMIGA
6188 "amiga",
6189# ifdef FEAT_ARP
6190 "arp",
6191# endif
6192#endif
6193#ifdef __BEOS__
6194 "beos",
6195#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006196#if defined(BSD) && !defined(MACOS_X)
6197 "bsd",
6198#endif
6199#ifdef hpux
6200 "hpux",
6201#endif
6202#ifdef __linux__
6203 "linux",
6204#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006205#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006206 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6207 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006208# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006209 "macunix", /* Mac OS X, with the darwin feature */
6210 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006211# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212#endif
6213#ifdef __QNX__
6214 "qnx",
6215#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006216#ifdef SUN_SYSTEM
6217 "sun",
6218#else
6219 "moon",
6220#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006221#ifdef UNIX
6222 "unix",
6223#endif
6224#ifdef VMS
6225 "vms",
6226#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006227#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006228 "win32",
6229#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006230#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006231 "win32unix",
6232#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006233#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006234 "win64",
6235#endif
6236#ifdef EBCDIC
6237 "ebcdic",
6238#endif
6239#ifndef CASE_INSENSITIVE_FILENAME
6240 "fname_case",
6241#endif
6242#ifdef HAVE_ACL
6243 "acl",
6244#endif
6245#ifdef FEAT_ARABIC
6246 "arabic",
6247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006248 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006249#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006250 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006251#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006252#ifdef FEAT_AUTOSERVERNAME
6253 "autoservername",
6254#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006255#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006257# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006258 "balloon_multiline",
6259# endif
6260#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006261#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006262 "balloon_eval_term",
6263#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6265 "builtin_terms",
6266# ifdef ALL_BUILTIN_TCAPS
6267 "all_builtin_terms",
6268# endif
6269#endif
6270#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006271 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 || defined(FEAT_GUI_MOTIF))
6273 "browsefilter",
6274#endif
6275#ifdef FEAT_BYTEOFF
6276 "byte_offset",
6277#endif
6278#ifdef FEAT_JOB_CHANNEL
6279 "channel",
6280#endif
6281#ifdef FEAT_CINDENT
6282 "cindent",
6283#endif
6284#ifdef FEAT_CLIENTSERVER
6285 "clientserver",
6286#endif
6287#ifdef FEAT_CLIPBOARD
6288 "clipboard",
6289#endif
6290#ifdef FEAT_CMDL_COMPL
6291 "cmdline_compl",
6292#endif
6293#ifdef FEAT_CMDHIST
6294 "cmdline_hist",
6295#endif
6296#ifdef FEAT_COMMENTS
6297 "comments",
6298#endif
6299#ifdef FEAT_CONCEAL
6300 "conceal",
6301#endif
6302#ifdef FEAT_CRYPT
6303 "cryptv",
6304 "crypt-blowfish",
6305 "crypt-blowfish2",
6306#endif
6307#ifdef FEAT_CSCOPE
6308 "cscope",
6309#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006310 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006311#ifdef CURSOR_SHAPE
6312 "cursorshape",
6313#endif
6314#ifdef DEBUG
6315 "debug",
6316#endif
6317#ifdef FEAT_CON_DIALOG
6318 "dialog_con",
6319#endif
6320#ifdef FEAT_GUI_DIALOG
6321 "dialog_gui",
6322#endif
6323#ifdef FEAT_DIFF
6324 "diff",
6325#endif
6326#ifdef FEAT_DIGRAPHS
6327 "digraphs",
6328#endif
6329#ifdef FEAT_DIRECTX
6330 "directx",
6331#endif
6332#ifdef FEAT_DND
6333 "dnd",
6334#endif
6335#ifdef FEAT_EMACS_TAGS
6336 "emacs_tags",
6337#endif
6338 "eval", /* always present, of course! */
6339 "ex_extra", /* graduated feature */
6340#ifdef FEAT_SEARCH_EXTRA
6341 "extra_search",
6342#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343#ifdef FEAT_SEARCHPATH
6344 "file_in_path",
6345#endif
6346#ifdef FEAT_FILTERPIPE
6347 "filterpipe",
6348#endif
6349#ifdef FEAT_FIND_ID
6350 "find_in_path",
6351#endif
6352#ifdef FEAT_FLOAT
6353 "float",
6354#endif
6355#ifdef FEAT_FOLDING
6356 "folding",
6357#endif
6358#ifdef FEAT_FOOTER
6359 "footer",
6360#endif
6361#if !defined(USE_SYSTEM) && defined(UNIX)
6362 "fork",
6363#endif
6364#ifdef FEAT_GETTEXT
6365 "gettext",
6366#endif
6367#ifdef FEAT_GUI
6368 "gui",
6369#endif
6370#ifdef FEAT_GUI_ATHENA
6371# ifdef FEAT_GUI_NEXTAW
6372 "gui_neXtaw",
6373# else
6374 "gui_athena",
6375# endif
6376#endif
6377#ifdef FEAT_GUI_GTK
6378 "gui_gtk",
6379# ifdef USE_GTK3
6380 "gui_gtk3",
6381# else
6382 "gui_gtk2",
6383# endif
6384#endif
6385#ifdef FEAT_GUI_GNOME
6386 "gui_gnome",
6387#endif
6388#ifdef FEAT_GUI_MAC
6389 "gui_mac",
6390#endif
6391#ifdef FEAT_GUI_MOTIF
6392 "gui_motif",
6393#endif
6394#ifdef FEAT_GUI_PHOTON
6395 "gui_photon",
6396#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006397#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006398 "gui_win32",
6399#endif
6400#ifdef FEAT_HANGULIN
6401 "hangul_input",
6402#endif
6403#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6404 "iconv",
6405#endif
6406#ifdef FEAT_INS_EXPAND
6407 "insert_expand",
6408#endif
6409#ifdef FEAT_JOB_CHANNEL
6410 "job",
6411#endif
6412#ifdef FEAT_JUMPLIST
6413 "jumplist",
6414#endif
6415#ifdef FEAT_KEYMAP
6416 "keymap",
6417#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006418 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006419#ifdef FEAT_LANGMAP
6420 "langmap",
6421#endif
6422#ifdef FEAT_LIBCALL
6423 "libcall",
6424#endif
6425#ifdef FEAT_LINEBREAK
6426 "linebreak",
6427#endif
6428#ifdef FEAT_LISP
6429 "lispindent",
6430#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006431 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432#ifdef FEAT_LOCALMAP
6433 "localmap",
6434#endif
6435#ifdef FEAT_LUA
6436# ifndef DYNAMIC_LUA
6437 "lua",
6438# endif
6439#endif
6440#ifdef FEAT_MENU
6441 "menu",
6442#endif
6443#ifdef FEAT_SESSION
6444 "mksession",
6445#endif
6446#ifdef FEAT_MODIFY_FNAME
6447 "modify_fname",
6448#endif
6449#ifdef FEAT_MOUSE
6450 "mouse",
6451#endif
6452#ifdef FEAT_MOUSESHAPE
6453 "mouseshape",
6454#endif
6455#if defined(UNIX) || defined(VMS)
6456# ifdef FEAT_MOUSE_DEC
6457 "mouse_dec",
6458# endif
6459# ifdef FEAT_MOUSE_GPM
6460 "mouse_gpm",
6461# endif
6462# ifdef FEAT_MOUSE_JSB
6463 "mouse_jsbterm",
6464# endif
6465# ifdef FEAT_MOUSE_NET
6466 "mouse_netterm",
6467# endif
6468# ifdef FEAT_MOUSE_PTERM
6469 "mouse_pterm",
6470# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006471# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472 "mouse_sgr",
6473# endif
6474# ifdef FEAT_SYSMOUSE
6475 "mouse_sysmouse",
6476# endif
6477# ifdef FEAT_MOUSE_URXVT
6478 "mouse_urxvt",
6479# endif
6480# ifdef FEAT_MOUSE_XTERM
6481 "mouse_xterm",
6482# endif
6483#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485#ifdef FEAT_MBYTE_IME
6486 "multi_byte_ime",
6487#endif
6488#ifdef FEAT_MULTI_LANG
6489 "multi_lang",
6490#endif
6491#ifdef FEAT_MZSCHEME
6492#ifndef DYNAMIC_MZSCHEME
6493 "mzscheme",
6494#endif
6495#endif
6496#ifdef FEAT_NUM64
6497 "num64",
6498#endif
6499#ifdef FEAT_OLE
6500 "ole",
6501#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006502#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006504#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505#ifdef FEAT_PATH_EXTRA
6506 "path_extra",
6507#endif
6508#ifdef FEAT_PERL
6509#ifndef DYNAMIC_PERL
6510 "perl",
6511#endif
6512#endif
6513#ifdef FEAT_PERSISTENT_UNDO
6514 "persistent_undo",
6515#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006516#if defined(FEAT_PYTHON)
6517 "python_compiled",
6518# if defined(DYNAMIC_PYTHON)
6519 "python_dynamic",
6520# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006522 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006523# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006524#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006525#if defined(FEAT_PYTHON3)
6526 "python3_compiled",
6527# if defined(DYNAMIC_PYTHON3)
6528 "python3_dynamic",
6529# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006531 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006532# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006533#endif
6534#ifdef FEAT_POSTSCRIPT
6535 "postscript",
6536#endif
6537#ifdef FEAT_PRINTER
6538 "printer",
6539#endif
6540#ifdef FEAT_PROFILE
6541 "profile",
6542#endif
6543#ifdef FEAT_RELTIME
6544 "reltime",
6545#endif
6546#ifdef FEAT_QUICKFIX
6547 "quickfix",
6548#endif
6549#ifdef FEAT_RIGHTLEFT
6550 "rightleft",
6551#endif
6552#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6553 "ruby",
6554#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006556#ifdef FEAT_CMDL_INFO
6557 "showcmd",
6558 "cmdline_info",
6559#endif
6560#ifdef FEAT_SIGNS
6561 "signs",
6562#endif
6563#ifdef FEAT_SMARTINDENT
6564 "smartindent",
6565#endif
6566#ifdef STARTUPTIME
6567 "startuptime",
6568#endif
6569#ifdef FEAT_STL_OPT
6570 "statusline",
6571#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006572#ifdef FEAT_NETBEANS_INTG
6573 "netbeans_intg",
6574#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006575#ifdef FEAT_SOUND
6576 "sound",
6577#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006578#ifdef FEAT_SPELL
6579 "spell",
6580#endif
6581#ifdef FEAT_SYN_HL
6582 "syntax",
6583#endif
6584#if defined(USE_SYSTEM) || !defined(UNIX)
6585 "system",
6586#endif
6587#ifdef FEAT_TAG_BINS
6588 "tag_binary",
6589#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590#ifdef FEAT_TCL
6591# ifndef DYNAMIC_TCL
6592 "tcl",
6593# endif
6594#endif
6595#ifdef FEAT_TERMGUICOLORS
6596 "termguicolors",
6597#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006598#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006599 "terminal",
6600#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006601#ifdef TERMINFO
6602 "terminfo",
6603#endif
6604#ifdef FEAT_TERMRESPONSE
6605 "termresponse",
6606#endif
6607#ifdef FEAT_TEXTOBJ
6608 "textobjects",
6609#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006610#ifdef FEAT_TEXT_PROP
6611 "textprop",
6612#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006613#ifdef HAVE_TGETENT
6614 "tgetent",
6615#endif
6616#ifdef FEAT_TIMERS
6617 "timers",
6618#endif
6619#ifdef FEAT_TITLE
6620 "title",
6621#endif
6622#ifdef FEAT_TOOLBAR
6623 "toolbar",
6624#endif
6625#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6626 "unnamedplus",
6627#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006628 "user-commands", /* was accidentally included in 5.4 */
6629 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006630#ifdef FEAT_VARTABS
6631 "vartabs",
6632#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006633 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006634#ifdef FEAT_VIMINFO
6635 "viminfo",
6636#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006637 "vimscript-1",
6638 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006639 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006643 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006644#ifdef FEAT_VTP
6645 "vtp",
6646#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006647#ifdef FEAT_WILDIGN
6648 "wildignore",
6649#endif
6650#ifdef FEAT_WILDMENU
6651 "wildmenu",
6652#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006653 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006654#ifdef FEAT_WAK
6655 "winaltkeys",
6656#endif
6657#ifdef FEAT_WRITEBACKUP
6658 "writebackup",
6659#endif
6660#ifdef FEAT_XIM
6661 "xim",
6662#endif
6663#ifdef FEAT_XFONTSET
6664 "xfontset",
6665#endif
6666#ifdef FEAT_XPM_W32
6667 "xpm",
6668 "xpm_w32", /* for backward compatibility */
6669#else
6670# if defined(HAVE_XPM)
6671 "xpm",
6672# endif
6673#endif
6674#ifdef USE_XSMP
6675 "xsmp",
6676#endif
6677#ifdef USE_XSMP_INTERACT
6678 "xsmp_interact",
6679#endif
6680#ifdef FEAT_XCLIPBOARD
6681 "xterm_clipboard",
6682#endif
6683#ifdef FEAT_XTERM_SAVE
6684 "xterm_save",
6685#endif
6686#if defined(UNIX) && defined(FEAT_X11)
6687 "X11",
6688#endif
6689 NULL
6690 };
6691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006692 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 for (i = 0; has_list[i] != NULL; ++i)
6694 if (STRICMP(name, has_list[i]) == 0)
6695 {
6696 n = TRUE;
6697 break;
6698 }
6699
6700 if (n == FALSE)
6701 {
6702 if (STRNICMP(name, "patch", 5) == 0)
6703 {
6704 if (name[5] == '-'
6705 && STRLEN(name) >= 11
6706 && vim_isdigit(name[6])
6707 && vim_isdigit(name[8])
6708 && vim_isdigit(name[10]))
6709 {
6710 int major = atoi((char *)name + 6);
6711 int minor = atoi((char *)name + 8);
6712
6713 /* Expect "patch-9.9.01234". */
6714 n = (major < VIM_VERSION_MAJOR
6715 || (major == VIM_VERSION_MAJOR
6716 && (minor < VIM_VERSION_MINOR
6717 || (minor == VIM_VERSION_MINOR
6718 && has_patch(atoi((char *)name + 10))))));
6719 }
6720 else
6721 n = has_patch(atoi((char *)name + 5));
6722 }
6723 else if (STRICMP(name, "vim_starting") == 0)
6724 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006725 else if (STRICMP(name, "ttyin") == 0)
6726 n = mch_input_isatty();
6727 else if (STRICMP(name, "ttyout") == 0)
6728 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006729 else if (STRICMP(name, "multi_byte_encoding") == 0)
6730 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006731#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732 else if (STRICMP(name, "balloon_multiline") == 0)
6733 n = multiline_balloon_available();
6734#endif
6735#ifdef DYNAMIC_TCL
6736 else if (STRICMP(name, "tcl") == 0)
6737 n = tcl_enabled(FALSE);
6738#endif
6739#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6740 else if (STRICMP(name, "iconv") == 0)
6741 n = iconv_enabled(FALSE);
6742#endif
6743#ifdef DYNAMIC_LUA
6744 else if (STRICMP(name, "lua") == 0)
6745 n = lua_enabled(FALSE);
6746#endif
6747#ifdef DYNAMIC_MZSCHEME
6748 else if (STRICMP(name, "mzscheme") == 0)
6749 n = mzscheme_enabled(FALSE);
6750#endif
6751#ifdef DYNAMIC_RUBY
6752 else if (STRICMP(name, "ruby") == 0)
6753 n = ruby_enabled(FALSE);
6754#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006755#ifdef DYNAMIC_PYTHON
6756 else if (STRICMP(name, "python") == 0)
6757 n = python_enabled(FALSE);
6758#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759#ifdef DYNAMIC_PYTHON3
6760 else if (STRICMP(name, "python3") == 0)
6761 n = python3_enabled(FALSE);
6762#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006763#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6764 else if (STRICMP(name, "pythonx") == 0)
6765 {
6766# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6767 if (p_pyx == 0)
6768 n = python3_enabled(FALSE) || python_enabled(FALSE);
6769 else if (p_pyx == 3)
6770 n = python3_enabled(FALSE);
6771 else if (p_pyx == 2)
6772 n = python_enabled(FALSE);
6773# elif defined(DYNAMIC_PYTHON)
6774 n = python_enabled(FALSE);
6775# elif defined(DYNAMIC_PYTHON3)
6776 n = python3_enabled(FALSE);
6777# endif
6778 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779#endif
6780#ifdef DYNAMIC_PERL
6781 else if (STRICMP(name, "perl") == 0)
6782 n = perl_enabled(FALSE);
6783#endif
6784#ifdef FEAT_GUI
6785 else if (STRICMP(name, "gui_running") == 0)
6786 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006787# ifdef FEAT_BROWSE
6788 else if (STRICMP(name, "browse") == 0)
6789 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6790# endif
6791#endif
6792#ifdef FEAT_SYN_HL
6793 else if (STRICMP(name, "syntax_items") == 0)
6794 n = syntax_present(curwin);
6795#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006796#ifdef FEAT_VTP
6797 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006798 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006799#endif
6800#ifdef FEAT_NETBEANS_INTG
6801 else if (STRICMP(name, "netbeans_enabled") == 0)
6802 n = netbeans_active();
6803#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006804#ifdef FEAT_MOUSE_GPM
6805 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6806 n = gpm_enabled();
6807#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006808#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006809 else if (STRICMP(name, "terminal") == 0)
6810 n = terminal_enabled();
6811#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006812#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006813 else if (STRICMP(name, "conpty") == 0)
6814 n = use_conpty();
6815#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006816 }
6817
6818 rettv->vval.v_number = n;
6819}
6820
6821/*
6822 * "has_key()" function
6823 */
6824 static void
6825f_has_key(typval_T *argvars, typval_T *rettv)
6826{
6827 if (argvars[0].v_type != VAR_DICT)
6828 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006829 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830 return;
6831 }
6832 if (argvars[0].vval.v_dict == NULL)
6833 return;
6834
6835 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006836 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837}
6838
6839/*
6840 * "haslocaldir()" function
6841 */
6842 static void
6843f_haslocaldir(typval_T *argvars, typval_T *rettv)
6844{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006845 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006846 win_T *wp = NULL;
6847
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006848 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6849
6850 // Check for window-local and tab-local directories
6851 if (wp != NULL && wp->w_localdir != NULL)
6852 rettv->vval.v_number = 1;
6853 else if (tp != NULL && tp->tp_localdir != NULL)
6854 rettv->vval.v_number = 2;
6855 else
6856 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857}
6858
6859/*
6860 * "hasmapto()" function
6861 */
6862 static void
6863f_hasmapto(typval_T *argvars, typval_T *rettv)
6864{
6865 char_u *name;
6866 char_u *mode;
6867 char_u buf[NUMBUFLEN];
6868 int abbr = FALSE;
6869
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006870 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006871 if (argvars[1].v_type == VAR_UNKNOWN)
6872 mode = (char_u *)"nvo";
6873 else
6874 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006875 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006876 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006877 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 }
6879
6880 if (map_to_exists(name, mode, abbr))
6881 rettv->vval.v_number = TRUE;
6882 else
6883 rettv->vval.v_number = FALSE;
6884}
6885
6886/*
6887 * "histadd()" function
6888 */
6889 static void
6890f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6891{
6892#ifdef FEAT_CMDHIST
6893 int histype;
6894 char_u *str;
6895 char_u buf[NUMBUFLEN];
6896#endif
6897
6898 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006899 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006900 return;
6901#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006902 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006903 histype = str != NULL ? get_histtype(str) : -1;
6904 if (histype >= 0)
6905 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006906 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006907 if (*str != NUL)
6908 {
6909 init_history();
6910 add_to_history(histype, str, FALSE, NUL);
6911 rettv->vval.v_number = TRUE;
6912 return;
6913 }
6914 }
6915#endif
6916}
6917
6918/*
6919 * "histdel()" function
6920 */
6921 static void
6922f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6923{
6924#ifdef FEAT_CMDHIST
6925 int n;
6926 char_u buf[NUMBUFLEN];
6927 char_u *str;
6928
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006929 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 if (str == NULL)
6931 n = 0;
6932 else if (argvars[1].v_type == VAR_UNKNOWN)
6933 /* only one argument: clear entire history */
6934 n = clr_history(get_histtype(str));
6935 else if (argvars[1].v_type == VAR_NUMBER)
6936 /* index given: remove that entry */
6937 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006938 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006939 else
6940 /* string given: remove all matching entries */
6941 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006942 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006943 rettv->vval.v_number = n;
6944#endif
6945}
6946
6947/*
6948 * "histget()" function
6949 */
6950 static void
6951f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6952{
6953#ifdef FEAT_CMDHIST
6954 int type;
6955 int idx;
6956 char_u *str;
6957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006958 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959 if (str == NULL)
6960 rettv->vval.v_string = NULL;
6961 else
6962 {
6963 type = get_histtype(str);
6964 if (argvars[1].v_type == VAR_UNKNOWN)
6965 idx = get_history_idx(type);
6966 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006967 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006968 /* -1 on type error */
6969 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6970 }
6971#else
6972 rettv->vval.v_string = NULL;
6973#endif
6974 rettv->v_type = VAR_STRING;
6975}
6976
6977/*
6978 * "histnr()" function
6979 */
6980 static void
6981f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6982{
6983 int i;
6984
6985#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006986 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006987
6988 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6989 if (i >= HIST_CMD && i < HIST_COUNT)
6990 i = get_history_idx(i);
6991 else
6992#endif
6993 i = -1;
6994 rettv->vval.v_number = i;
6995}
6996
6997/*
6998 * "highlightID(name)" function
6999 */
7000 static void
7001f_hlID(typval_T *argvars, typval_T *rettv)
7002{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007003 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007004}
7005
7006/*
7007 * "highlight_exists()" function
7008 */
7009 static void
7010f_hlexists(typval_T *argvars, typval_T *rettv)
7011{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007012 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007013}
7014
7015/*
7016 * "hostname()" function
7017 */
7018 static void
7019f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
7020{
7021 char_u hostname[256];
7022
7023 mch_get_host_name(hostname, 256);
7024 rettv->v_type = VAR_STRING;
7025 rettv->vval.v_string = vim_strsave(hostname);
7026}
7027
7028/*
7029 * iconv() function
7030 */
7031 static void
7032f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7033{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 char_u buf1[NUMBUFLEN];
7035 char_u buf2[NUMBUFLEN];
7036 char_u *from, *to, *str;
7037 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038
7039 rettv->v_type = VAR_STRING;
7040 rettv->vval.v_string = NULL;
7041
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007042 str = tv_get_string(&argvars[0]);
7043 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7044 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007045 vimconv.vc_type = CONV_NONE;
7046 convert_setup(&vimconv, from, to);
7047
7048 /* If the encodings are equal, no conversion needed. */
7049 if (vimconv.vc_type == CONV_NONE)
7050 rettv->vval.v_string = vim_strsave(str);
7051 else
7052 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7053
7054 convert_setup(&vimconv, NULL, NULL);
7055 vim_free(from);
7056 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007057}
7058
7059/*
7060 * "indent()" function
7061 */
7062 static void
7063f_indent(typval_T *argvars, typval_T *rettv)
7064{
7065 linenr_T lnum;
7066
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007067 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7069 rettv->vval.v_number = get_indent_lnum(lnum);
7070 else
7071 rettv->vval.v_number = -1;
7072}
7073
7074/*
7075 * "index()" function
7076 */
7077 static void
7078f_index(typval_T *argvars, typval_T *rettv)
7079{
7080 list_T *l;
7081 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007082 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007083 long idx = 0;
7084 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007085 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007086
7087 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007088 if (argvars[0].v_type == VAR_BLOB)
7089 {
7090 typval_T tv;
7091 int start = 0;
7092
7093 if (argvars[2].v_type != VAR_UNKNOWN)
7094 {
7095 start = tv_get_number_chk(&argvars[2], &error);
7096 if (error)
7097 return;
7098 }
7099 b = argvars[0].vval.v_blob;
7100 if (b == NULL)
7101 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007102 if (start < 0)
7103 {
7104 start = blob_len(b) + start;
7105 if (start < 0)
7106 start = 0;
7107 }
7108
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007109 for (idx = start; idx < blob_len(b); ++idx)
7110 {
7111 tv.v_type = VAR_NUMBER;
7112 tv.vval.v_number = blob_get(b, idx);
7113 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7114 {
7115 rettv->vval.v_number = idx;
7116 return;
7117 }
7118 }
7119 return;
7120 }
7121 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007122 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007123 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 return;
7125 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007126
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007127 l = argvars[0].vval.v_list;
7128 if (l != NULL)
7129 {
7130 item = l->lv_first;
7131 if (argvars[2].v_type != VAR_UNKNOWN)
7132 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133 /* Start at specified item. Use the cached index that list_find()
7134 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007135 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 idx = l->lv_idx;
7137 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007138 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007139 if (error)
7140 item = NULL;
7141 }
7142
7143 for ( ; item != NULL; item = item->li_next, ++idx)
7144 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7145 {
7146 rettv->vval.v_number = idx;
7147 break;
7148 }
7149 }
7150}
7151
7152static int inputsecret_flag = 0;
7153
7154/*
7155 * "input()" function
7156 * Also handles inputsecret() when inputsecret is set.
7157 */
7158 static void
7159f_input(typval_T *argvars, typval_T *rettv)
7160{
7161 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7162}
7163
7164/*
7165 * "inputdialog()" function
7166 */
7167 static void
7168f_inputdialog(typval_T *argvars, typval_T *rettv)
7169{
7170#if defined(FEAT_GUI_TEXTDIALOG)
7171 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7172 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7173 {
7174 char_u *message;
7175 char_u buf[NUMBUFLEN];
7176 char_u *defstr = (char_u *)"";
7177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007178 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007179 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007180 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007181 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7182 else
7183 IObuff[0] = NUL;
7184 if (message != NULL && defstr != NULL
7185 && do_dialog(VIM_QUESTION, NULL, message,
7186 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7187 rettv->vval.v_string = vim_strsave(IObuff);
7188 else
7189 {
7190 if (message != NULL && defstr != NULL
7191 && argvars[1].v_type != VAR_UNKNOWN
7192 && argvars[2].v_type != VAR_UNKNOWN)
7193 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007194 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195 else
7196 rettv->vval.v_string = NULL;
7197 }
7198 rettv->v_type = VAR_STRING;
7199 }
7200 else
7201#endif
7202 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7203}
7204
7205/*
7206 * "inputlist()" function
7207 */
7208 static void
7209f_inputlist(typval_T *argvars, typval_T *rettv)
7210{
7211 listitem_T *li;
7212 int selected;
7213 int mouse_used;
7214
7215#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007216 /* While starting up, there is no place to enter text. When running tests
7217 * with --not-a-term we assume feedkeys() will be used. */
7218 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007219 return;
7220#endif
7221 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7222 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007223 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007224 return;
7225 }
7226
7227 msg_start();
7228 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7229 lines_left = Rows; /* avoid more prompt */
7230 msg_scroll = TRUE;
7231 msg_clr_eos();
7232
7233 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7234 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007235 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 msg_putchar('\n');
7237 }
7238
7239 /* Ask for choice. */
7240 selected = prompt_for_number(&mouse_used);
7241 if (mouse_used)
7242 selected -= lines_left;
7243
7244 rettv->vval.v_number = selected;
7245}
7246
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7248
7249/*
7250 * "inputrestore()" function
7251 */
7252 static void
7253f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7254{
7255 if (ga_userinput.ga_len > 0)
7256 {
7257 --ga_userinput.ga_len;
7258 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7259 + ga_userinput.ga_len);
7260 /* default return is zero == OK */
7261 }
7262 else if (p_verbose > 1)
7263 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007264 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265 rettv->vval.v_number = 1; /* Failed */
7266 }
7267}
7268
7269/*
7270 * "inputsave()" function
7271 */
7272 static void
7273f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7274{
7275 /* Add an entry to the stack of typeahead storage. */
7276 if (ga_grow(&ga_userinput, 1) == OK)
7277 {
7278 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7279 + ga_userinput.ga_len);
7280 ++ga_userinput.ga_len;
7281 /* default return is zero == OK */
7282 }
7283 else
7284 rettv->vval.v_number = 1; /* Failed */
7285}
7286
7287/*
7288 * "inputsecret()" function
7289 */
7290 static void
7291f_inputsecret(typval_T *argvars, typval_T *rettv)
7292{
7293 ++cmdline_star;
7294 ++inputsecret_flag;
7295 f_input(argvars, rettv);
7296 --cmdline_star;
7297 --inputsecret_flag;
7298}
7299
7300/*
7301 * "insert()" function
7302 */
7303 static void
7304f_insert(typval_T *argvars, typval_T *rettv)
7305{
7306 long before = 0;
7307 listitem_T *item;
7308 list_T *l;
7309 int error = FALSE;
7310
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007311 if (argvars[0].v_type == VAR_BLOB)
7312 {
7313 int val, len;
7314 char_u *p;
7315
7316 len = blob_len(argvars[0].vval.v_blob);
7317 if (argvars[2].v_type != VAR_UNKNOWN)
7318 {
7319 before = (long)tv_get_number_chk(&argvars[2], &error);
7320 if (error)
7321 return; // type error; errmsg already given
7322 if (before < 0 || before > len)
7323 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007324 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007325 return;
7326 }
7327 }
7328 val = tv_get_number_chk(&argvars[1], &error);
7329 if (error)
7330 return;
7331 if (val < 0 || val > 255)
7332 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007333 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007334 return;
7335 }
7336
7337 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7338 return;
7339 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7340 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7341 *(p + before) = val;
7342 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7343
7344 copy_tv(&argvars[0], rettv);
7345 }
7346 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007347 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007348 else if ((l = argvars[0].vval.v_list) != NULL
7349 && !var_check_lock(l->lv_lock,
7350 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351 {
7352 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007353 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007354 if (error)
7355 return; /* type error; errmsg already given */
7356
7357 if (before == l->lv_len)
7358 item = NULL;
7359 else
7360 {
7361 item = list_find(l, before);
7362 if (item == NULL)
7363 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007364 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 l = NULL;
7366 }
7367 }
7368 if (l != NULL)
7369 {
7370 list_insert_tv(l, &argvars[1], item);
7371 copy_tv(&argvars[0], rettv);
7372 }
7373 }
7374}
7375
7376/*
7377 * "invert(expr)" function
7378 */
7379 static void
7380f_invert(typval_T *argvars, typval_T *rettv)
7381{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007382 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383}
7384
7385/*
7386 * "isdirectory()" function
7387 */
7388 static void
7389f_isdirectory(typval_T *argvars, typval_T *rettv)
7390{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007391 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392}
7393
7394/*
7395 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7396 * or it refers to a List or Dictionary that is locked.
7397 */
7398 static int
7399tv_islocked(typval_T *tv)
7400{
7401 return (tv->v_lock & VAR_LOCKED)
7402 || (tv->v_type == VAR_LIST
7403 && tv->vval.v_list != NULL
7404 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7405 || (tv->v_type == VAR_DICT
7406 && tv->vval.v_dict != NULL
7407 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7408}
7409
7410/*
7411 * "islocked()" function
7412 */
7413 static void
7414f_islocked(typval_T *argvars, typval_T *rettv)
7415{
7416 lval_T lv;
7417 char_u *end;
7418 dictitem_T *di;
7419
7420 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007421 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007422 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 if (end != NULL && lv.ll_name != NULL)
7424 {
7425 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007426 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 else
7428 {
7429 if (lv.ll_tv == NULL)
7430 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007431 di = find_var(lv.ll_name, NULL, TRUE);
7432 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007434 /* Consider a variable locked when:
7435 * 1. the variable itself is locked
7436 * 2. the value of the variable is locked.
7437 * 3. the List or Dict value is locked.
7438 */
7439 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7440 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 }
7442 }
7443 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007444 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007445 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007446 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007447 else if (lv.ll_list != NULL)
7448 /* List item. */
7449 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7450 else
7451 /* Dictionary item. */
7452 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7453 }
7454 }
7455
7456 clear_lval(&lv);
7457}
7458
7459#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7460/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007461 * "isinf()" function
7462 */
7463 static void
7464f_isinf(typval_T *argvars, typval_T *rettv)
7465{
7466 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7467 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7468}
7469
7470/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 * "isnan()" function
7472 */
7473 static void
7474f_isnan(typval_T *argvars, typval_T *rettv)
7475{
7476 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7477 && isnan(argvars[0].vval.v_float);
7478}
7479#endif
7480
7481/*
7482 * "items(dict)" function
7483 */
7484 static void
7485f_items(typval_T *argvars, typval_T *rettv)
7486{
7487 dict_list(argvars, rettv, 2);
7488}
7489
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490/*
7491 * "join()" function
7492 */
7493 static void
7494f_join(typval_T *argvars, typval_T *rettv)
7495{
7496 garray_T ga;
7497 char_u *sep;
7498
7499 if (argvars[0].v_type != VAR_LIST)
7500 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007501 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502 return;
7503 }
7504 if (argvars[0].vval.v_list == NULL)
7505 return;
7506 if (argvars[1].v_type == VAR_UNKNOWN)
7507 sep = (char_u *)" ";
7508 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007509 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510
7511 rettv->v_type = VAR_STRING;
7512
7513 if (sep != NULL)
7514 {
7515 ga_init2(&ga, (int)sizeof(char), 80);
7516 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7517 ga_append(&ga, NUL);
7518 rettv->vval.v_string = (char_u *)ga.ga_data;
7519 }
7520 else
7521 rettv->vval.v_string = NULL;
7522}
7523
7524/*
7525 * "js_decode()" function
7526 */
7527 static void
7528f_js_decode(typval_T *argvars, typval_T *rettv)
7529{
7530 js_read_T reader;
7531
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007532 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007533 reader.js_fill = NULL;
7534 reader.js_used = 0;
7535 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007536 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537}
7538
7539/*
7540 * "js_encode()" function
7541 */
7542 static void
7543f_js_encode(typval_T *argvars, typval_T *rettv)
7544{
7545 rettv->v_type = VAR_STRING;
7546 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7547}
7548
7549/*
7550 * "json_decode()" function
7551 */
7552 static void
7553f_json_decode(typval_T *argvars, typval_T *rettv)
7554{
7555 js_read_T reader;
7556
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007557 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558 reader.js_fill = NULL;
7559 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007560 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561}
7562
7563/*
7564 * "json_encode()" function
7565 */
7566 static void
7567f_json_encode(typval_T *argvars, typval_T *rettv)
7568{
7569 rettv->v_type = VAR_STRING;
7570 rettv->vval.v_string = json_encode(&argvars[0], 0);
7571}
7572
7573/*
7574 * "keys()" function
7575 */
7576 static void
7577f_keys(typval_T *argvars, typval_T *rettv)
7578{
7579 dict_list(argvars, rettv, 0);
7580}
7581
7582/*
7583 * "last_buffer_nr()" function.
7584 */
7585 static void
7586f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7587{
7588 int n = 0;
7589 buf_T *buf;
7590
Bram Moolenaar29323592016-07-24 22:04:11 +02007591 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592 if (n < buf->b_fnum)
7593 n = buf->b_fnum;
7594
7595 rettv->vval.v_number = n;
7596}
7597
7598/*
7599 * "len()" function
7600 */
7601 static void
7602f_len(typval_T *argvars, typval_T *rettv)
7603{
7604 switch (argvars[0].v_type)
7605 {
7606 case VAR_STRING:
7607 case VAR_NUMBER:
7608 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007609 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007611 case VAR_BLOB:
7612 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7613 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007614 case VAR_LIST:
7615 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7616 break;
7617 case VAR_DICT:
7618 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7619 break;
7620 case VAR_UNKNOWN:
7621 case VAR_SPECIAL:
7622 case VAR_FLOAT:
7623 case VAR_FUNC:
7624 case VAR_PARTIAL:
7625 case VAR_JOB:
7626 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007627 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007628 break;
7629 }
7630}
7631
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007633libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634{
7635#ifdef FEAT_LIBCALL
7636 char_u *string_in;
7637 char_u **string_result;
7638 int nr_result;
7639#endif
7640
7641 rettv->v_type = type;
7642 if (type != VAR_NUMBER)
7643 rettv->vval.v_string = NULL;
7644
7645 if (check_restricted() || check_secure())
7646 return;
7647
7648#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007649 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7651 {
7652 string_in = NULL;
7653 if (argvars[2].v_type == VAR_STRING)
7654 string_in = argvars[2].vval.v_string;
7655 if (type == VAR_NUMBER)
7656 string_result = NULL;
7657 else
7658 string_result = &rettv->vval.v_string;
7659 if (mch_libcall(argvars[0].vval.v_string,
7660 argvars[1].vval.v_string,
7661 string_in,
7662 argvars[2].vval.v_number,
7663 string_result,
7664 &nr_result) == OK
7665 && type == VAR_NUMBER)
7666 rettv->vval.v_number = nr_result;
7667 }
7668#endif
7669}
7670
7671/*
7672 * "libcall()" function
7673 */
7674 static void
7675f_libcall(typval_T *argvars, typval_T *rettv)
7676{
7677 libcall_common(argvars, rettv, VAR_STRING);
7678}
7679
7680/*
7681 * "libcallnr()" function
7682 */
7683 static void
7684f_libcallnr(typval_T *argvars, typval_T *rettv)
7685{
7686 libcall_common(argvars, rettv, VAR_NUMBER);
7687}
7688
7689/*
7690 * "line(string)" function
7691 */
7692 static void
7693f_line(typval_T *argvars, typval_T *rettv)
7694{
7695 linenr_T lnum = 0;
7696 pos_T *fp;
7697 int fnum;
7698
7699 fp = var2fpos(&argvars[0], TRUE, &fnum);
7700 if (fp != NULL)
7701 lnum = fp->lnum;
7702 rettv->vval.v_number = lnum;
7703}
7704
7705/*
7706 * "line2byte(lnum)" function
7707 */
7708 static void
7709f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7710{
7711#ifndef FEAT_BYTEOFF
7712 rettv->vval.v_number = -1;
7713#else
7714 linenr_T lnum;
7715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007716 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7718 rettv->vval.v_number = -1;
7719 else
7720 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7721 if (rettv->vval.v_number >= 0)
7722 ++rettv->vval.v_number;
7723#endif
7724}
7725
7726/*
7727 * "lispindent(lnum)" function
7728 */
7729 static void
7730f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7731{
7732#ifdef FEAT_LISP
7733 pos_T pos;
7734 linenr_T lnum;
7735
7736 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007737 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7739 {
7740 curwin->w_cursor.lnum = lnum;
7741 rettv->vval.v_number = get_lisp_indent();
7742 curwin->w_cursor = pos;
7743 }
7744 else
7745#endif
7746 rettv->vval.v_number = -1;
7747}
7748
7749/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007750 * "list2str()" function
7751 */
7752 static void
7753f_list2str(typval_T *argvars, typval_T *rettv)
7754{
7755 list_T *l;
7756 listitem_T *li;
7757 garray_T ga;
7758 int utf8 = FALSE;
7759
7760 rettv->v_type = VAR_STRING;
7761 rettv->vval.v_string = NULL;
7762 if (argvars[0].v_type != VAR_LIST)
7763 {
7764 emsg(_(e_invarg));
7765 return;
7766 }
7767
7768 l = argvars[0].vval.v_list;
7769 if (l == NULL)
7770 return; // empty list results in empty string
7771
7772 if (argvars[1].v_type != VAR_UNKNOWN)
7773 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7774
7775 ga_init2(&ga, 1, 80);
7776 if (has_mbyte || utf8)
7777 {
7778 char_u buf[MB_MAXBYTES + 1];
7779 int (*char2bytes)(int, char_u *);
7780
7781 if (utf8 || enc_utf8)
7782 char2bytes = utf_char2bytes;
7783 else
7784 char2bytes = mb_char2bytes;
7785
7786 for (li = l->lv_first; li != NULL; li = li->li_next)
7787 {
7788 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
7789 ga_concat(&ga, buf);
7790 }
7791 ga_append(&ga, NUL);
7792 }
7793 else if (ga_grow(&ga, list_len(l) + 1) == OK)
7794 {
7795 for (li = l->lv_first; li != NULL; li = li->li_next)
7796 ga_append(&ga, tv_get_number(&li->li_tv));
7797 ga_append(&ga, NUL);
7798 }
7799
7800 rettv->v_type = VAR_STRING;
7801 rettv->vval.v_string = ga.ga_data;
7802}
7803
7804/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805 * "localtime()" function
7806 */
7807 static void
7808f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7809{
7810 rettv->vval.v_number = (varnumber_T)time(NULL);
7811}
7812
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813 static void
7814get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7815{
7816 char_u *keys;
7817 char_u *which;
7818 char_u buf[NUMBUFLEN];
7819 char_u *keys_buf = NULL;
7820 char_u *rhs;
7821 int mode;
7822 int abbr = FALSE;
7823 int get_dict = FALSE;
7824 mapblock_T *mp;
7825 int buffer_local;
7826
7827 /* return empty string for failure */
7828 rettv->v_type = VAR_STRING;
7829 rettv->vval.v_string = NULL;
7830
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007831 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 if (*keys == NUL)
7833 return;
7834
7835 if (argvars[1].v_type != VAR_UNKNOWN)
7836 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007837 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 if (argvars[2].v_type != VAR_UNKNOWN)
7839 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007840 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007842 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 }
7844 }
7845 else
7846 which = (char_u *)"";
7847 if (which == NULL)
7848 return;
7849
7850 mode = get_map_mode(&which, 0);
7851
7852 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7853 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7854 vim_free(keys_buf);
7855
7856 if (!get_dict)
7857 {
7858 /* Return a string. */
7859 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007860 {
7861 if (*rhs == NUL)
7862 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7863 else
7864 rettv->vval.v_string = str2special_save(rhs, FALSE);
7865 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866
7867 }
7868 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7869 {
7870 /* Return a dictionary. */
7871 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7872 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7873 dict_T *dict = rettv->vval.v_dict;
7874
Bram Moolenaare0be1672018-07-08 16:50:37 +02007875 dict_add_string(dict, "lhs", lhs);
7876 dict_add_string(dict, "rhs", mp->m_orig_str);
7877 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7878 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7879 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007880 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7881 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007882 dict_add_number(dict, "buffer", (long)buffer_local);
7883 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7884 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885
7886 vim_free(lhs);
7887 vim_free(mapmode);
7888 }
7889}
7890
7891#ifdef FEAT_FLOAT
7892/*
7893 * "log()" function
7894 */
7895 static void
7896f_log(typval_T *argvars, typval_T *rettv)
7897{
7898 float_T f = 0.0;
7899
7900 rettv->v_type = VAR_FLOAT;
7901 if (get_float_arg(argvars, &f) == OK)
7902 rettv->vval.v_float = log(f);
7903 else
7904 rettv->vval.v_float = 0.0;
7905}
7906
7907/*
7908 * "log10()" function
7909 */
7910 static void
7911f_log10(typval_T *argvars, typval_T *rettv)
7912{
7913 float_T f = 0.0;
7914
7915 rettv->v_type = VAR_FLOAT;
7916 if (get_float_arg(argvars, &f) == OK)
7917 rettv->vval.v_float = log10(f);
7918 else
7919 rettv->vval.v_float = 0.0;
7920}
7921#endif
7922
7923#ifdef FEAT_LUA
7924/*
7925 * "luaeval()" function
7926 */
7927 static void
7928f_luaeval(typval_T *argvars, typval_T *rettv)
7929{
7930 char_u *str;
7931 char_u buf[NUMBUFLEN];
7932
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007933 if (check_restricted() || check_secure())
7934 return;
7935
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007936 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 do_luaeval(str, argvars + 1, rettv);
7938}
7939#endif
7940
7941/*
7942 * "map()" function
7943 */
7944 static void
7945f_map(typval_T *argvars, typval_T *rettv)
7946{
7947 filter_map(argvars, rettv, TRUE);
7948}
7949
7950/*
7951 * "maparg()" function
7952 */
7953 static void
7954f_maparg(typval_T *argvars, typval_T *rettv)
7955{
7956 get_maparg(argvars, rettv, TRUE);
7957}
7958
7959/*
7960 * "mapcheck()" function
7961 */
7962 static void
7963f_mapcheck(typval_T *argvars, typval_T *rettv)
7964{
7965 get_maparg(argvars, rettv, FALSE);
7966}
7967
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007968typedef enum
7969{
7970 MATCH_END, /* matchend() */
7971 MATCH_MATCH, /* match() */
7972 MATCH_STR, /* matchstr() */
7973 MATCH_LIST, /* matchlist() */
7974 MATCH_POS /* matchstrpos() */
7975} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976
7977 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007978find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979{
7980 char_u *str = NULL;
7981 long len = 0;
7982 char_u *expr = NULL;
7983 char_u *pat;
7984 regmatch_T regmatch;
7985 char_u patbuf[NUMBUFLEN];
7986 char_u strbuf[NUMBUFLEN];
7987 char_u *save_cpo;
7988 long start = 0;
7989 long nth = 1;
7990 colnr_T startcol = 0;
7991 int match = 0;
7992 list_T *l = NULL;
7993 listitem_T *li = NULL;
7994 long idx = 0;
7995 char_u *tofree = NULL;
7996
7997 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7998 save_cpo = p_cpo;
7999 p_cpo = (char_u *)"";
8000
8001 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008002 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008004 /* type MATCH_LIST: return empty list when there are no matches.
8005 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006 if (rettv_list_alloc(rettv) == FAIL)
8007 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008008 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 && (list_append_string(rettv->vval.v_list,
8010 (char_u *)"", 0) == FAIL
8011 || list_append_number(rettv->vval.v_list,
8012 (varnumber_T)-1) == FAIL
8013 || list_append_number(rettv->vval.v_list,
8014 (varnumber_T)-1) == FAIL
8015 || list_append_number(rettv->vval.v_list,
8016 (varnumber_T)-1) == FAIL))
8017 {
8018 list_free(rettv->vval.v_list);
8019 rettv->vval.v_list = NULL;
8020 goto theend;
8021 }
8022 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008023 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008024 {
8025 rettv->v_type = VAR_STRING;
8026 rettv->vval.v_string = NULL;
8027 }
8028
8029 if (argvars[0].v_type == VAR_LIST)
8030 {
8031 if ((l = argvars[0].vval.v_list) == NULL)
8032 goto theend;
8033 li = l->lv_first;
8034 }
8035 else
8036 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008037 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008038 len = (long)STRLEN(str);
8039 }
8040
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008041 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 if (pat == NULL)
8043 goto theend;
8044
8045 if (argvars[2].v_type != VAR_UNKNOWN)
8046 {
8047 int error = FALSE;
8048
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008049 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050 if (error)
8051 goto theend;
8052 if (l != NULL)
8053 {
8054 li = list_find(l, start);
8055 if (li == NULL)
8056 goto theend;
8057 idx = l->lv_idx; /* use the cached index */
8058 }
8059 else
8060 {
8061 if (start < 0)
8062 start = 0;
8063 if (start > len)
8064 goto theend;
8065 /* When "count" argument is there ignore matches before "start",
8066 * otherwise skip part of the string. Differs when pattern is "^"
8067 * or "\<". */
8068 if (argvars[3].v_type != VAR_UNKNOWN)
8069 startcol = start;
8070 else
8071 {
8072 str += start;
8073 len -= start;
8074 }
8075 }
8076
8077 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008078 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 if (error)
8080 goto theend;
8081 }
8082
8083 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8084 if (regmatch.regprog != NULL)
8085 {
8086 regmatch.rm_ic = p_ic;
8087
8088 for (;;)
8089 {
8090 if (l != NULL)
8091 {
8092 if (li == NULL)
8093 {
8094 match = FALSE;
8095 break;
8096 }
8097 vim_free(tofree);
8098 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8099 if (str == NULL)
8100 break;
8101 }
8102
8103 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8104
8105 if (match && --nth <= 0)
8106 break;
8107 if (l == NULL && !match)
8108 break;
8109
8110 /* Advance to just after the match. */
8111 if (l != NULL)
8112 {
8113 li = li->li_next;
8114 ++idx;
8115 }
8116 else
8117 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 startcol = (colnr_T)(regmatch.startp[0]
8119 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008120 if (startcol > (colnr_T)len
8121 || str + startcol <= regmatch.startp[0])
8122 {
8123 match = FALSE;
8124 break;
8125 }
8126 }
8127 }
8128
8129 if (match)
8130 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008131 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008132 {
8133 listitem_T *li1 = rettv->vval.v_list->lv_first;
8134 listitem_T *li2 = li1->li_next;
8135 listitem_T *li3 = li2->li_next;
8136 listitem_T *li4 = li3->li_next;
8137
8138 vim_free(li1->li_tv.vval.v_string);
8139 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8140 (int)(regmatch.endp[0] - regmatch.startp[0]));
8141 li3->li_tv.vval.v_number =
8142 (varnumber_T)(regmatch.startp[0] - expr);
8143 li4->li_tv.vval.v_number =
8144 (varnumber_T)(regmatch.endp[0] - expr);
8145 if (l != NULL)
8146 li2->li_tv.vval.v_number = (varnumber_T)idx;
8147 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008148 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008149 {
8150 int i;
8151
8152 /* return list with matched string and submatches */
8153 for (i = 0; i < NSUBEXP; ++i)
8154 {
8155 if (regmatch.endp[i] == NULL)
8156 {
8157 if (list_append_string(rettv->vval.v_list,
8158 (char_u *)"", 0) == FAIL)
8159 break;
8160 }
8161 else if (list_append_string(rettv->vval.v_list,
8162 regmatch.startp[i],
8163 (int)(regmatch.endp[i] - regmatch.startp[i]))
8164 == FAIL)
8165 break;
8166 }
8167 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008168 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008169 {
8170 /* return matched string */
8171 if (l != NULL)
8172 copy_tv(&li->li_tv, rettv);
8173 else
8174 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8175 (int)(regmatch.endp[0] - regmatch.startp[0]));
8176 }
8177 else if (l != NULL)
8178 rettv->vval.v_number = idx;
8179 else
8180 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008181 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 rettv->vval.v_number =
8183 (varnumber_T)(regmatch.startp[0] - str);
8184 else
8185 rettv->vval.v_number =
8186 (varnumber_T)(regmatch.endp[0] - str);
8187 rettv->vval.v_number += (varnumber_T)(str - expr);
8188 }
8189 }
8190 vim_regfree(regmatch.regprog);
8191 }
8192
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008193theend:
8194 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 /* matchstrpos() without a list: drop the second item. */
8196 listitem_remove(rettv->vval.v_list,
8197 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198 vim_free(tofree);
8199 p_cpo = save_cpo;
8200}
8201
8202/*
8203 * "match()" function
8204 */
8205 static void
8206f_match(typval_T *argvars, typval_T *rettv)
8207{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008208 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209}
8210
Bram Moolenaar95e51472018-07-28 16:55:56 +02008211#ifdef FEAT_SEARCH_EXTRA
8212 static int
8213matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8214{
8215 dictitem_T *di;
8216
8217 if (tv->v_type != VAR_DICT)
8218 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008219 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008220 return FAIL;
8221 }
8222
8223 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008224 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008225 (char_u *)"conceal", FALSE);
8226
8227 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8228 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008229 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008230 if (*win == NULL)
8231 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01008232 emsg(_(e_invalwindow));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008233 return FAIL;
8234 }
8235 }
8236
8237 return OK;
8238}
8239#endif
8240
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008241/*
8242 * "matchadd()" function
8243 */
8244 static void
8245f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8246{
8247#ifdef FEAT_SEARCH_EXTRA
8248 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008249 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8250 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008251 int prio = 10; /* default priority */
8252 int id = -1;
8253 int error = FALSE;
8254 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008255 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008256
8257 rettv->vval.v_number = -1;
8258
8259 if (grp == NULL || pat == NULL)
8260 return;
8261 if (argvars[2].v_type != VAR_UNKNOWN)
8262 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008263 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 if (argvars[3].v_type != VAR_UNKNOWN)
8265 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008266 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008267 if (argvars[4].v_type != VAR_UNKNOWN
8268 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8269 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270 }
8271 }
8272 if (error == TRUE)
8273 return;
8274 if (id >= 1 && id <= 3)
8275 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008276 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008277 return;
8278 }
8279
Bram Moolenaar95e51472018-07-28 16:55:56 +02008280 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281 conceal_char);
8282#endif
8283}
8284
8285/*
8286 * "matchaddpos()" function
8287 */
8288 static void
8289f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8290{
8291#ifdef FEAT_SEARCH_EXTRA
8292 char_u buf[NUMBUFLEN];
8293 char_u *group;
8294 int prio = 10;
8295 int id = -1;
8296 int error = FALSE;
8297 list_T *l;
8298 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008299 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008300
8301 rettv->vval.v_number = -1;
8302
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008303 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304 if (group == NULL)
8305 return;
8306
8307 if (argvars[1].v_type != VAR_LIST)
8308 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008309 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008310 return;
8311 }
8312 l = argvars[1].vval.v_list;
8313 if (l == NULL)
8314 return;
8315
8316 if (argvars[2].v_type != VAR_UNKNOWN)
8317 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008318 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319 if (argvars[3].v_type != VAR_UNKNOWN)
8320 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008321 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008322
8323 if (argvars[4].v_type != VAR_UNKNOWN
8324 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8325 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326 }
8327 }
8328 if (error == TRUE)
8329 return;
8330
8331 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8332 if (id == 1 || id == 2)
8333 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008334 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335 return;
8336 }
8337
Bram Moolenaar95e51472018-07-28 16:55:56 +02008338 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339 conceal_char);
8340#endif
8341}
8342
8343/*
8344 * "matcharg()" function
8345 */
8346 static void
8347f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8348{
8349 if (rettv_list_alloc(rettv) == OK)
8350 {
8351#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008352 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 matchitem_T *m;
8354
8355 if (id >= 1 && id <= 3)
8356 {
8357 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8358 {
8359 list_append_string(rettv->vval.v_list,
8360 syn_id2name(m->hlg_id), -1);
8361 list_append_string(rettv->vval.v_list, m->pattern, -1);
8362 }
8363 else
8364 {
8365 list_append_string(rettv->vval.v_list, NULL, -1);
8366 list_append_string(rettv->vval.v_list, NULL, -1);
8367 }
8368 }
8369#endif
8370 }
8371}
8372
8373/*
8374 * "matchdelete()" function
8375 */
8376 static void
8377f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8378{
8379#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01008380 win_T *win = get_optional_window(argvars, 1);
8381
8382 if (win == NULL)
8383 rettv->vval.v_number = -1;
8384 else
8385 rettv->vval.v_number = match_delete(win,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008386 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387#endif
8388}
8389
8390/*
8391 * "matchend()" function
8392 */
8393 static void
8394f_matchend(typval_T *argvars, typval_T *rettv)
8395{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008396 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008397}
8398
8399/*
8400 * "matchlist()" function
8401 */
8402 static void
8403f_matchlist(typval_T *argvars, typval_T *rettv)
8404{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008405 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008406}
8407
8408/*
8409 * "matchstr()" function
8410 */
8411 static void
8412f_matchstr(typval_T *argvars, typval_T *rettv)
8413{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008414 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008415}
8416
8417/*
8418 * "matchstrpos()" function
8419 */
8420 static void
8421f_matchstrpos(typval_T *argvars, typval_T *rettv)
8422{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008423 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008424}
8425
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008426 static void
8427max_min(typval_T *argvars, typval_T *rettv, int domax)
8428{
8429 varnumber_T n = 0;
8430 varnumber_T i;
8431 int error = FALSE;
8432
8433 if (argvars[0].v_type == VAR_LIST)
8434 {
8435 list_T *l;
8436 listitem_T *li;
8437
8438 l = argvars[0].vval.v_list;
8439 if (l != NULL)
8440 {
8441 li = l->lv_first;
8442 if (li != NULL)
8443 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008444 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008445 for (;;)
8446 {
8447 li = li->li_next;
8448 if (li == NULL)
8449 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008450 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008451 if (domax ? i > n : i < n)
8452 n = i;
8453 }
8454 }
8455 }
8456 }
8457 else if (argvars[0].v_type == VAR_DICT)
8458 {
8459 dict_T *d;
8460 int first = TRUE;
8461 hashitem_T *hi;
8462 int todo;
8463
8464 d = argvars[0].vval.v_dict;
8465 if (d != NULL)
8466 {
8467 todo = (int)d->dv_hashtab.ht_used;
8468 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8469 {
8470 if (!HASHITEM_EMPTY(hi))
8471 {
8472 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008473 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008474 if (first)
8475 {
8476 n = i;
8477 first = FALSE;
8478 }
8479 else if (domax ? i > n : i < n)
8480 n = i;
8481 }
8482 }
8483 }
8484 }
8485 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008486 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008487 rettv->vval.v_number = error ? 0 : n;
8488}
8489
8490/*
8491 * "max()" function
8492 */
8493 static void
8494f_max(typval_T *argvars, typval_T *rettv)
8495{
8496 max_min(argvars, rettv, TRUE);
8497}
8498
8499/*
8500 * "min()" function
8501 */
8502 static void
8503f_min(typval_T *argvars, typval_T *rettv)
8504{
8505 max_min(argvars, rettv, FALSE);
8506}
8507
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008508/*
8509 * Create the directory in which "dir" is located, and higher levels when
8510 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008511 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008512 */
8513 static int
8514mkdir_recurse(char_u *dir, int prot)
8515{
8516 char_u *p;
8517 char_u *updir;
8518 int r = FAIL;
8519
8520 /* Get end of directory name in "dir".
8521 * We're done when it's "/" or "c:/". */
8522 p = gettail_sep(dir);
8523 if (p <= get_past_head(dir))
8524 return OK;
8525
8526 /* If the directory exists we're done. Otherwise: create it.*/
8527 updir = vim_strnsave(dir, (int)(p - dir));
8528 if (updir == NULL)
8529 return FAIL;
8530 if (mch_isdir(updir))
8531 r = OK;
8532 else if (mkdir_recurse(updir, prot) == OK)
8533 r = vim_mkdir_emsg(updir, prot);
8534 vim_free(updir);
8535 return r;
8536}
8537
8538#ifdef vim_mkdir
8539/*
8540 * "mkdir()" function
8541 */
8542 static void
8543f_mkdir(typval_T *argvars, typval_T *rettv)
8544{
8545 char_u *dir;
8546 char_u buf[NUMBUFLEN];
8547 int prot = 0755;
8548
8549 rettv->vval.v_number = FAIL;
8550 if (check_restricted() || check_secure())
8551 return;
8552
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008553 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008554 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008555 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008556
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008557 if (*gettail(dir) == NUL)
8558 /* remove trailing slashes */
8559 *gettail_sep(dir) = NUL;
8560
8561 if (argvars[1].v_type != VAR_UNKNOWN)
8562 {
8563 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008564 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008565 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008566 if (prot == -1)
8567 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008568 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008569 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008570 {
8571 if (mch_isdir(dir))
8572 {
8573 /* With the "p" flag it's OK if the dir already exists. */
8574 rettv->vval.v_number = OK;
8575 return;
8576 }
8577 mkdir_recurse(dir, prot);
8578 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008579 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008580 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008581}
8582#endif
8583
8584/*
8585 * "mode()" function
8586 */
8587 static void
8588f_mode(typval_T *argvars, typval_T *rettv)
8589{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008590 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008591
Bram Moolenaar612cc382018-07-29 15:34:26 +02008592 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008593
8594 if (time_for_testing == 93784)
8595 {
8596 /* Testing the two-character code. */
8597 buf[0] = 'x';
8598 buf[1] = '!';
8599 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008600#ifdef FEAT_TERMINAL
8601 else if (term_use_loop())
8602 buf[0] = 't';
8603#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008604 else if (VIsual_active)
8605 {
8606 if (VIsual_select)
8607 buf[0] = VIsual_mode + 's' - 'v';
8608 else
8609 buf[0] = VIsual_mode;
8610 }
8611 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8612 || State == CONFIRM)
8613 {
8614 buf[0] = 'r';
8615 if (State == ASKMORE)
8616 buf[1] = 'm';
8617 else if (State == CONFIRM)
8618 buf[1] = '?';
8619 }
8620 else if (State == EXTERNCMD)
8621 buf[0] = '!';
8622 else if (State & INSERT)
8623 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008624 if (State & VREPLACE_FLAG)
8625 {
8626 buf[0] = 'R';
8627 buf[1] = 'v';
8628 }
8629 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008630 {
8631 if (State & REPLACE_FLAG)
8632 buf[0] = 'R';
8633 else
8634 buf[0] = 'i';
8635#ifdef FEAT_INS_EXPAND
8636 if (ins_compl_active())
8637 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008638 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008639 buf[1] = 'x';
8640#endif
8641 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008642 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008643 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 {
8645 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008646 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008647 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008648 else if (exmode_active == EXMODE_NORMAL)
8649 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650 }
8651 else
8652 {
8653 buf[0] = 'n';
8654 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008655 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008656 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008657 // to be able to detect force-linewise/blockwise/characterwise operations
8658 buf[2] = motion_force;
8659 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008660 else if (restart_edit == 'I' || restart_edit == 'R'
8661 || restart_edit == 'V')
8662 {
8663 buf[1] = 'i';
8664 buf[2] = restart_edit;
8665 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008666 }
8667
8668 /* Clear out the minor mode when the argument is not a non-zero number or
8669 * non-empty string. */
8670 if (!non_zero_arg(&argvars[0]))
8671 buf[1] = NUL;
8672
8673 rettv->vval.v_string = vim_strsave(buf);
8674 rettv->v_type = VAR_STRING;
8675}
8676
8677#if defined(FEAT_MZSCHEME) || defined(PROTO)
8678/*
8679 * "mzeval()" function
8680 */
8681 static void
8682f_mzeval(typval_T *argvars, typval_T *rettv)
8683{
8684 char_u *str;
8685 char_u buf[NUMBUFLEN];
8686
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008687 if (check_restricted() || check_secure())
8688 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008689 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008690 do_mzeval(str, rettv);
8691}
8692
8693 void
8694mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8695{
8696 typval_T argvars[3];
8697
8698 argvars[0].v_type = VAR_STRING;
8699 argvars[0].vval.v_string = name;
8700 copy_tv(args, &argvars[1]);
8701 argvars[2].v_type = VAR_UNKNOWN;
8702 f_call(argvars, rettv);
8703 clear_tv(&argvars[1]);
8704}
8705#endif
8706
8707/*
8708 * "nextnonblank()" function
8709 */
8710 static void
8711f_nextnonblank(typval_T *argvars, typval_T *rettv)
8712{
8713 linenr_T lnum;
8714
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008715 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008716 {
8717 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8718 {
8719 lnum = 0;
8720 break;
8721 }
8722 if (*skipwhite(ml_get(lnum)) != NUL)
8723 break;
8724 }
8725 rettv->vval.v_number = lnum;
8726}
8727
8728/*
8729 * "nr2char()" function
8730 */
8731 static void
8732f_nr2char(typval_T *argvars, typval_T *rettv)
8733{
8734 char_u buf[NUMBUFLEN];
8735
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008736 if (has_mbyte)
8737 {
8738 int utf8 = 0;
8739
8740 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008741 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008742 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008743 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008744 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008745 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746 }
8747 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008748 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008749 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008750 buf[1] = NUL;
8751 }
8752 rettv->v_type = VAR_STRING;
8753 rettv->vval.v_string = vim_strsave(buf);
8754}
8755
8756/*
8757 * "or(expr, expr)" function
8758 */
8759 static void
8760f_or(typval_T *argvars, typval_T *rettv)
8761{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008762 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8763 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008764}
8765
8766/*
8767 * "pathshorten()" function
8768 */
8769 static void
8770f_pathshorten(typval_T *argvars, typval_T *rettv)
8771{
8772 char_u *p;
8773
8774 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008775 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008776 if (p == NULL)
8777 rettv->vval.v_string = NULL;
8778 else
8779 {
8780 p = vim_strsave(p);
8781 rettv->vval.v_string = p;
8782 if (p != NULL)
8783 shorten_dir(p);
8784 }
8785}
8786
8787#ifdef FEAT_PERL
8788/*
8789 * "perleval()" function
8790 */
8791 static void
8792f_perleval(typval_T *argvars, typval_T *rettv)
8793{
8794 char_u *str;
8795 char_u buf[NUMBUFLEN];
8796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008797 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008798 do_perleval(str, rettv);
8799}
8800#endif
8801
8802#ifdef FEAT_FLOAT
8803/*
8804 * "pow()" function
8805 */
8806 static void
8807f_pow(typval_T *argvars, typval_T *rettv)
8808{
8809 float_T fx = 0.0, fy = 0.0;
8810
8811 rettv->v_type = VAR_FLOAT;
8812 if (get_float_arg(argvars, &fx) == OK
8813 && get_float_arg(&argvars[1], &fy) == OK)
8814 rettv->vval.v_float = pow(fx, fy);
8815 else
8816 rettv->vval.v_float = 0.0;
8817}
8818#endif
8819
8820/*
8821 * "prevnonblank()" function
8822 */
8823 static void
8824f_prevnonblank(typval_T *argvars, typval_T *rettv)
8825{
8826 linenr_T lnum;
8827
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008828 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008829 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8830 lnum = 0;
8831 else
8832 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8833 --lnum;
8834 rettv->vval.v_number = lnum;
8835}
8836
8837/* This dummy va_list is here because:
8838 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8839 * - locally in the function results in a "used before set" warning
8840 * - using va_start() to initialize it gives "function with fixed args" error */
8841static va_list ap;
8842
8843/*
8844 * "printf()" function
8845 */
8846 static void
8847f_printf(typval_T *argvars, typval_T *rettv)
8848{
8849 char_u buf[NUMBUFLEN];
8850 int len;
8851 char_u *s;
8852 int saved_did_emsg = did_emsg;
8853 char *fmt;
8854
8855 rettv->v_type = VAR_STRING;
8856 rettv->vval.v_string = NULL;
8857
8858 /* Get the required length, allocate the buffer and do it for real. */
8859 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008860 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008861 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008862 if (!did_emsg)
8863 {
8864 s = alloc(len + 1);
8865 if (s != NULL)
8866 {
8867 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008868 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8869 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008870 }
8871 }
8872 did_emsg |= saved_did_emsg;
8873}
8874
8875/*
8876 * "pumvisible()" function
8877 */
8878 static void
8879f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8880{
8881#ifdef FEAT_INS_EXPAND
8882 if (pum_visible())
8883 rettv->vval.v_number = 1;
8884#endif
8885}
8886
8887#ifdef FEAT_PYTHON3
8888/*
8889 * "py3eval()" function
8890 */
8891 static void
8892f_py3eval(typval_T *argvars, typval_T *rettv)
8893{
8894 char_u *str;
8895 char_u buf[NUMBUFLEN];
8896
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008897 if (check_restricted() || check_secure())
8898 return;
8899
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008900 if (p_pyx == 0)
8901 p_pyx = 3;
8902
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008903 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008904 do_py3eval(str, rettv);
8905}
8906#endif
8907
8908#ifdef FEAT_PYTHON
8909/*
8910 * "pyeval()" function
8911 */
8912 static void
8913f_pyeval(typval_T *argvars, typval_T *rettv)
8914{
8915 char_u *str;
8916 char_u buf[NUMBUFLEN];
8917
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008918 if (check_restricted() || check_secure())
8919 return;
8920
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008921 if (p_pyx == 0)
8922 p_pyx = 2;
8923
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008924 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008925 do_pyeval(str, rettv);
8926}
8927#endif
8928
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008929#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8930/*
8931 * "pyxeval()" function
8932 */
8933 static void
8934f_pyxeval(typval_T *argvars, typval_T *rettv)
8935{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008936 if (check_restricted() || check_secure())
8937 return;
8938
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008939# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8940 init_pyxversion();
8941 if (p_pyx == 2)
8942 f_pyeval(argvars, rettv);
8943 else
8944 f_py3eval(argvars, rettv);
8945# elif defined(FEAT_PYTHON)
8946 f_pyeval(argvars, rettv);
8947# elif defined(FEAT_PYTHON3)
8948 f_py3eval(argvars, rettv);
8949# endif
8950}
8951#endif
8952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008953/*
8954 * "range()" function
8955 */
8956 static void
8957f_range(typval_T *argvars, typval_T *rettv)
8958{
8959 varnumber_T start;
8960 varnumber_T end;
8961 varnumber_T stride = 1;
8962 varnumber_T i;
8963 int error = FALSE;
8964
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008965 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008966 if (argvars[1].v_type == VAR_UNKNOWN)
8967 {
8968 end = start - 1;
8969 start = 0;
8970 }
8971 else
8972 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008973 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008974 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008975 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008976 }
8977
8978 if (error)
8979 return; /* type error; errmsg already given */
8980 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008981 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008982 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008983 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008984 else
8985 {
8986 if (rettv_list_alloc(rettv) == OK)
8987 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8988 if (list_append_number(rettv->vval.v_list,
8989 (varnumber_T)i) == FAIL)
8990 break;
8991 }
8992}
8993
8994/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008995 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008996 */
8997 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008998readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008999{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02009000 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009001 typval_T save_val;
9002 typval_T rettv;
9003 typval_T argv[2];
9004 int retval = 0;
9005 int error = FALSE;
9006
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02009007 if (expr->v_type == VAR_UNKNOWN)
9008 return 1;
9009
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009010 prepare_vimvar(VV_VAL, &save_val);
9011 set_vim_var_string(VV_VAL, name, -1);
9012 argv[0].v_type = VAR_STRING;
9013 argv[0].vval.v_string = name;
9014
9015 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
9016 goto theend;
9017
9018 retval = tv_get_number_chk(&rettv, &error);
9019 if (error)
9020 retval = -1;
9021 clear_tv(&rettv);
9022
9023theend:
9024 set_vim_var_string(VV_VAL, NULL, 0);
9025 restore_vimvar(VV_VAL, &save_val);
9026 return retval;
9027}
9028
9029/*
9030 * "readdir()" function
9031 */
9032 static void
9033f_readdir(typval_T *argvars, typval_T *rettv)
9034{
9035 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02009036 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009037 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02009038 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009039 garray_T ga;
9040 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009041
9042 if (rettv_list_alloc(rettv) == FAIL)
9043 return;
9044 path = tv_get_string(&argvars[0]);
9045 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009046
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02009047 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
9048 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009049 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009050 for (i = 0; i < ga.ga_len; i++)
9051 {
9052 p = ((char_u **)ga.ga_data)[i];
9053 list_append_string(rettv->vval.v_list, p, -1);
9054 }
9055 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02009056 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02009057}
9058
9059/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009060 * "readfile()" function
9061 */
9062 static void
9063f_readfile(typval_T *argvars, typval_T *rettv)
9064{
9065 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009066 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009067 int failed = FALSE;
9068 char_u *fname;
9069 FILE *fd;
9070 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9071 int io_size = sizeof(buf);
9072 int readlen; /* size of last fread() */
9073 char_u *prev = NULL; /* previously read bytes, if any */
9074 long prevlen = 0; /* length of data in prev */
9075 long prevsize = 0; /* size of prev buffer */
9076 long maxline = MAXLNUM;
9077 long cnt = 0;
9078 char_u *p; /* position in buf */
9079 char_u *start; /* start of current line */
9080
9081 if (argvars[1].v_type != VAR_UNKNOWN)
9082 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009083 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009084 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009085 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9086 blob = TRUE;
9087
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009088 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009089 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009090 }
9091
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009092 if (blob)
9093 {
9094 if (rettv_blob_alloc(rettv) == FAIL)
9095 return;
9096 }
9097 else
9098 {
9099 if (rettv_list_alloc(rettv) == FAIL)
9100 return;
9101 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009102
9103 /* Always open the file in binary mode, library functions have a mind of
9104 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009105 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009106 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9107 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009108 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009109 return;
9110 }
9111
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009112 if (blob)
9113 {
9114 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9115 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009116 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009117 blob_free(rettv->vval.v_blob);
9118 }
9119 fclose(fd);
9120 return;
9121 }
9122
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009123 while (cnt < maxline || maxline < 0)
9124 {
9125 readlen = (int)fread(buf, 1, io_size, fd);
9126
9127 /* This for loop processes what was read, but is also entered at end
9128 * of file so that either:
9129 * - an incomplete line gets written
9130 * - a "binary" file gets an empty line at the end if it ends in a
9131 * newline. */
9132 for (p = buf, start = buf;
9133 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9134 ++p)
9135 {
9136 if (*p == '\n' || readlen <= 0)
9137 {
9138 listitem_T *li;
9139 char_u *s = NULL;
9140 long_u len = p - start;
9141
9142 /* Finished a line. Remove CRs before NL. */
9143 if (readlen > 0 && !binary)
9144 {
9145 while (len > 0 && start[len - 1] == '\r')
9146 --len;
9147 /* removal may cross back to the "prev" string */
9148 if (len == 0)
9149 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9150 --prevlen;
9151 }
9152 if (prevlen == 0)
9153 s = vim_strnsave(start, (int)len);
9154 else
9155 {
9156 /* Change "prev" buffer to be the right size. This way
9157 * the bytes are only copied once, and very long lines are
9158 * allocated only once. */
9159 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9160 {
9161 mch_memmove(s + prevlen, start, len);
9162 s[prevlen + len] = NUL;
9163 prev = NULL; /* the list will own the string */
9164 prevlen = prevsize = 0;
9165 }
9166 }
9167 if (s == NULL)
9168 {
9169 do_outofmem_msg((long_u) prevlen + len + 1);
9170 failed = TRUE;
9171 break;
9172 }
9173
9174 if ((li = listitem_alloc()) == NULL)
9175 {
9176 vim_free(s);
9177 failed = TRUE;
9178 break;
9179 }
9180 li->li_tv.v_type = VAR_STRING;
9181 li->li_tv.v_lock = 0;
9182 li->li_tv.vval.v_string = s;
9183 list_append(rettv->vval.v_list, li);
9184
9185 start = p + 1; /* step over newline */
9186 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9187 break;
9188 }
9189 else if (*p == NUL)
9190 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009191 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9192 * when finding the BF and check the previous two bytes. */
9193 else if (*p == 0xbf && enc_utf8 && !binary)
9194 {
9195 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9196 * + 1, these may be in the "prev" string. */
9197 char_u back1 = p >= buf + 1 ? p[-1]
9198 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9199 char_u back2 = p >= buf + 2 ? p[-2]
9200 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9201 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9202
9203 if (back2 == 0xef && back1 == 0xbb)
9204 {
9205 char_u *dest = p - 2;
9206
9207 /* Usually a BOM is at the beginning of a file, and so at
9208 * the beginning of a line; then we can just step over it.
9209 */
9210 if (start == dest)
9211 start = p + 1;
9212 else
9213 {
9214 /* have to shuffle buf to close gap */
9215 int adjust_prevlen = 0;
9216
9217 if (dest < buf)
9218 {
9219 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9220 dest = buf;
9221 }
9222 if (readlen > p - buf + 1)
9223 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9224 readlen -= 3 - adjust_prevlen;
9225 prevlen -= adjust_prevlen;
9226 p = dest - 1;
9227 }
9228 }
9229 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009230 } /* for */
9231
9232 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9233 break;
9234 if (start < p)
9235 {
9236 /* There's part of a line in buf, store it in "prev". */
9237 if (p - start + prevlen >= prevsize)
9238 {
9239 /* need bigger "prev" buffer */
9240 char_u *newprev;
9241
9242 /* A common use case is ordinary text files and "prev" gets a
9243 * fragment of a line, so the first allocation is made
9244 * small, to avoid repeatedly 'allocing' large and
9245 * 'reallocing' small. */
9246 if (prevsize == 0)
9247 prevsize = (long)(p - start);
9248 else
9249 {
9250 long grow50pc = (prevsize * 3) / 2;
9251 long growmin = (long)((p - start) * 2 + prevlen);
9252 prevsize = grow50pc > growmin ? grow50pc : growmin;
9253 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02009254 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009255 if (newprev == NULL)
9256 {
9257 do_outofmem_msg((long_u)prevsize);
9258 failed = TRUE;
9259 break;
9260 }
9261 prev = newprev;
9262 }
9263 /* Add the line part to end of "prev". */
9264 mch_memmove(prev + prevlen, start, p - start);
9265 prevlen += (long)(p - start);
9266 }
9267 } /* while */
9268
9269 /*
9270 * For a negative line count use only the lines at the end of the file,
9271 * free the rest.
9272 */
9273 if (!failed && maxline < 0)
9274 while (cnt > -maxline)
9275 {
9276 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9277 --cnt;
9278 }
9279
9280 if (failed)
9281 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02009282 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009283 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02009284 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009285 }
9286
9287 vim_free(prev);
9288 fclose(fd);
9289}
9290
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009291 static void
9292return_register(int regname, typval_T *rettv)
9293{
9294 char_u buf[2] = {0, 0};
9295
9296 buf[0] = (char_u)regname;
9297 rettv->v_type = VAR_STRING;
9298 rettv->vval.v_string = vim_strsave(buf);
9299}
9300
9301/*
9302 * "reg_executing()" function
9303 */
9304 static void
9305f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9306{
9307 return_register(reg_executing, rettv);
9308}
9309
9310/*
9311 * "reg_recording()" function
9312 */
9313 static void
9314f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9315{
9316 return_register(reg_recording, rettv);
9317}
9318
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009319#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009320/*
9321 * Convert a List to proftime_T.
9322 * Return FAIL when there is something wrong.
9323 */
9324 static int
9325list2proftime(typval_T *arg, proftime_T *tm)
9326{
9327 long n1, n2;
9328 int error = FALSE;
9329
9330 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9331 || arg->vval.v_list->lv_len != 2)
9332 return FAIL;
9333 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9334 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009335# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336 tm->HighPart = n1;
9337 tm->LowPart = n2;
9338# else
9339 tm->tv_sec = n1;
9340 tm->tv_usec = n2;
9341# endif
9342 return error ? FAIL : OK;
9343}
9344#endif /* FEAT_RELTIME */
9345
9346/*
9347 * "reltime()" function
9348 */
9349 static void
9350f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9351{
9352#ifdef FEAT_RELTIME
9353 proftime_T res;
9354 proftime_T start;
9355
9356 if (argvars[0].v_type == VAR_UNKNOWN)
9357 {
9358 /* No arguments: get current time. */
9359 profile_start(&res);
9360 }
9361 else if (argvars[1].v_type == VAR_UNKNOWN)
9362 {
9363 if (list2proftime(&argvars[0], &res) == FAIL)
9364 return;
9365 profile_end(&res);
9366 }
9367 else
9368 {
9369 /* Two arguments: compute the difference. */
9370 if (list2proftime(&argvars[0], &start) == FAIL
9371 || list2proftime(&argvars[1], &res) == FAIL)
9372 return;
9373 profile_sub(&res, &start);
9374 }
9375
9376 if (rettv_list_alloc(rettv) == OK)
9377 {
9378 long n1, n2;
9379
Bram Moolenaar4f974752019-02-17 17:44:42 +01009380# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009381 n1 = res.HighPart;
9382 n2 = res.LowPart;
9383# else
9384 n1 = res.tv_sec;
9385 n2 = res.tv_usec;
9386# endif
9387 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9388 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9389 }
9390#endif
9391}
9392
9393#ifdef FEAT_FLOAT
9394/*
9395 * "reltimefloat()" function
9396 */
9397 static void
9398f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9399{
9400# ifdef FEAT_RELTIME
9401 proftime_T tm;
9402# endif
9403
9404 rettv->v_type = VAR_FLOAT;
9405 rettv->vval.v_float = 0;
9406# ifdef FEAT_RELTIME
9407 if (list2proftime(&argvars[0], &tm) == OK)
9408 rettv->vval.v_float = profile_float(&tm);
9409# endif
9410}
9411#endif
9412
9413/*
9414 * "reltimestr()" function
9415 */
9416 static void
9417f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9418{
9419#ifdef FEAT_RELTIME
9420 proftime_T tm;
9421#endif
9422
9423 rettv->v_type = VAR_STRING;
9424 rettv->vval.v_string = NULL;
9425#ifdef FEAT_RELTIME
9426 if (list2proftime(&argvars[0], &tm) == OK)
9427 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9428#endif
9429}
9430
9431#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009432 static void
9433make_connection(void)
9434{
9435 if (X_DISPLAY == NULL
9436# ifdef FEAT_GUI
9437 && !gui.in_use
9438# endif
9439 )
9440 {
9441 x_force_connect = TRUE;
9442 setup_term_clip();
9443 x_force_connect = FALSE;
9444 }
9445}
9446
9447 static int
9448check_connection(void)
9449{
9450 make_connection();
9451 if (X_DISPLAY == NULL)
9452 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009453 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009454 return FAIL;
9455 }
9456 return OK;
9457}
9458#endif
9459
9460#ifdef FEAT_CLIENTSERVER
9461 static void
9462remote_common(typval_T *argvars, typval_T *rettv, int expr)
9463{
9464 char_u *server_name;
9465 char_u *keys;
9466 char_u *r = NULL;
9467 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009468 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009469# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009470 HWND w;
9471# else
9472 Window w;
9473# endif
9474
9475 if (check_restricted() || check_secure())
9476 return;
9477
9478# ifdef FEAT_X11
9479 if (check_connection() == FAIL)
9480 return;
9481# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009482 if (argvars[2].v_type != VAR_UNKNOWN
9483 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009484 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009485
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009486 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 if (server_name == NULL)
9488 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009489 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009490# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009491 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009493 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9494 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009495# endif
9496 {
9497 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009498 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009499 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009500 vim_free(r);
9501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009502 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009503 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009504 return;
9505 }
9506
9507 rettv->vval.v_string = r;
9508
9509 if (argvars[2].v_type != VAR_UNKNOWN)
9510 {
9511 dictitem_T v;
9512 char_u str[30];
9513 char_u *idvar;
9514
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009515 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009516 if (idvar != NULL && *idvar != NUL)
9517 {
9518 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9519 v.di_tv.v_type = VAR_STRING;
9520 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009521 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009522 vim_free(v.di_tv.vval.v_string);
9523 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009524 }
9525}
9526#endif
9527
9528/*
9529 * "remote_expr()" function
9530 */
9531 static void
9532f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9533{
9534 rettv->v_type = VAR_STRING;
9535 rettv->vval.v_string = NULL;
9536#ifdef FEAT_CLIENTSERVER
9537 remote_common(argvars, rettv, TRUE);
9538#endif
9539}
9540
9541/*
9542 * "remote_foreground()" function
9543 */
9544 static void
9545f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9546{
9547#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009548# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009549 /* On Win32 it's done in this application. */
9550 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009551 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009552
9553 if (server_name != NULL)
9554 serverForeground(server_name);
9555 }
9556# else
9557 /* Send a foreground() expression to the server. */
9558 argvars[1].v_type = VAR_STRING;
9559 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9560 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009561 rettv->v_type = VAR_STRING;
9562 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009563 remote_common(argvars, rettv, TRUE);
9564 vim_free(argvars[1].vval.v_string);
9565# endif
9566#endif
9567}
9568
9569 static void
9570f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9571{
9572#ifdef FEAT_CLIENTSERVER
9573 dictitem_T v;
9574 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009575# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009576 long_u n = 0;
9577# endif
9578 char_u *serverid;
9579
9580 if (check_restricted() || check_secure())
9581 {
9582 rettv->vval.v_number = -1;
9583 return;
9584 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009585 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009586 if (serverid == NULL)
9587 {
9588 rettv->vval.v_number = -1;
9589 return; /* type error; errmsg already given */
9590 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009591# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009592 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9593 if (n == 0)
9594 rettv->vval.v_number = -1;
9595 else
9596 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009597 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009598 rettv->vval.v_number = (s != NULL);
9599 }
9600# else
9601 if (check_connection() == FAIL)
9602 return;
9603
9604 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9605 serverStrToWin(serverid), &s);
9606# endif
9607
9608 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9609 {
9610 char_u *retvar;
9611
9612 v.di_tv.v_type = VAR_STRING;
9613 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009614 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009615 if (retvar != NULL)
9616 set_var(retvar, &v.di_tv, FALSE);
9617 vim_free(v.di_tv.vval.v_string);
9618 }
9619#else
9620 rettv->vval.v_number = -1;
9621#endif
9622}
9623
9624 static void
9625f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9626{
9627 char_u *r = NULL;
9628
9629#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009630 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009631
9632 if (serverid != NULL && !check_restricted() && !check_secure())
9633 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009634 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009635# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009636 /* The server's HWND is encoded in the 'id' parameter */
9637 long_u n = 0;
9638# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009639
9640 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009641 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009642
Bram Moolenaar4f974752019-02-17 17:44:42 +01009643# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009644 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9645 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009646 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009647 if (r == NULL)
9648# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009649 if (check_connection() == FAIL
9650 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9651 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009652# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009653 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009654 }
9655#endif
9656 rettv->v_type = VAR_STRING;
9657 rettv->vval.v_string = r;
9658}
9659
9660/*
9661 * "remote_send()" function
9662 */
9663 static void
9664f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9665{
9666 rettv->v_type = VAR_STRING;
9667 rettv->vval.v_string = NULL;
9668#ifdef FEAT_CLIENTSERVER
9669 remote_common(argvars, rettv, FALSE);
9670#endif
9671}
9672
9673/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009674 * "remote_startserver()" function
9675 */
9676 static void
9677f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9678{
9679#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009680 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009681
9682 if (server == NULL)
9683 return; /* type error; errmsg already given */
9684 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009685 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009686 else
9687 {
9688# ifdef FEAT_X11
9689 if (check_connection() == OK)
9690 serverRegisterName(X_DISPLAY, server);
9691# else
9692 serverSetName(server);
9693# endif
9694 }
9695#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009696 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009697#endif
9698}
9699
9700/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009701 * "remove()" function
9702 */
9703 static void
9704f_remove(typval_T *argvars, typval_T *rettv)
9705{
9706 list_T *l;
9707 listitem_T *item, *item2;
9708 listitem_T *li;
9709 long idx;
9710 long end;
9711 char_u *key;
9712 dict_T *d;
9713 dictitem_T *di;
9714 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009715 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009716
9717 if (argvars[0].v_type == VAR_DICT)
9718 {
9719 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009720 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009721 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009722 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009724 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009725 if (key != NULL)
9726 {
9727 di = dict_find(d, key, -1);
9728 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009729 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009730 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9731 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9732 {
9733 *rettv = di->di_tv;
9734 init_tv(&di->di_tv);
9735 dictitem_remove(d, di);
9736 }
9737 }
9738 }
9739 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009740 else if (argvars[0].v_type == VAR_BLOB)
9741 {
9742 idx = (long)tv_get_number_chk(&argvars[1], &error);
9743 if (!error)
9744 {
9745 blob_T *b = argvars[0].vval.v_blob;
9746 int len = blob_len(b);
9747 char_u *p;
9748
9749 if (idx < 0)
9750 // count from the end
9751 idx = len + idx;
9752 if (idx < 0 || idx >= len)
9753 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009754 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009755 return;
9756 }
9757 if (argvars[2].v_type == VAR_UNKNOWN)
9758 {
9759 // Remove one item, return its value.
9760 p = (char_u *)b->bv_ga.ga_data;
9761 rettv->vval.v_number = (varnumber_T) *(p + idx);
9762 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9763 --b->bv_ga.ga_len;
9764 }
9765 else
9766 {
9767 blob_T *blob;
9768
9769 // Remove range of items, return list with values.
9770 end = (long)tv_get_number_chk(&argvars[2], &error);
9771 if (error)
9772 return;
9773 if (end < 0)
9774 // count from the end
9775 end = len + end;
9776 if (end >= len || idx > end)
9777 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009778 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009779 return;
9780 }
9781 blob = blob_alloc();
9782 if (blob == NULL)
9783 return;
9784 blob->bv_ga.ga_len = end - idx + 1;
9785 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9786 {
9787 vim_free(blob);
9788 return;
9789 }
9790 p = (char_u *)b->bv_ga.ga_data;
9791 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9792 (size_t)(end - idx + 1));
9793 ++blob->bv_refcount;
9794 rettv->v_type = VAR_BLOB;
9795 rettv->vval.v_blob = blob;
9796
9797 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9798 b->bv_ga.ga_len -= end - idx + 1;
9799 }
9800 }
9801 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009802 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009803 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009804 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009805 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009806 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009807 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009808 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009809 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009810 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009811 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009812 else
9813 {
9814 if (argvars[2].v_type == VAR_UNKNOWN)
9815 {
9816 /* Remove one item, return its value. */
9817 vimlist_remove(l, item, item);
9818 *rettv = item->li_tv;
9819 vim_free(item);
9820 }
9821 else
9822 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009823 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009824 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009826 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009827 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009828 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009829 else
9830 {
9831 int cnt = 0;
9832
9833 for (li = item; li != NULL; li = li->li_next)
9834 {
9835 ++cnt;
9836 if (li == item2)
9837 break;
9838 }
9839 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009840 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 else
9842 {
9843 vimlist_remove(l, item, item2);
9844 if (rettv_list_alloc(rettv) == OK)
9845 {
9846 l = rettv->vval.v_list;
9847 l->lv_first = item;
9848 l->lv_last = item2;
9849 item->li_prev = NULL;
9850 item2->li_next = NULL;
9851 l->lv_len = cnt;
9852 }
9853 }
9854 }
9855 }
9856 }
9857 }
9858}
9859
9860/*
9861 * "rename({from}, {to})" function
9862 */
9863 static void
9864f_rename(typval_T *argvars, typval_T *rettv)
9865{
9866 char_u buf[NUMBUFLEN];
9867
9868 if (check_restricted() || check_secure())
9869 rettv->vval.v_number = -1;
9870 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009871 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9872 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009873}
9874
9875/*
9876 * "repeat()" function
9877 */
9878 static void
9879f_repeat(typval_T *argvars, typval_T *rettv)
9880{
9881 char_u *p;
9882 int n;
9883 int slen;
9884 int len;
9885 char_u *r;
9886 int i;
9887
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009888 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009889 if (argvars[0].v_type == VAR_LIST)
9890 {
9891 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9892 while (n-- > 0)
9893 if (list_extend(rettv->vval.v_list,
9894 argvars[0].vval.v_list, NULL) == FAIL)
9895 break;
9896 }
9897 else
9898 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009899 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009900 rettv->v_type = VAR_STRING;
9901 rettv->vval.v_string = NULL;
9902
9903 slen = (int)STRLEN(p);
9904 len = slen * n;
9905 if (len <= 0)
9906 return;
9907
9908 r = alloc(len + 1);
9909 if (r != NULL)
9910 {
9911 for (i = 0; i < n; i++)
9912 mch_memmove(r + i * slen, p, (size_t)slen);
9913 r[len] = NUL;
9914 }
9915
9916 rettv->vval.v_string = r;
9917 }
9918}
9919
9920/*
9921 * "resolve()" function
9922 */
9923 static void
9924f_resolve(typval_T *argvars, typval_T *rettv)
9925{
9926 char_u *p;
9927#ifdef HAVE_READLINK
9928 char_u *buf = NULL;
9929#endif
9930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009931 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009932#ifdef FEAT_SHORTCUT
9933 {
9934 char_u *v = NULL;
9935
Bram Moolenaardce1e892019-02-10 23:18:53 +01009936 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009937 if (v != NULL)
9938 rettv->vval.v_string = v;
9939 else
9940 rettv->vval.v_string = vim_strsave(p);
9941 }
9942#else
9943# ifdef HAVE_READLINK
9944 {
9945 char_u *cpy;
9946 int len;
9947 char_u *remain = NULL;
9948 char_u *q;
9949 int is_relative_to_current = FALSE;
9950 int has_trailing_pathsep = FALSE;
9951 int limit = 100;
9952
9953 p = vim_strsave(p);
9954
9955 if (p[0] == '.' && (vim_ispathsep(p[1])
9956 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9957 is_relative_to_current = TRUE;
9958
9959 len = STRLEN(p);
9960 if (len > 0 && after_pathsep(p, p + len))
9961 {
9962 has_trailing_pathsep = TRUE;
9963 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9964 }
9965
9966 q = getnextcomp(p);
9967 if (*q != NUL)
9968 {
9969 /* Separate the first path component in "p", and keep the
9970 * remainder (beginning with the path separator). */
9971 remain = vim_strsave(q - 1);
9972 q[-1] = NUL;
9973 }
9974
9975 buf = alloc(MAXPATHL + 1);
9976 if (buf == NULL)
9977 goto fail;
9978
9979 for (;;)
9980 {
9981 for (;;)
9982 {
9983 len = readlink((char *)p, (char *)buf, MAXPATHL);
9984 if (len <= 0)
9985 break;
9986 buf[len] = NUL;
9987
9988 if (limit-- == 0)
9989 {
9990 vim_free(p);
9991 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009992 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009993 rettv->vval.v_string = NULL;
9994 goto fail;
9995 }
9996
9997 /* Ensure that the result will have a trailing path separator
9998 * if the argument has one. */
9999 if (remain == NULL && has_trailing_pathsep)
10000 add_pathsep(buf);
10001
10002 /* Separate the first path component in the link value and
10003 * concatenate the remainders. */
10004 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10005 if (*q != NUL)
10006 {
10007 if (remain == NULL)
10008 remain = vim_strsave(q - 1);
10009 else
10010 {
10011 cpy = concat_str(q - 1, remain);
10012 if (cpy != NULL)
10013 {
10014 vim_free(remain);
10015 remain = cpy;
10016 }
10017 }
10018 q[-1] = NUL;
10019 }
10020
10021 q = gettail(p);
10022 if (q > p && *q == NUL)
10023 {
10024 /* Ignore trailing path separator. */
10025 q[-1] = NUL;
10026 q = gettail(p);
10027 }
10028 if (q > p && !mch_isFullName(buf))
10029 {
10030 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +020010031 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010032 if (cpy != NULL)
10033 {
10034 STRCPY(cpy, p);
10035 STRCPY(gettail(cpy), buf);
10036 vim_free(p);
10037 p = cpy;
10038 }
10039 }
10040 else
10041 {
10042 vim_free(p);
10043 p = vim_strsave(buf);
10044 }
10045 }
10046
10047 if (remain == NULL)
10048 break;
10049
10050 /* Append the first path component of "remain" to "p". */
10051 q = getnextcomp(remain + 1);
10052 len = q - remain - (*q != NUL);
10053 cpy = vim_strnsave(p, STRLEN(p) + len);
10054 if (cpy != NULL)
10055 {
10056 STRNCAT(cpy, remain, len);
10057 vim_free(p);
10058 p = cpy;
10059 }
10060 /* Shorten "remain". */
10061 if (*q != NUL)
10062 STRMOVE(remain, q - 1);
10063 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010064 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010065 }
10066
10067 /* If the result is a relative path name, make it explicitly relative to
10068 * the current directory if and only if the argument had this form. */
10069 if (!vim_ispathsep(*p))
10070 {
10071 if (is_relative_to_current
10072 && *p != NUL
10073 && !(p[0] == '.'
10074 && (p[1] == NUL
10075 || vim_ispathsep(p[1])
10076 || (p[1] == '.'
10077 && (p[2] == NUL
10078 || vim_ispathsep(p[2]))))))
10079 {
10080 /* Prepend "./". */
10081 cpy = concat_str((char_u *)"./", p);
10082 if (cpy != NULL)
10083 {
10084 vim_free(p);
10085 p = cpy;
10086 }
10087 }
10088 else if (!is_relative_to_current)
10089 {
10090 /* Strip leading "./". */
10091 q = p;
10092 while (q[0] == '.' && vim_ispathsep(q[1]))
10093 q += 2;
10094 if (q > p)
10095 STRMOVE(p, p + 2);
10096 }
10097 }
10098
10099 /* Ensure that the result will have no trailing path separator
10100 * if the argument had none. But keep "/" or "//". */
10101 if (!has_trailing_pathsep)
10102 {
10103 q = p + STRLEN(p);
10104 if (after_pathsep(p, q))
10105 *gettail_sep(p) = NUL;
10106 }
10107
10108 rettv->vval.v_string = p;
10109 }
10110# else
10111 rettv->vval.v_string = vim_strsave(p);
10112# endif
10113#endif
10114
10115 simplify_filename(rettv->vval.v_string);
10116
10117#ifdef HAVE_READLINK
10118fail:
10119 vim_free(buf);
10120#endif
10121 rettv->v_type = VAR_STRING;
10122}
10123
10124/*
10125 * "reverse({list})" function
10126 */
10127 static void
10128f_reverse(typval_T *argvars, typval_T *rettv)
10129{
10130 list_T *l;
10131 listitem_T *li, *ni;
10132
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010133 if (argvars[0].v_type == VAR_BLOB)
10134 {
10135 blob_T *b = argvars[0].vval.v_blob;
10136 int i, len = blob_len(b);
10137
10138 for (i = 0; i < len / 2; i++)
10139 {
10140 int tmp = blob_get(b, i);
10141
10142 blob_set(b, i, blob_get(b, len - i - 1));
10143 blob_set(b, len - i - 1, tmp);
10144 }
10145 rettv_blob_set(rettv, b);
10146 return;
10147 }
10148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010149 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010150 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010151 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010152 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010153 (char_u *)N_("reverse() argument"), TRUE))
10154 {
10155 li = l->lv_last;
10156 l->lv_first = l->lv_last = NULL;
10157 l->lv_len = 0;
10158 while (li != NULL)
10159 {
10160 ni = li->li_prev;
10161 list_append(l, li);
10162 li = ni;
10163 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010164 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010165 l->lv_idx = l->lv_len - l->lv_idx - 1;
10166 }
10167}
10168
10169#define SP_NOMOVE 0x01 /* don't move cursor */
10170#define SP_REPEAT 0x02 /* repeat to find outer pair */
10171#define SP_RETCOUNT 0x04 /* return matchcount */
10172#define SP_SETPCMARK 0x08 /* set previous context mark */
10173#define SP_START 0x10 /* accept match at start position */
10174#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10175#define SP_END 0x40 /* leave cursor at end of match */
10176#define SP_COLUMN 0x80 /* start at cursor column */
10177
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010178/*
10179 * Get flags for a search function.
10180 * Possibly sets "p_ws".
10181 * Returns BACKWARD, FORWARD or zero (for an error).
10182 */
10183 static int
10184get_search_arg(typval_T *varp, int *flagsp)
10185{
10186 int dir = FORWARD;
10187 char_u *flags;
10188 char_u nbuf[NUMBUFLEN];
10189 int mask;
10190
10191 if (varp->v_type != VAR_UNKNOWN)
10192 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010193 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010194 if (flags == NULL)
10195 return 0; /* type error; errmsg already given */
10196 while (*flags != NUL)
10197 {
10198 switch (*flags)
10199 {
10200 case 'b': dir = BACKWARD; break;
10201 case 'w': p_ws = TRUE; break;
10202 case 'W': p_ws = FALSE; break;
10203 default: mask = 0;
10204 if (flagsp != NULL)
10205 switch (*flags)
10206 {
10207 case 'c': mask = SP_START; break;
10208 case 'e': mask = SP_END; break;
10209 case 'm': mask = SP_RETCOUNT; break;
10210 case 'n': mask = SP_NOMOVE; break;
10211 case 'p': mask = SP_SUBPAT; break;
10212 case 'r': mask = SP_REPEAT; break;
10213 case 's': mask = SP_SETPCMARK; break;
10214 case 'z': mask = SP_COLUMN; break;
10215 }
10216 if (mask == 0)
10217 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010218 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010219 dir = 0;
10220 }
10221 else
10222 *flagsp |= mask;
10223 }
10224 if (dir == 0)
10225 break;
10226 ++flags;
10227 }
10228 }
10229 return dir;
10230}
10231
10232/*
10233 * Shared by search() and searchpos() functions.
10234 */
10235 static int
10236search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10237{
10238 int flags;
10239 char_u *pat;
10240 pos_T pos;
10241 pos_T save_cursor;
10242 int save_p_ws = p_ws;
10243 int dir;
10244 int retval = 0; /* default: FAIL */
10245 long lnum_stop = 0;
10246 proftime_T tm;
10247#ifdef FEAT_RELTIME
10248 long time_limit = 0;
10249#endif
10250 int options = SEARCH_KEEP;
10251 int subpatnum;
10252
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010253 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010254 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10255 if (dir == 0)
10256 goto theend;
10257 flags = *flagsp;
10258 if (flags & SP_START)
10259 options |= SEARCH_START;
10260 if (flags & SP_END)
10261 options |= SEARCH_END;
10262 if (flags & SP_COLUMN)
10263 options |= SEARCH_COL;
10264
10265 /* Optional arguments: line number to stop searching and timeout. */
10266 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10267 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010268 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010269 if (lnum_stop < 0)
10270 goto theend;
10271#ifdef FEAT_RELTIME
10272 if (argvars[3].v_type != VAR_UNKNOWN)
10273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010274 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 if (time_limit < 0)
10276 goto theend;
10277 }
10278#endif
10279 }
10280
10281#ifdef FEAT_RELTIME
10282 /* Set the time limit, if there is one. */
10283 profile_setlimit(time_limit, &tm);
10284#endif
10285
10286 /*
10287 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10288 * Check to make sure only those flags are set.
10289 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10290 * flags cannot be set. Check for that condition also.
10291 */
10292 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10293 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10294 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010295 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 goto theend;
10297 }
10298
10299 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010300 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010301 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010302 if (subpatnum != FAIL)
10303 {
10304 if (flags & SP_SUBPAT)
10305 retval = subpatnum;
10306 else
10307 retval = pos.lnum;
10308 if (flags & SP_SETPCMARK)
10309 setpcmark();
10310 curwin->w_cursor = pos;
10311 if (match_pos != NULL)
10312 {
10313 /* Store the match cursor position */
10314 match_pos->lnum = pos.lnum;
10315 match_pos->col = pos.col + 1;
10316 }
10317 /* "/$" will put the cursor after the end of the line, may need to
10318 * correct that here */
10319 check_cursor();
10320 }
10321
10322 /* If 'n' flag is used: restore cursor position. */
10323 if (flags & SP_NOMOVE)
10324 curwin->w_cursor = save_cursor;
10325 else
10326 curwin->w_set_curswant = TRUE;
10327theend:
10328 p_ws = save_p_ws;
10329
10330 return retval;
10331}
10332
10333#ifdef FEAT_FLOAT
10334
10335/*
10336 * round() is not in C90, use ceil() or floor() instead.
10337 */
10338 float_T
10339vim_round(float_T f)
10340{
10341 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10342}
10343
10344/*
10345 * "round({float})" function
10346 */
10347 static void
10348f_round(typval_T *argvars, typval_T *rettv)
10349{
10350 float_T f = 0.0;
10351
10352 rettv->v_type = VAR_FLOAT;
10353 if (get_float_arg(argvars, &f) == OK)
10354 rettv->vval.v_float = vim_round(f);
10355 else
10356 rettv->vval.v_float = 0.0;
10357}
10358#endif
10359
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010360#ifdef FEAT_RUBY
10361/*
10362 * "rubyeval()" function
10363 */
10364 static void
10365f_rubyeval(typval_T *argvars, typval_T *rettv)
10366{
10367 char_u *str;
10368 char_u buf[NUMBUFLEN];
10369
10370 str = tv_get_string_buf(&argvars[0], buf);
10371 do_rubyeval(str, rettv);
10372}
10373#endif
10374
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010375/*
10376 * "screenattr()" function
10377 */
10378 static void
10379f_screenattr(typval_T *argvars, typval_T *rettv)
10380{
10381 int row;
10382 int col;
10383 int c;
10384
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010385 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10386 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010387 if (row < 0 || row >= screen_Rows
10388 || col < 0 || col >= screen_Columns)
10389 c = -1;
10390 else
10391 c = ScreenAttrs[LineOffset[row] + col];
10392 rettv->vval.v_number = c;
10393}
10394
10395/*
10396 * "screenchar()" function
10397 */
10398 static void
10399f_screenchar(typval_T *argvars, typval_T *rettv)
10400{
10401 int row;
10402 int col;
10403 int off;
10404 int c;
10405
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010406 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10407 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010408 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010409 c = -1;
10410 else
10411 {
10412 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010413 if (enc_utf8 && ScreenLinesUC[off] != 0)
10414 c = ScreenLinesUC[off];
10415 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010416 c = ScreenLines[off];
10417 }
10418 rettv->vval.v_number = c;
10419}
10420
10421/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010422 * "screenchars()" function
10423 */
10424 static void
10425f_screenchars(typval_T *argvars, typval_T *rettv)
10426{
10427 int row;
10428 int col;
10429 int off;
10430 int c;
10431 int i;
10432
10433 if (rettv_list_alloc(rettv) == FAIL)
10434 return;
10435 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10436 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10437 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10438 return;
10439
10440 off = LineOffset[row] + col;
10441 if (enc_utf8 && ScreenLinesUC[off] != 0)
10442 c = ScreenLinesUC[off];
10443 else
10444 c = ScreenLines[off];
10445 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10446
10447 if (enc_utf8)
10448
10449 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10450 list_append_number(rettv->vval.v_list,
10451 (varnumber_T)ScreenLinesC[i][off]);
10452}
10453
10454/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010455 * "screencol()" function
10456 *
10457 * First column is 1 to be consistent with virtcol().
10458 */
10459 static void
10460f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10461{
10462 rettv->vval.v_number = screen_screencol() + 1;
10463}
10464
10465/*
10466 * "screenrow()" function
10467 */
10468 static void
10469f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10470{
10471 rettv->vval.v_number = screen_screenrow() + 1;
10472}
10473
10474/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010475 * "screenstring()" function
10476 */
10477 static void
10478f_screenstring(typval_T *argvars, typval_T *rettv)
10479{
10480 int row;
10481 int col;
10482 int off;
10483 int c;
10484 int i;
10485 char_u buf[MB_MAXBYTES + 1];
10486 int buflen = 0;
10487
10488 rettv->vval.v_string = NULL;
10489 rettv->v_type = VAR_STRING;
10490
10491 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10492 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10493 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10494 return;
10495
10496 off = LineOffset[row] + col;
10497 if (enc_utf8 && ScreenLinesUC[off] != 0)
10498 c = ScreenLinesUC[off];
10499 else
10500 c = ScreenLines[off];
10501 buflen += mb_char2bytes(c, buf);
10502
10503 if (enc_utf8)
10504 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10505 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10506
10507 buf[buflen] = NUL;
10508 rettv->vval.v_string = vim_strsave(buf);
10509}
10510
10511/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010512 * "search()" function
10513 */
10514 static void
10515f_search(typval_T *argvars, typval_T *rettv)
10516{
10517 int flags = 0;
10518
10519 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10520}
10521
10522/*
10523 * "searchdecl()" function
10524 */
10525 static void
10526f_searchdecl(typval_T *argvars, typval_T *rettv)
10527{
10528 int locally = 1;
10529 int thisblock = 0;
10530 int error = FALSE;
10531 char_u *name;
10532
10533 rettv->vval.v_number = 1; /* default: FAIL */
10534
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010535 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010536 if (argvars[1].v_type != VAR_UNKNOWN)
10537 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010538 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010539 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010540 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010541 }
10542 if (!error && name != NULL)
10543 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10544 locally, thisblock, SEARCH_KEEP) == FAIL;
10545}
10546
10547/*
10548 * Used by searchpair() and searchpairpos()
10549 */
10550 static int
10551searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10552{
10553 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010554 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010555 int save_p_ws = p_ws;
10556 int dir;
10557 int flags = 0;
10558 char_u nbuf1[NUMBUFLEN];
10559 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010560 int retval = 0; /* default: FAIL */
10561 long lnum_stop = 0;
10562 long time_limit = 0;
10563
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010564 /* Get the three pattern arguments: start, middle, end. Will result in an
10565 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010566 spat = tv_get_string_chk(&argvars[0]);
10567 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10568 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010569 if (spat == NULL || mpat == NULL || epat == NULL)
10570 goto theend; /* type error */
10571
10572 /* Handle the optional fourth argument: flags */
10573 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10574 if (dir == 0)
10575 goto theend;
10576
10577 /* Don't accept SP_END or SP_SUBPAT.
10578 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10579 */
10580 if ((flags & (SP_END | SP_SUBPAT)) != 0
10581 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10582 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010583 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010584 goto theend;
10585 }
10586
10587 /* Using 'r' implies 'W', otherwise it doesn't work. */
10588 if (flags & SP_REPEAT)
10589 p_ws = FALSE;
10590
10591 /* Optional fifth argument: skip expression */
10592 if (argvars[3].v_type == VAR_UNKNOWN
10593 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010594 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010595 else
10596 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010597 skip = &argvars[4];
10598 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10599 && skip->v_type != VAR_STRING)
10600 {
10601 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010602 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010603 goto theend;
10604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010605 if (argvars[5].v_type != VAR_UNKNOWN)
10606 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010607 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010608 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010609 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010610 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010611 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010612 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010613#ifdef FEAT_RELTIME
10614 if (argvars[6].v_type != VAR_UNKNOWN)
10615 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010616 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010617 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010618 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010619 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010620 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010621 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010622 }
10623#endif
10624 }
10625 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010626
10627 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10628 match_pos, lnum_stop, time_limit);
10629
10630theend:
10631 p_ws = save_p_ws;
10632
10633 return retval;
10634}
10635
10636/*
10637 * "searchpair()" function
10638 */
10639 static void
10640f_searchpair(typval_T *argvars, typval_T *rettv)
10641{
10642 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10643}
10644
10645/*
10646 * "searchpairpos()" function
10647 */
10648 static void
10649f_searchpairpos(typval_T *argvars, typval_T *rettv)
10650{
10651 pos_T match_pos;
10652 int lnum = 0;
10653 int col = 0;
10654
10655 if (rettv_list_alloc(rettv) == FAIL)
10656 return;
10657
10658 if (searchpair_cmn(argvars, &match_pos) > 0)
10659 {
10660 lnum = match_pos.lnum;
10661 col = match_pos.col;
10662 }
10663
10664 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10665 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10666}
10667
10668/*
10669 * Search for a start/middle/end thing.
10670 * Used by searchpair(), see its documentation for the details.
10671 * Returns 0 or -1 for no match,
10672 */
10673 long
10674do_searchpair(
10675 char_u *spat, /* start pattern */
10676 char_u *mpat, /* middle pattern */
10677 char_u *epat, /* end pattern */
10678 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010679 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010680 int flags, /* SP_SETPCMARK and other SP_ values */
10681 pos_T *match_pos,
10682 linenr_T lnum_stop, /* stop at this line if not zero */
10683 long time_limit UNUSED) /* stop after this many msec */
10684{
10685 char_u *save_cpo;
10686 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10687 long retval = 0;
10688 pos_T pos;
10689 pos_T firstpos;
10690 pos_T foundpos;
10691 pos_T save_cursor;
10692 pos_T save_pos;
10693 int n;
10694 int r;
10695 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010696 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010697 int err;
10698 int options = SEARCH_KEEP;
10699 proftime_T tm;
10700
10701 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10702 save_cpo = p_cpo;
10703 p_cpo = empty_option;
10704
10705#ifdef FEAT_RELTIME
10706 /* Set the time limit, if there is one. */
10707 profile_setlimit(time_limit, &tm);
10708#endif
10709
10710 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10711 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +020010712 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
10713 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010714 if (pat2 == NULL || pat3 == NULL)
10715 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010716 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010717 if (*mpat == NUL)
10718 STRCPY(pat3, pat2);
10719 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010720 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010721 spat, epat, mpat);
10722 if (flags & SP_START)
10723 options |= SEARCH_START;
10724
Bram Moolenaar48570482017-10-30 21:48:41 +010010725 if (skip != NULL)
10726 {
10727 /* Empty string means to not use the skip expression. */
10728 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10729 use_skip = skip->vval.v_string != NULL
10730 && *skip->vval.v_string != NUL;
10731 }
10732
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010733 save_cursor = curwin->w_cursor;
10734 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010735 CLEAR_POS(&firstpos);
10736 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010737 pat = pat3;
10738 for (;;)
10739 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010740 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010741 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010742 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010743 /* didn't find it or found the first match again: FAIL */
10744 break;
10745
10746 if (firstpos.lnum == 0)
10747 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010748 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010749 {
10750 /* Found the same position again. Can happen with a pattern that
10751 * has "\zs" at the end and searching backwards. Advance one
10752 * character and try again. */
10753 if (dir == BACKWARD)
10754 decl(&pos);
10755 else
10756 incl(&pos);
10757 }
10758 foundpos = pos;
10759
10760 /* clear the start flag to avoid getting stuck here */
10761 options &= ~SEARCH_START;
10762
10763 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010764 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010765 {
10766 save_pos = curwin->w_cursor;
10767 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010768 err = FALSE;
10769 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010770 curwin->w_cursor = save_pos;
10771 if (err)
10772 {
10773 /* Evaluating {skip} caused an error, break here. */
10774 curwin->w_cursor = save_cursor;
10775 retval = -1;
10776 break;
10777 }
10778 if (r)
10779 continue;
10780 }
10781
10782 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10783 {
10784 /* Found end when searching backwards or start when searching
10785 * forward: nested pair. */
10786 ++nest;
10787 pat = pat2; /* nested, don't search for middle */
10788 }
10789 else
10790 {
10791 /* Found end when searching forward or start when searching
10792 * backward: end of (nested) pair; or found middle in outer pair. */
10793 if (--nest == 1)
10794 pat = pat3; /* outer level, search for middle */
10795 }
10796
10797 if (nest == 0)
10798 {
10799 /* Found the match: return matchcount or line number. */
10800 if (flags & SP_RETCOUNT)
10801 ++retval;
10802 else
10803 retval = pos.lnum;
10804 if (flags & SP_SETPCMARK)
10805 setpcmark();
10806 curwin->w_cursor = pos;
10807 if (!(flags & SP_REPEAT))
10808 break;
10809 nest = 1; /* search for next unmatched */
10810 }
10811 }
10812
10813 if (match_pos != NULL)
10814 {
10815 /* Store the match cursor position */
10816 match_pos->lnum = curwin->w_cursor.lnum;
10817 match_pos->col = curwin->w_cursor.col + 1;
10818 }
10819
10820 /* If 'n' flag is used or search failed: restore cursor position. */
10821 if ((flags & SP_NOMOVE) || retval == 0)
10822 curwin->w_cursor = save_cursor;
10823
10824theend:
10825 vim_free(pat2);
10826 vim_free(pat3);
10827 if (p_cpo == empty_option)
10828 p_cpo = save_cpo;
10829 else
10830 /* Darn, evaluating the {skip} expression changed the value. */
10831 free_string_option(save_cpo);
10832
10833 return retval;
10834}
10835
10836/*
10837 * "searchpos()" function
10838 */
10839 static void
10840f_searchpos(typval_T *argvars, typval_T *rettv)
10841{
10842 pos_T match_pos;
10843 int lnum = 0;
10844 int col = 0;
10845 int n;
10846 int flags = 0;
10847
10848 if (rettv_list_alloc(rettv) == FAIL)
10849 return;
10850
10851 n = search_cmn(argvars, &match_pos, &flags);
10852 if (n > 0)
10853 {
10854 lnum = match_pos.lnum;
10855 col = match_pos.col;
10856 }
10857
10858 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10859 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10860 if (flags & SP_SUBPAT)
10861 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10862}
10863
10864 static void
10865f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10866{
10867#ifdef FEAT_CLIENTSERVER
10868 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010869 char_u *server = tv_get_string_chk(&argvars[0]);
10870 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010871
10872 rettv->vval.v_number = -1;
10873 if (server == NULL || reply == NULL)
10874 return;
10875 if (check_restricted() || check_secure())
10876 return;
10877# ifdef FEAT_X11
10878 if (check_connection() == FAIL)
10879 return;
10880# endif
10881
10882 if (serverSendReply(server, reply) < 0)
10883 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010884 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010885 return;
10886 }
10887 rettv->vval.v_number = 0;
10888#else
10889 rettv->vval.v_number = -1;
10890#endif
10891}
10892
10893 static void
10894f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10895{
10896 char_u *r = NULL;
10897
10898#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010899# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010900 r = serverGetVimNames();
10901# else
10902 make_connection();
10903 if (X_DISPLAY != NULL)
10904 r = serverGetVimNames(X_DISPLAY);
10905# endif
10906#endif
10907 rettv->v_type = VAR_STRING;
10908 rettv->vval.v_string = r;
10909}
10910
10911/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010912 * "setbufline()" function
10913 */
10914 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010915f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010916{
10917 linenr_T lnum;
10918 buf_T *buf;
10919
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010920 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010921 if (buf == NULL)
10922 rettv->vval.v_number = 1; /* FAIL */
10923 else
10924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010925 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010926 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010927 }
10928}
10929
10930/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010931 * "setbufvar()" function
10932 */
10933 static void
10934f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10935{
10936 buf_T *buf;
10937 char_u *varname, *bufvarname;
10938 typval_T *varp;
10939 char_u nbuf[NUMBUFLEN];
10940
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010941 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010942 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010943 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10944 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010945 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010946 varp = &argvars[2];
10947
10948 if (buf != NULL && varname != NULL && varp != NULL)
10949 {
10950 if (*varname == '&')
10951 {
10952 long numval;
10953 char_u *strval;
10954 int error = FALSE;
10955 aco_save_T aco;
10956
10957 /* set curbuf to be our buf, temporarily */
10958 aucmd_prepbuf(&aco, buf);
10959
10960 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010961 numval = (long)tv_get_number_chk(varp, &error);
10962 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010963 if (!error && strval != NULL)
10964 set_option_value(varname, numval, strval, OPT_LOCAL);
10965
10966 /* reset notion of buffer */
10967 aucmd_restbuf(&aco);
10968 }
10969 else
10970 {
10971 buf_T *save_curbuf = curbuf;
10972
Bram Moolenaar964b3742019-05-24 18:54:09 +020010973 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010974 if (bufvarname != NULL)
10975 {
10976 curbuf = buf;
10977 STRCPY(bufvarname, "b:");
10978 STRCPY(bufvarname + 2, varname);
10979 set_var(bufvarname, varp, TRUE);
10980 vim_free(bufvarname);
10981 curbuf = save_curbuf;
10982 }
10983 }
10984 }
10985}
10986
10987 static void
10988f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10989{
10990 dict_T *d;
10991 dictitem_T *di;
10992 char_u *csearch;
10993
10994 if (argvars[0].v_type != VAR_DICT)
10995 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010996 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997 return;
10998 }
10999
11000 if ((d = argvars[0].vval.v_dict) != NULL)
11001 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011002 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011003 if (csearch != NULL)
11004 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011005 if (enc_utf8)
11006 {
11007 int pcc[MAX_MCO];
11008 int c = utfc_ptr2char(csearch, pcc);
11009
11010 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11011 }
11012 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011013 set_last_csearch(PTR2CHAR(csearch),
11014 csearch, MB_PTR2LEN(csearch));
11015 }
11016
11017 di = dict_find(d, (char_u *)"forward", -1);
11018 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011019 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011020 ? FORWARD : BACKWARD);
11021
11022 di = dict_find(d, (char_u *)"until", -1);
11023 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011024 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011025 }
11026}
11027
11028/*
11029 * "setcmdpos()" function
11030 */
11031 static void
11032f_setcmdpos(typval_T *argvars, typval_T *rettv)
11033{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011034 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011035
11036 if (pos >= 0)
11037 rettv->vval.v_number = set_cmdline_pos(pos);
11038}
11039
11040/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020011041 * "setenv()" function
11042 */
11043 static void
11044f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
11045{
11046 char_u namebuf[NUMBUFLEN];
11047 char_u valbuf[NUMBUFLEN];
11048 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
11049
11050 if (argvars[1].v_type == VAR_SPECIAL
11051 && argvars[1].vval.v_number == VVAL_NULL)
11052 vim_unsetenv(name);
11053 else
11054 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
11055}
11056
11057/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011058 * "setfperm({fname}, {mode})" function
11059 */
11060 static void
11061f_setfperm(typval_T *argvars, typval_T *rettv)
11062{
11063 char_u *fname;
11064 char_u modebuf[NUMBUFLEN];
11065 char_u *mode_str;
11066 int i;
11067 int mask;
11068 int mode = 0;
11069
11070 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011071 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011072 if (fname == NULL)
11073 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011074 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011075 if (mode_str == NULL)
11076 return;
11077 if (STRLEN(mode_str) != 9)
11078 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011079 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 return;
11081 }
11082
11083 mask = 1;
11084 for (i = 8; i >= 0; --i)
11085 {
11086 if (mode_str[i] != '-')
11087 mode |= mask;
11088 mask = mask << 1;
11089 }
11090 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11091}
11092
11093/*
11094 * "setline()" function
11095 */
11096 static void
11097f_setline(typval_T *argvars, typval_T *rettv)
11098{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011099 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011100
Bram Moolenaarca851592018-06-06 21:04:07 +020011101 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011102}
11103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011104/*
11105 * Used by "setqflist()" and "setloclist()" functions
11106 */
11107 static void
11108set_qf_ll_list(
11109 win_T *wp UNUSED,
11110 typval_T *list_arg UNUSED,
11111 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011112 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011113 typval_T *rettv)
11114{
11115#ifdef FEAT_QUICKFIX
11116 static char *e_invact = N_("E927: Invalid action: '%s'");
11117 char_u *act;
11118 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011119 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011120#endif
11121
11122 rettv->vval.v_number = -1;
11123
11124#ifdef FEAT_QUICKFIX
11125 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011126 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011127 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011128 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011129 else
11130 {
11131 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011132 dict_T *d = NULL;
11133 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011134
11135 if (action_arg->v_type == VAR_STRING)
11136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011137 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011138 if (act == NULL)
11139 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011140 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11141 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011142 action = *act;
11143 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011144 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011145 }
11146 else if (action_arg->v_type == VAR_UNKNOWN)
11147 action = ' ';
11148 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011149 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011150
Bram Moolenaard823fa92016-08-12 16:29:27 +020011151 if (action_arg->v_type != VAR_UNKNOWN
11152 && what_arg->v_type != VAR_UNKNOWN)
11153 {
11154 if (what_arg->v_type == VAR_DICT)
11155 d = what_arg->vval.v_dict;
11156 else
11157 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011158 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011159 valid_dict = FALSE;
11160 }
11161 }
11162
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011163 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011164 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011165 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11166 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011167 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011168 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011169 }
11170#endif
11171}
11172
11173/*
11174 * "setloclist()" function
11175 */
11176 static void
11177f_setloclist(typval_T *argvars, typval_T *rettv)
11178{
11179 win_T *win;
11180
11181 rettv->vval.v_number = -1;
11182
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011183 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011184 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011185 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011186}
11187
11188/*
11189 * "setmatches()" function
11190 */
11191 static void
11192f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11193{
11194#ifdef FEAT_SEARCH_EXTRA
11195 list_T *l;
11196 listitem_T *li;
11197 dict_T *d;
11198 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010011199 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011200
11201 rettv->vval.v_number = -1;
11202 if (argvars[0].v_type != VAR_LIST)
11203 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011204 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205 return;
11206 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010011207 if (win == NULL)
11208 return;
11209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011210 if ((l = argvars[0].vval.v_list) != NULL)
11211 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011212 /* To some extent make sure that we are dealing with a list from
11213 * "getmatches()". */
11214 li = l->lv_first;
11215 while (li != NULL)
11216 {
11217 if (li->li_tv.v_type != VAR_DICT
11218 || (d = li->li_tv.vval.v_dict) == NULL)
11219 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011220 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011221 return;
11222 }
11223 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11224 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11225 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11226 && dict_find(d, (char_u *)"priority", -1) != NULL
11227 && dict_find(d, (char_u *)"id", -1) != NULL))
11228 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011229 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011230 return;
11231 }
11232 li = li->li_next;
11233 }
11234
Bram Moolenaaraff74912019-03-30 18:11:49 +010011235 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236 li = l->lv_first;
11237 while (li != NULL)
11238 {
11239 int i = 0;
Bram Moolenaar54315892019-04-26 22:33:49 +020011240 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011241 dictitem_T *di;
11242 char_u *group;
11243 int priority;
11244 int id;
11245 char_u *conceal;
11246
11247 d = li->li_tv.vval.v_dict;
11248 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11249 {
11250 if (s == NULL)
11251 {
11252 s = list_alloc();
11253 if (s == NULL)
11254 return;
11255 }
11256
11257 /* match from matchaddpos() */
11258 for (i = 1; i < 9; i++)
11259 {
11260 sprintf((char *)buf, (char *)"pos%d", i);
11261 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11262 {
11263 if (di->di_tv.v_type != VAR_LIST)
11264 return;
11265
11266 list_append_tv(s, &di->di_tv);
11267 s->lv_refcount++;
11268 }
11269 else
11270 break;
11271 }
11272 }
11273
Bram Moolenaar8f667172018-12-14 15:38:31 +010011274 group = dict_get_string(d, (char_u *)"group", TRUE);
11275 priority = (int)dict_get_number(d, (char_u *)"priority");
11276 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011277 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011278 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011279 : NULL;
11280 if (i == 0)
11281 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011282 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011283 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011284 priority, id, NULL, conceal);
11285 }
11286 else
11287 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011288 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011289 list_unref(s);
11290 s = NULL;
11291 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011292 vim_free(group);
11293 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011294
11295 li = li->li_next;
11296 }
11297 rettv->vval.v_number = 0;
11298 }
11299#endif
11300}
11301
11302/*
11303 * "setpos()" function
11304 */
11305 static void
11306f_setpos(typval_T *argvars, typval_T *rettv)
11307{
11308 pos_T pos;
11309 int fnum;
11310 char_u *name;
11311 colnr_T curswant = -1;
11312
11313 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011314 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011315 if (name != NULL)
11316 {
11317 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11318 {
11319 if (--pos.col < 0)
11320 pos.col = 0;
11321 if (name[0] == '.' && name[1] == NUL)
11322 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011323 /* set cursor; "fnum" is ignored */
11324 curwin->w_cursor = pos;
11325 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011326 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011327 curwin->w_curswant = curswant - 1;
11328 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011329 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011330 check_cursor();
11331 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011332 }
11333 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11334 {
11335 /* set mark */
11336 if (setmark_pos(name[1], &pos, fnum) == OK)
11337 rettv->vval.v_number = 0;
11338 }
11339 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011340 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011341 }
11342 }
11343}
11344
11345/*
11346 * "setqflist()" function
11347 */
11348 static void
11349f_setqflist(typval_T *argvars, typval_T *rettv)
11350{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011351 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011352}
11353
11354/*
11355 * "setreg()" function
11356 */
11357 static void
11358f_setreg(typval_T *argvars, typval_T *rettv)
11359{
11360 int regname;
11361 char_u *strregname;
11362 char_u *stropt;
11363 char_u *strval;
11364 int append;
11365 char_u yank_type;
11366 long block_len;
11367
11368 block_len = -1;
11369 yank_type = MAUTO;
11370 append = FALSE;
11371
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011372 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011373 rettv->vval.v_number = 1; /* FAIL is default */
11374
11375 if (strregname == NULL)
11376 return; /* type error; errmsg already given */
11377 regname = *strregname;
11378 if (regname == 0 || regname == '@')
11379 regname = '"';
11380
11381 if (argvars[2].v_type != VAR_UNKNOWN)
11382 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011383 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384 if (stropt == NULL)
11385 return; /* type error */
11386 for (; *stropt != NUL; ++stropt)
11387 switch (*stropt)
11388 {
11389 case 'a': case 'A': /* append */
11390 append = TRUE;
11391 break;
11392 case 'v': case 'c': /* character-wise selection */
11393 yank_type = MCHAR;
11394 break;
11395 case 'V': case 'l': /* line-wise selection */
11396 yank_type = MLINE;
11397 break;
11398 case 'b': case Ctrl_V: /* block-wise selection */
11399 yank_type = MBLOCK;
11400 if (VIM_ISDIGIT(stropt[1]))
11401 {
11402 ++stropt;
11403 block_len = getdigits(&stropt) - 1;
11404 --stropt;
11405 }
11406 break;
11407 }
11408 }
11409
11410 if (argvars[1].v_type == VAR_LIST)
11411 {
11412 char_u **lstval;
11413 char_u **allocval;
11414 char_u buf[NUMBUFLEN];
11415 char_u **curval;
11416 char_u **curallocval;
11417 list_T *ll = argvars[1].vval.v_list;
11418 listitem_T *li;
11419 int len;
11420
11421 /* If the list is NULL handle like an empty list. */
11422 len = ll == NULL ? 0 : ll->lv_len;
11423
11424 /* First half: use for pointers to result lines; second half: use for
11425 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020011426 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011427 if (lstval == NULL)
11428 return;
11429 curval = lstval;
11430 allocval = lstval + len + 2;
11431 curallocval = allocval;
11432
11433 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11434 li = li->li_next)
11435 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011436 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011437 if (strval == NULL)
11438 goto free_lstval;
11439 if (strval == buf)
11440 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011441 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011442 * overwrite the string. */
11443 strval = vim_strsave(buf);
11444 if (strval == NULL)
11445 goto free_lstval;
11446 *curallocval++ = strval;
11447 }
11448 *curval++ = strval;
11449 }
11450 *curval++ = NULL;
11451
11452 write_reg_contents_lst(regname, lstval, -1,
11453 append, yank_type, block_len);
11454free_lstval:
11455 while (curallocval > allocval)
11456 vim_free(*--curallocval);
11457 vim_free(lstval);
11458 }
11459 else
11460 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011461 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011462 if (strval == NULL)
11463 return;
11464 write_reg_contents_ex(regname, strval, -1,
11465 append, yank_type, block_len);
11466 }
11467 rettv->vval.v_number = 0;
11468}
11469
11470/*
11471 * "settabvar()" function
11472 */
11473 static void
11474f_settabvar(typval_T *argvars, typval_T *rettv)
11475{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011476 tabpage_T *save_curtab;
11477 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011478 char_u *varname, *tabvarname;
11479 typval_T *varp;
11480
11481 rettv->vval.v_number = 0;
11482
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011483 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011484 return;
11485
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011486 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11487 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011488 varp = &argvars[2];
11489
Bram Moolenaar4033c552017-09-16 20:54:51 +020011490 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011491 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011492 save_curtab = curtab;
11493 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011494
Bram Moolenaar964b3742019-05-24 18:54:09 +020011495 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011496 if (tabvarname != NULL)
11497 {
11498 STRCPY(tabvarname, "t:");
11499 STRCPY(tabvarname + 2, varname);
11500 set_var(tabvarname, varp, TRUE);
11501 vim_free(tabvarname);
11502 }
11503
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011504 /* Restore current tabpage */
11505 if (valid_tabpage(save_curtab))
11506 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011507 }
11508}
11509
11510/*
11511 * "settabwinvar()" function
11512 */
11513 static void
11514f_settabwinvar(typval_T *argvars, typval_T *rettv)
11515{
11516 setwinvar(argvars, rettv, 1);
11517}
11518
11519/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011520 * "settagstack()" function
11521 */
11522 static void
11523f_settagstack(typval_T *argvars, typval_T *rettv)
11524{
11525 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11526 win_T *wp;
11527 dict_T *d;
11528 int action = 'r';
11529
11530 rettv->vval.v_number = -1;
11531
11532 // first argument: window number or id
11533 wp = find_win_by_nr_or_id(&argvars[0]);
11534 if (wp == NULL)
11535 return;
11536
11537 // second argument: dict with items to set in the tag stack
11538 if (argvars[1].v_type != VAR_DICT)
11539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011540 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011541 return;
11542 }
11543 d = argvars[1].vval.v_dict;
11544 if (d == NULL)
11545 return;
11546
11547 // third argument: action - 'a' for append and 'r' for replace.
11548 // default is to replace the stack.
11549 if (argvars[2].v_type == VAR_UNKNOWN)
11550 action = 'r';
11551 else if (argvars[2].v_type == VAR_STRING)
11552 {
11553 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011554 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011555 if (actstr == NULL)
11556 return;
11557 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11558 action = *actstr;
11559 else
11560 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011561 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011562 return;
11563 }
11564 }
11565 else
11566 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011567 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011568 return;
11569 }
11570
11571 if (set_tagstack(wp, d, action) == OK)
11572 rettv->vval.v_number = 0;
11573}
11574
11575/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011576 * "setwinvar()" function
11577 */
11578 static void
11579f_setwinvar(typval_T *argvars, typval_T *rettv)
11580{
11581 setwinvar(argvars, rettv, 0);
11582}
11583
11584#ifdef FEAT_CRYPT
11585/*
11586 * "sha256({string})" function
11587 */
11588 static void
11589f_sha256(typval_T *argvars, typval_T *rettv)
11590{
11591 char_u *p;
11592
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011593 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011594 rettv->vval.v_string = vim_strsave(
11595 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11596 rettv->v_type = VAR_STRING;
11597}
11598#endif /* FEAT_CRYPT */
11599
11600/*
11601 * "shellescape({string})" function
11602 */
11603 static void
11604f_shellescape(typval_T *argvars, typval_T *rettv)
11605{
Bram Moolenaar20615522017-06-05 18:46:26 +020011606 int do_special = non_zero_arg(&argvars[1]);
11607
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011608 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011609 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011610 rettv->v_type = VAR_STRING;
11611}
11612
11613/*
11614 * shiftwidth() function
11615 */
11616 static void
11617f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11618{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011619 rettv->vval.v_number = 0;
11620
11621 if (argvars[0].v_type != VAR_UNKNOWN)
11622 {
11623 long col;
11624
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011625 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011626 if (col < 0)
11627 return; // type error; errmsg already given
11628#ifdef FEAT_VARTABS
11629 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11630 return;
11631#endif
11632 }
11633
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011634 rettv->vval.v_number = get_sw_value(curbuf);
11635}
11636
11637/*
11638 * "simplify()" function
11639 */
11640 static void
11641f_simplify(typval_T *argvars, typval_T *rettv)
11642{
11643 char_u *p;
11644
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011645 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011646 rettv->vval.v_string = vim_strsave(p);
11647 simplify_filename(rettv->vval.v_string); /* simplify in place */
11648 rettv->v_type = VAR_STRING;
11649}
11650
11651#ifdef FEAT_FLOAT
11652/*
11653 * "sin()" function
11654 */
11655 static void
11656f_sin(typval_T *argvars, typval_T *rettv)
11657{
11658 float_T f = 0.0;
11659
11660 rettv->v_type = VAR_FLOAT;
11661 if (get_float_arg(argvars, &f) == OK)
11662 rettv->vval.v_float = sin(f);
11663 else
11664 rettv->vval.v_float = 0.0;
11665}
11666
11667/*
11668 * "sinh()" function
11669 */
11670 static void
11671f_sinh(typval_T *argvars, typval_T *rettv)
11672{
11673 float_T f = 0.0;
11674
11675 rettv->v_type = VAR_FLOAT;
11676 if (get_float_arg(argvars, &f) == OK)
11677 rettv->vval.v_float = sinh(f);
11678 else
11679 rettv->vval.v_float = 0.0;
11680}
11681#endif
11682
Bram Moolenaareae1b912019-05-09 15:12:55 +020011683static int item_compare(const void *s1, const void *s2);
11684static int item_compare2(const void *s1, const void *s2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011685
11686/* struct used in the array that's given to qsort() */
11687typedef struct
11688{
11689 listitem_T *item;
11690 int idx;
11691} sortItem_T;
11692
11693/* struct storing information about current sort */
11694typedef struct
11695{
11696 int item_compare_ic;
11697 int item_compare_numeric;
11698 int item_compare_numbers;
11699#ifdef FEAT_FLOAT
11700 int item_compare_float;
11701#endif
11702 char_u *item_compare_func;
11703 partial_T *item_compare_partial;
11704 dict_T *item_compare_selfdict;
11705 int item_compare_func_err;
11706 int item_compare_keep_zero;
11707} sortinfo_T;
11708static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011709#define ITEM_COMPARE_FAIL 999
11710
11711/*
11712 * Compare functions for f_sort() and f_uniq() below.
11713 */
11714 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011715item_compare(const void *s1, const void *s2)
11716{
11717 sortItem_T *si1, *si2;
11718 typval_T *tv1, *tv2;
11719 char_u *p1, *p2;
11720 char_u *tofree1 = NULL, *tofree2 = NULL;
11721 int res;
11722 char_u numbuf1[NUMBUFLEN];
11723 char_u numbuf2[NUMBUFLEN];
11724
11725 si1 = (sortItem_T *)s1;
11726 si2 = (sortItem_T *)s2;
11727 tv1 = &si1->item->li_tv;
11728 tv2 = &si2->item->li_tv;
11729
11730 if (sortinfo->item_compare_numbers)
11731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011732 varnumber_T v1 = tv_get_number(tv1);
11733 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011734
11735 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11736 }
11737
11738#ifdef FEAT_FLOAT
11739 if (sortinfo->item_compare_float)
11740 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011741 float_T v1 = tv_get_float(tv1);
11742 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011743
11744 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11745 }
11746#endif
11747
11748 /* tv2string() puts quotes around a string and allocates memory. Don't do
11749 * that for string variables. Use a single quote when comparing with a
11750 * non-string to do what the docs promise. */
11751 if (tv1->v_type == VAR_STRING)
11752 {
11753 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11754 p1 = (char_u *)"'";
11755 else
11756 p1 = tv1->vval.v_string;
11757 }
11758 else
11759 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11760 if (tv2->v_type == VAR_STRING)
11761 {
11762 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11763 p2 = (char_u *)"'";
11764 else
11765 p2 = tv2->vval.v_string;
11766 }
11767 else
11768 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11769 if (p1 == NULL)
11770 p1 = (char_u *)"";
11771 if (p2 == NULL)
11772 p2 = (char_u *)"";
11773 if (!sortinfo->item_compare_numeric)
11774 {
11775 if (sortinfo->item_compare_ic)
11776 res = STRICMP(p1, p2);
11777 else
11778 res = STRCMP(p1, p2);
11779 }
11780 else
11781 {
11782 double n1, n2;
11783 n1 = strtod((char *)p1, (char **)&p1);
11784 n2 = strtod((char *)p2, (char **)&p2);
11785 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11786 }
11787
11788 /* When the result would be zero, compare the item indexes. Makes the
11789 * sort stable. */
11790 if (res == 0 && !sortinfo->item_compare_keep_zero)
11791 res = si1->idx > si2->idx ? 1 : -1;
11792
11793 vim_free(tofree1);
11794 vim_free(tofree2);
11795 return res;
11796}
11797
11798 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011799item_compare2(const void *s1, const void *s2)
11800{
11801 sortItem_T *si1, *si2;
11802 int res;
11803 typval_T rettv;
11804 typval_T argv[3];
11805 int dummy;
11806 char_u *func_name;
11807 partial_T *partial = sortinfo->item_compare_partial;
11808
11809 /* shortcut after failure in previous call; compare all items equal */
11810 if (sortinfo->item_compare_func_err)
11811 return 0;
11812
11813 si1 = (sortItem_T *)s1;
11814 si2 = (sortItem_T *)s2;
11815
11816 if (partial == NULL)
11817 func_name = sortinfo->item_compare_func;
11818 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011819 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011820
11821 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11822 * in the copy without changing the original list items. */
11823 copy_tv(&si1->item->li_tv, &argv[0]);
11824 copy_tv(&si2->item->li_tv, &argv[1]);
11825
11826 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
Bram Moolenaar6ed88192019-05-11 18:37:44 +020011827 res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011828 partial, sortinfo->item_compare_selfdict);
11829 clear_tv(&argv[0]);
11830 clear_tv(&argv[1]);
11831
11832 if (res == FAIL)
11833 res = ITEM_COMPARE_FAIL;
11834 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011835 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011836 if (sortinfo->item_compare_func_err)
11837 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11838 clear_tv(&rettv);
11839
11840 /* When the result would be zero, compare the pointers themselves. Makes
11841 * the sort stable. */
11842 if (res == 0 && !sortinfo->item_compare_keep_zero)
11843 res = si1->idx > si2->idx ? 1 : -1;
11844
11845 return res;
11846}
11847
11848/*
11849 * "sort({list})" function
11850 */
11851 static void
11852do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11853{
11854 list_T *l;
11855 listitem_T *li;
11856 sortItem_T *ptrs;
11857 sortinfo_T *old_sortinfo;
11858 sortinfo_T info;
11859 long len;
11860 long i;
11861
11862 /* Pointer to current info struct used in compare function. Save and
11863 * restore the current one for nested calls. */
11864 old_sortinfo = sortinfo;
11865 sortinfo = &info;
11866
11867 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011868 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011869 else
11870 {
11871 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010011872 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011873 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11874 TRUE))
11875 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011876 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011877
11878 len = list_len(l);
11879 if (len <= 1)
11880 goto theend; /* short list sorts pretty quickly */
11881
11882 info.item_compare_ic = FALSE;
11883 info.item_compare_numeric = FALSE;
11884 info.item_compare_numbers = FALSE;
11885#ifdef FEAT_FLOAT
11886 info.item_compare_float = FALSE;
11887#endif
11888 info.item_compare_func = NULL;
11889 info.item_compare_partial = NULL;
11890 info.item_compare_selfdict = NULL;
11891 if (argvars[1].v_type != VAR_UNKNOWN)
11892 {
11893 /* optional second argument: {func} */
11894 if (argvars[1].v_type == VAR_FUNC)
11895 info.item_compare_func = argvars[1].vval.v_string;
11896 else if (argvars[1].v_type == VAR_PARTIAL)
11897 info.item_compare_partial = argvars[1].vval.v_partial;
11898 else
11899 {
11900 int error = FALSE;
11901
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011902 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011903 if (error)
11904 goto theend; /* type error; errmsg already given */
11905 if (i == 1)
11906 info.item_compare_ic = TRUE;
11907 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011908 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011909 else if (i != 0)
11910 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011911 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011912 goto theend;
11913 }
11914 if (info.item_compare_func != NULL)
11915 {
11916 if (*info.item_compare_func == NUL)
11917 {
11918 /* empty string means default sort */
11919 info.item_compare_func = NULL;
11920 }
11921 else if (STRCMP(info.item_compare_func, "n") == 0)
11922 {
11923 info.item_compare_func = NULL;
11924 info.item_compare_numeric = TRUE;
11925 }
11926 else if (STRCMP(info.item_compare_func, "N") == 0)
11927 {
11928 info.item_compare_func = NULL;
11929 info.item_compare_numbers = TRUE;
11930 }
11931#ifdef FEAT_FLOAT
11932 else if (STRCMP(info.item_compare_func, "f") == 0)
11933 {
11934 info.item_compare_func = NULL;
11935 info.item_compare_float = TRUE;
11936 }
11937#endif
11938 else if (STRCMP(info.item_compare_func, "i") == 0)
11939 {
11940 info.item_compare_func = NULL;
11941 info.item_compare_ic = TRUE;
11942 }
11943 }
11944 }
11945
11946 if (argvars[2].v_type != VAR_UNKNOWN)
11947 {
11948 /* optional third argument: {dict} */
11949 if (argvars[2].v_type != VAR_DICT)
11950 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011951 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011952 goto theend;
11953 }
11954 info.item_compare_selfdict = argvars[2].vval.v_dict;
11955 }
11956 }
11957
11958 /* Make an array with each entry pointing to an item in the List. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020011959 ptrs = ALLOC_MULT(sortItem_T, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011960 if (ptrs == NULL)
11961 goto theend;
11962
11963 i = 0;
11964 if (sort)
11965 {
11966 /* sort(): ptrs will be the list to sort */
11967 for (li = l->lv_first; li != NULL; li = li->li_next)
11968 {
11969 ptrs[i].item = li;
11970 ptrs[i].idx = i;
11971 ++i;
11972 }
11973
11974 info.item_compare_func_err = FALSE;
11975 info.item_compare_keep_zero = FALSE;
11976 /* test the compare function */
11977 if ((info.item_compare_func != NULL
11978 || info.item_compare_partial != NULL)
11979 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11980 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011981 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011982 else
11983 {
11984 /* Sort the array with item pointers. */
11985 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11986 info.item_compare_func == NULL
11987 && info.item_compare_partial == NULL
11988 ? item_compare : item_compare2);
11989
11990 if (!info.item_compare_func_err)
11991 {
11992 /* Clear the List and append the items in sorted order. */
11993 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11994 l->lv_len = 0;
11995 for (i = 0; i < len; ++i)
11996 list_append(l, ptrs[i].item);
11997 }
11998 }
11999 }
12000 else
12001 {
12002 int (*item_compare_func_ptr)(const void *, const void *);
12003
12004 /* f_uniq(): ptrs will be a stack of items to remove */
12005 info.item_compare_func_err = FALSE;
12006 info.item_compare_keep_zero = TRUE;
12007 item_compare_func_ptr = info.item_compare_func != NULL
12008 || info.item_compare_partial != NULL
12009 ? item_compare2 : item_compare;
12010
12011 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12012 li = li->li_next)
12013 {
12014 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12015 == 0)
12016 ptrs[i++].item = li;
12017 if (info.item_compare_func_err)
12018 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012019 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012020 break;
12021 }
12022 }
12023
12024 if (!info.item_compare_func_err)
12025 {
12026 while (--i >= 0)
12027 {
12028 li = ptrs[i].item->li_next;
12029 ptrs[i].item->li_next = li->li_next;
12030 if (li->li_next != NULL)
12031 li->li_next->li_prev = ptrs[i].item;
12032 else
12033 l->lv_last = ptrs[i].item;
12034 list_fix_watch(l, li);
12035 listitem_free(li);
12036 l->lv_len--;
12037 }
12038 }
12039 }
12040
12041 vim_free(ptrs);
12042 }
12043theend:
12044 sortinfo = old_sortinfo;
12045}
12046
12047/*
12048 * "sort({list})" function
12049 */
12050 static void
12051f_sort(typval_T *argvars, typval_T *rettv)
12052{
12053 do_sort_uniq(argvars, rettv, TRUE);
12054}
12055
12056/*
12057 * "uniq({list})" function
12058 */
12059 static void
12060f_uniq(typval_T *argvars, typval_T *rettv)
12061{
12062 do_sort_uniq(argvars, rettv, FALSE);
12063}
12064
12065/*
12066 * "soundfold({word})" function
12067 */
12068 static void
12069f_soundfold(typval_T *argvars, typval_T *rettv)
12070{
12071 char_u *s;
12072
12073 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012074 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012075#ifdef FEAT_SPELL
12076 rettv->vval.v_string = eval_soundfold(s);
12077#else
12078 rettv->vval.v_string = vim_strsave(s);
12079#endif
12080}
12081
12082/*
12083 * "spellbadword()" function
12084 */
12085 static void
12086f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12087{
12088 char_u *word = (char_u *)"";
12089 hlf_T attr = HLF_COUNT;
12090 int len = 0;
12091
12092 if (rettv_list_alloc(rettv) == FAIL)
12093 return;
12094
12095#ifdef FEAT_SPELL
12096 if (argvars[0].v_type == VAR_UNKNOWN)
12097 {
12098 /* Find the start and length of the badly spelled word. */
12099 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12100 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012101 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012102 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012103 curwin->w_set_curswant = TRUE;
12104 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012105 }
12106 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12107 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012108 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012109 int capcol = -1;
12110
12111 if (str != NULL)
12112 {
12113 /* Check the argument for spelling. */
12114 while (*str != NUL)
12115 {
12116 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12117 if (attr != HLF_COUNT)
12118 {
12119 word = str;
12120 break;
12121 }
12122 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012123 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012124 }
12125 }
12126 }
12127#endif
12128
12129 list_append_string(rettv->vval.v_list, word, len);
12130 list_append_string(rettv->vval.v_list, (char_u *)(
12131 attr == HLF_SPB ? "bad" :
12132 attr == HLF_SPR ? "rare" :
12133 attr == HLF_SPL ? "local" :
12134 attr == HLF_SPC ? "caps" :
12135 ""), -1);
12136}
12137
12138/*
12139 * "spellsuggest()" function
12140 */
12141 static void
12142f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12143{
12144#ifdef FEAT_SPELL
12145 char_u *str;
12146 int typeerr = FALSE;
12147 int maxcount;
12148 garray_T ga;
12149 int i;
12150 listitem_T *li;
12151 int need_capital = FALSE;
12152#endif
12153
12154 if (rettv_list_alloc(rettv) == FAIL)
12155 return;
12156
12157#ifdef FEAT_SPELL
12158 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12159 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012160 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012161 if (argvars[1].v_type != VAR_UNKNOWN)
12162 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012163 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012164 if (maxcount <= 0)
12165 return;
12166 if (argvars[2].v_type != VAR_UNKNOWN)
12167 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012168 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012169 if (typeerr)
12170 return;
12171 }
12172 }
12173 else
12174 maxcount = 25;
12175
12176 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12177
12178 for (i = 0; i < ga.ga_len; ++i)
12179 {
12180 str = ((char_u **)ga.ga_data)[i];
12181
12182 li = listitem_alloc();
12183 if (li == NULL)
12184 vim_free(str);
12185 else
12186 {
12187 li->li_tv.v_type = VAR_STRING;
12188 li->li_tv.v_lock = 0;
12189 li->li_tv.vval.v_string = str;
12190 list_append(rettv->vval.v_list, li);
12191 }
12192 }
12193 ga_clear(&ga);
12194 }
12195#endif
12196}
12197
12198 static void
12199f_split(typval_T *argvars, typval_T *rettv)
12200{
12201 char_u *str;
12202 char_u *end;
12203 char_u *pat = NULL;
12204 regmatch_T regmatch;
12205 char_u patbuf[NUMBUFLEN];
12206 char_u *save_cpo;
12207 int match;
12208 colnr_T col = 0;
12209 int keepempty = FALSE;
12210 int typeerr = FALSE;
12211
12212 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12213 save_cpo = p_cpo;
12214 p_cpo = (char_u *)"";
12215
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012216 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012217 if (argvars[1].v_type != VAR_UNKNOWN)
12218 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012219 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012220 if (pat == NULL)
12221 typeerr = TRUE;
12222 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012223 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012224 }
12225 if (pat == NULL || *pat == NUL)
12226 pat = (char_u *)"[\\x01- ]\\+";
12227
12228 if (rettv_list_alloc(rettv) == FAIL)
12229 return;
12230 if (typeerr)
12231 return;
12232
12233 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12234 if (regmatch.regprog != NULL)
12235 {
12236 regmatch.rm_ic = FALSE;
12237 while (*str != NUL || keepempty)
12238 {
12239 if (*str == NUL)
12240 match = FALSE; /* empty item at the end */
12241 else
12242 match = vim_regexec_nl(&regmatch, str, col);
12243 if (match)
12244 end = regmatch.startp[0];
12245 else
12246 end = str + STRLEN(str);
12247 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12248 && *str != NUL && match && end < regmatch.endp[0]))
12249 {
12250 if (list_append_string(rettv->vval.v_list, str,
12251 (int)(end - str)) == FAIL)
12252 break;
12253 }
12254 if (!match)
12255 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012256 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012257 if (regmatch.endp[0] > str)
12258 col = 0;
12259 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012260 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012261 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012262 str = regmatch.endp[0];
12263 }
12264
12265 vim_regfree(regmatch.regprog);
12266 }
12267
12268 p_cpo = save_cpo;
12269}
12270
12271#ifdef FEAT_FLOAT
12272/*
12273 * "sqrt()" function
12274 */
12275 static void
12276f_sqrt(typval_T *argvars, typval_T *rettv)
12277{
12278 float_T f = 0.0;
12279
12280 rettv->v_type = VAR_FLOAT;
12281 if (get_float_arg(argvars, &f) == OK)
12282 rettv->vval.v_float = sqrt(f);
12283 else
12284 rettv->vval.v_float = 0.0;
12285}
12286
12287/*
12288 * "str2float()" function
12289 */
12290 static void
12291f_str2float(typval_T *argvars, typval_T *rettv)
12292{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012293 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012294 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012295
Bram Moolenaar08243d22017-01-10 16:12:29 +010012296 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012297 p = skipwhite(p + 1);
12298 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012299 if (isneg)
12300 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012301 rettv->v_type = VAR_FLOAT;
12302}
12303#endif
12304
12305/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020012306 * "str2list()" function
12307 */
12308 static void
12309f_str2list(typval_T *argvars, typval_T *rettv)
12310{
12311 char_u *p;
12312 int utf8 = FALSE;
12313
12314 if (rettv_list_alloc(rettv) == FAIL)
12315 return;
12316
12317 if (argvars[1].v_type != VAR_UNKNOWN)
12318 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
12319
12320 p = tv_get_string(&argvars[0]);
12321
12322 if (has_mbyte || utf8)
12323 {
12324 int (*ptr2len)(char_u *);
12325 int (*ptr2char)(char_u *);
12326
12327 if (utf8 || enc_utf8)
12328 {
12329 ptr2len = utf_ptr2len;
12330 ptr2char = utf_ptr2char;
12331 }
12332 else
12333 {
12334 ptr2len = mb_ptr2len;
12335 ptr2char = mb_ptr2char;
12336 }
12337
12338 for ( ; *p != NUL; p += (*ptr2len)(p))
12339 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
12340 }
12341 else
12342 for ( ; *p != NUL; ++p)
12343 list_append_number(rettv->vval.v_list, *p);
12344}
12345
12346/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012347 * "str2nr()" function
12348 */
12349 static void
12350f_str2nr(typval_T *argvars, typval_T *rettv)
12351{
12352 int base = 10;
12353 char_u *p;
12354 varnumber_T n;
12355 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012356 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357
12358 if (argvars[1].v_type != VAR_UNKNOWN)
12359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012360 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012361 if (base != 2 && base != 8 && base != 10 && base != 16)
12362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012363 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012364 return;
12365 }
12366 }
12367
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012368 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012369 isneg = (*p == '-');
12370 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012371 p = skipwhite(p + 1);
12372 switch (base)
12373 {
12374 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12375 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12376 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12377 default: what = 0;
12378 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020012379 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
12380 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010012381 if (isneg)
12382 rettv->vval.v_number = -n;
12383 else
12384 rettv->vval.v_number = n;
12385
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012386}
12387
12388#ifdef HAVE_STRFTIME
12389/*
12390 * "strftime({format}[, {time}])" function
12391 */
12392 static void
12393f_strftime(typval_T *argvars, typval_T *rettv)
12394{
12395 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020012396 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012397 struct tm *curtime;
12398 time_t seconds;
12399 char_u *p;
12400
12401 rettv->v_type = VAR_STRING;
12402
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012403 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012404 if (argvars[1].v_type == VAR_UNKNOWN)
12405 seconds = time(NULL);
12406 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012407 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020012408 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012409 /* MSVC returns NULL for an invalid value of seconds. */
12410 if (curtime == NULL)
12411 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12412 else
12413 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012414 vimconv_T conv;
12415 char_u *enc;
12416
12417 conv.vc_type = CONV_NONE;
12418 enc = enc_locale();
12419 convert_setup(&conv, p_enc, enc);
12420 if (conv.vc_type != CONV_NONE)
12421 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012422 if (p != NULL)
12423 (void)strftime((char *)result_buf, sizeof(result_buf),
12424 (char *)p, curtime);
12425 else
12426 result_buf[0] = NUL;
12427
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012428 if (conv.vc_type != CONV_NONE)
12429 vim_free(p);
12430 convert_setup(&conv, enc, p_enc);
12431 if (conv.vc_type != CONV_NONE)
12432 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12433 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012434 rettv->vval.v_string = vim_strsave(result_buf);
12435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012436 /* Release conversion descriptors */
12437 convert_setup(&conv, NULL, NULL);
12438 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012439 }
12440}
12441#endif
12442
12443/*
12444 * "strgetchar()" function
12445 */
12446 static void
12447f_strgetchar(typval_T *argvars, typval_T *rettv)
12448{
12449 char_u *str;
12450 int len;
12451 int error = FALSE;
12452 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012453 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012454
12455 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012456 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012457 if (str == NULL)
12458 return;
12459 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012460 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012461 if (error)
12462 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012463
Bram Moolenaar13505972019-01-24 15:04:48 +010012464 while (charidx >= 0 && byteidx < len)
12465 {
12466 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012467 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012468 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12469 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012470 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012471 --charidx;
12472 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012473 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012474}
12475
12476/*
12477 * "stridx()" function
12478 */
12479 static void
12480f_stridx(typval_T *argvars, typval_T *rettv)
12481{
12482 char_u buf[NUMBUFLEN];
12483 char_u *needle;
12484 char_u *haystack;
12485 char_u *save_haystack;
12486 char_u *pos;
12487 int start_idx;
12488
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012489 needle = tv_get_string_chk(&argvars[1]);
12490 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012491 rettv->vval.v_number = -1;
12492 if (needle == NULL || haystack == NULL)
12493 return; /* type error; errmsg already given */
12494
12495 if (argvars[2].v_type != VAR_UNKNOWN)
12496 {
12497 int error = FALSE;
12498
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012499 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012500 if (error || start_idx >= (int)STRLEN(haystack))
12501 return;
12502 if (start_idx >= 0)
12503 haystack += start_idx;
12504 }
12505
12506 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12507 if (pos != NULL)
12508 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12509}
12510
12511/*
12512 * "string()" function
12513 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012514 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012515f_string(typval_T *argvars, typval_T *rettv)
12516{
12517 char_u *tofree;
12518 char_u numbuf[NUMBUFLEN];
12519
12520 rettv->v_type = VAR_STRING;
12521 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12522 get_copyID());
12523 /* Make a copy if we have a value but it's not in allocated memory. */
12524 if (rettv->vval.v_string != NULL && tofree == NULL)
12525 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12526}
12527
12528/*
12529 * "strlen()" function
12530 */
12531 static void
12532f_strlen(typval_T *argvars, typval_T *rettv)
12533{
12534 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012535 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012536}
12537
12538/*
12539 * "strchars()" function
12540 */
12541 static void
12542f_strchars(typval_T *argvars, typval_T *rettv)
12543{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012544 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012545 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012546 varnumber_T len = 0;
12547 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012548
12549 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012550 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012551 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012552 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012553 else
12554 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012555 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12556 while (*s != NUL)
12557 {
12558 func_mb_ptr2char_adv(&s);
12559 ++len;
12560 }
12561 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012562 }
12563}
12564
12565/*
12566 * "strdisplaywidth()" function
12567 */
12568 static void
12569f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12570{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012571 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012572 int col = 0;
12573
12574 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012575 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012576
12577 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12578}
12579
12580/*
12581 * "strwidth()" function
12582 */
12583 static void
12584f_strwidth(typval_T *argvars, typval_T *rettv)
12585{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012586 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012587
Bram Moolenaar13505972019-01-24 15:04:48 +010012588 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012589}
12590
12591/*
12592 * "strcharpart()" function
12593 */
12594 static void
12595f_strcharpart(typval_T *argvars, typval_T *rettv)
12596{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012597 char_u *p;
12598 int nchar;
12599 int nbyte = 0;
12600 int charlen;
12601 int len = 0;
12602 int slen;
12603 int error = FALSE;
12604
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012605 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012606 slen = (int)STRLEN(p);
12607
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012608 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012609 if (!error)
12610 {
12611 if (nchar > 0)
12612 while (nchar > 0 && nbyte < slen)
12613 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012614 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012615 --nchar;
12616 }
12617 else
12618 nbyte = nchar;
12619 if (argvars[2].v_type != VAR_UNKNOWN)
12620 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012621 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012622 while (charlen > 0 && nbyte + len < slen)
12623 {
12624 int off = nbyte + len;
12625
12626 if (off < 0)
12627 len += 1;
12628 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012629 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012630 --charlen;
12631 }
12632 }
12633 else
12634 len = slen - nbyte; /* default: all bytes that are available. */
12635 }
12636
12637 /*
12638 * Only return the overlap between the specified part and the actual
12639 * string.
12640 */
12641 if (nbyte < 0)
12642 {
12643 len += nbyte;
12644 nbyte = 0;
12645 }
12646 else if (nbyte > slen)
12647 nbyte = slen;
12648 if (len < 0)
12649 len = 0;
12650 else if (nbyte + len > slen)
12651 len = slen - nbyte;
12652
12653 rettv->v_type = VAR_STRING;
12654 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012655}
12656
12657/*
12658 * "strpart()" function
12659 */
12660 static void
12661f_strpart(typval_T *argvars, typval_T *rettv)
12662{
12663 char_u *p;
12664 int n;
12665 int len;
12666 int slen;
12667 int error = FALSE;
12668
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012669 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012670 slen = (int)STRLEN(p);
12671
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012672 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012673 if (error)
12674 len = 0;
12675 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012676 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012677 else
12678 len = slen - n; /* default len: all bytes that are available. */
12679
12680 /*
12681 * Only return the overlap between the specified part and the actual
12682 * string.
12683 */
12684 if (n < 0)
12685 {
12686 len += n;
12687 n = 0;
12688 }
12689 else if (n > slen)
12690 n = slen;
12691 if (len < 0)
12692 len = 0;
12693 else if (n + len > slen)
12694 len = slen - n;
12695
12696 rettv->v_type = VAR_STRING;
12697 rettv->vval.v_string = vim_strnsave(p + n, len);
12698}
12699
12700/*
12701 * "strridx()" function
12702 */
12703 static void
12704f_strridx(typval_T *argvars, typval_T *rettv)
12705{
12706 char_u buf[NUMBUFLEN];
12707 char_u *needle;
12708 char_u *haystack;
12709 char_u *rest;
12710 char_u *lastmatch = NULL;
12711 int haystack_len, end_idx;
12712
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012713 needle = tv_get_string_chk(&argvars[1]);
12714 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012715
12716 rettv->vval.v_number = -1;
12717 if (needle == NULL || haystack == NULL)
12718 return; /* type error; errmsg already given */
12719
12720 haystack_len = (int)STRLEN(haystack);
12721 if (argvars[2].v_type != VAR_UNKNOWN)
12722 {
12723 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012724 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012725 if (end_idx < 0)
12726 return; /* can never find a match */
12727 }
12728 else
12729 end_idx = haystack_len;
12730
12731 if (*needle == NUL)
12732 {
12733 /* Empty string matches past the end. */
12734 lastmatch = haystack + end_idx;
12735 }
12736 else
12737 {
12738 for (rest = haystack; *rest != '\0'; ++rest)
12739 {
12740 rest = (char_u *)strstr((char *)rest, (char *)needle);
12741 if (rest == NULL || rest > haystack + end_idx)
12742 break;
12743 lastmatch = rest;
12744 }
12745 }
12746
12747 if (lastmatch == NULL)
12748 rettv->vval.v_number = -1;
12749 else
12750 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12751}
12752
12753/*
12754 * "strtrans()" function
12755 */
12756 static void
12757f_strtrans(typval_T *argvars, typval_T *rettv)
12758{
12759 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012760 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761}
12762
12763/*
12764 * "submatch()" function
12765 */
12766 static void
12767f_submatch(typval_T *argvars, typval_T *rettv)
12768{
12769 int error = FALSE;
12770 int no;
12771 int retList = 0;
12772
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012773 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012774 if (error)
12775 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012776 if (no < 0 || no >= NSUBEXP)
12777 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012778 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010012779 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012780 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012781 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012782 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012783 if (error)
12784 return;
12785
12786 if (retList == 0)
12787 {
12788 rettv->v_type = VAR_STRING;
12789 rettv->vval.v_string = reg_submatch(no);
12790 }
12791 else
12792 {
12793 rettv->v_type = VAR_LIST;
12794 rettv->vval.v_list = reg_submatch_list(no);
12795 }
12796}
12797
12798/*
12799 * "substitute()" function
12800 */
12801 static void
12802f_substitute(typval_T *argvars, typval_T *rettv)
12803{
12804 char_u patbuf[NUMBUFLEN];
12805 char_u subbuf[NUMBUFLEN];
12806 char_u flagsbuf[NUMBUFLEN];
12807
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012808 char_u *str = tv_get_string_chk(&argvars[0]);
12809 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012810 char_u *sub = NULL;
12811 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012812 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012813
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012814 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12815 expr = &argvars[2];
12816 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012817 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012818
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012819 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012820 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12821 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012822 rettv->vval.v_string = NULL;
12823 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012824 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012825}
12826
12827/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012828 * "swapinfo(swap_filename)" function
12829 */
12830 static void
12831f_swapinfo(typval_T *argvars, typval_T *rettv)
12832{
12833 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012834 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012835}
12836
12837/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012838 * "swapname(expr)" function
12839 */
12840 static void
12841f_swapname(typval_T *argvars, typval_T *rettv)
12842{
12843 buf_T *buf;
12844
12845 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010012846 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020012847 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12848 || buf->b_ml.ml_mfp->mf_fname == NULL)
12849 rettv->vval.v_string = NULL;
12850 else
12851 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12852}
12853
12854/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012855 * "synID(lnum, col, trans)" function
12856 */
12857 static void
12858f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12859{
12860 int id = 0;
12861#ifdef FEAT_SYN_HL
12862 linenr_T lnum;
12863 colnr_T col;
12864 int trans;
12865 int transerr = FALSE;
12866
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012867 lnum = tv_get_lnum(argvars); /* -1 on type error */
12868 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
12869 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012870
12871 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12872 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12873 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12874#endif
12875
12876 rettv->vval.v_number = id;
12877}
12878
12879/*
12880 * "synIDattr(id, what [, mode])" function
12881 */
12882 static void
12883f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12884{
12885 char_u *p = NULL;
12886#ifdef FEAT_SYN_HL
12887 int id;
12888 char_u *what;
12889 char_u *mode;
12890 char_u modebuf[NUMBUFLEN];
12891 int modec;
12892
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012893 id = (int)tv_get_number(&argvars[0]);
12894 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012895 if (argvars[2].v_type != VAR_UNKNOWN)
12896 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012897 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012898 modec = TOLOWER_ASC(mode[0]);
12899 if (modec != 't' && modec != 'c' && modec != 'g')
12900 modec = 0; /* replace invalid with current */
12901 }
12902 else
12903 {
12904#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12905 if (USE_24BIT)
12906 modec = 'g';
12907 else
12908#endif
12909 if (t_colors > 1)
12910 modec = 'c';
12911 else
12912 modec = 't';
12913 }
12914
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012915 switch (TOLOWER_ASC(what[0]))
12916 {
12917 case 'b':
12918 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12919 p = highlight_color(id, what, modec);
12920 else /* bold */
12921 p = highlight_has_attr(id, HL_BOLD, modec);
12922 break;
12923
12924 case 'f': /* fg[#] or font */
12925 p = highlight_color(id, what, modec);
12926 break;
12927
12928 case 'i':
12929 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12930 p = highlight_has_attr(id, HL_INVERSE, modec);
12931 else /* italic */
12932 p = highlight_has_attr(id, HL_ITALIC, modec);
12933 break;
12934
12935 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012936 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012937 break;
12938
12939 case 'r': /* reverse */
12940 p = highlight_has_attr(id, HL_INVERSE, modec);
12941 break;
12942
12943 case 's':
12944 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12945 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012946 /* strikeout */
12947 else if (TOLOWER_ASC(what[1]) == 't' &&
12948 TOLOWER_ASC(what[2]) == 'r')
12949 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012950 else /* standout */
12951 p = highlight_has_attr(id, HL_STANDOUT, modec);
12952 break;
12953
12954 case 'u':
12955 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12956 /* underline */
12957 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12958 else
12959 /* undercurl */
12960 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12961 break;
12962 }
12963
12964 if (p != NULL)
12965 p = vim_strsave(p);
12966#endif
12967 rettv->v_type = VAR_STRING;
12968 rettv->vval.v_string = p;
12969}
12970
12971/*
12972 * "synIDtrans(id)" function
12973 */
12974 static void
12975f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12976{
12977 int id;
12978
12979#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012980 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012981
12982 if (id > 0)
12983 id = syn_get_final_id(id);
12984 else
12985#endif
12986 id = 0;
12987
12988 rettv->vval.v_number = id;
12989}
12990
12991/*
12992 * "synconcealed(lnum, col)" function
12993 */
12994 static void
12995f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12996{
12997#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12998 linenr_T lnum;
12999 colnr_T col;
13000 int syntax_flags = 0;
13001 int cchar;
13002 int matchid = 0;
13003 char_u str[NUMBUFLEN];
13004#endif
13005
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013006 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013007
13008#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013009 lnum = tv_get_lnum(argvars); /* -1 on type error */
13010 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013011
13012 vim_memset(str, NUL, sizeof(str));
13013
13014 if (rettv_list_alloc(rettv) != FAIL)
13015 {
13016 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13017 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13018 && curwin->w_p_cole > 0)
13019 {
13020 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13021 syntax_flags = get_syntax_info(&matchid);
13022
13023 /* get the conceal character */
13024 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13025 {
13026 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013027 if (cchar == NUL && curwin->w_p_cole == 1)
13028 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013029 if (cchar != NUL)
13030 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013031 if (has_mbyte)
13032 (*mb_char2bytes)(cchar, str);
13033 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013034 str[0] = cchar;
13035 }
13036 }
13037 }
13038
13039 list_append_number(rettv->vval.v_list,
13040 (syntax_flags & HL_CONCEAL) != 0);
13041 /* -1 to auto-determine strlen */
13042 list_append_string(rettv->vval.v_list, str, -1);
13043 list_append_number(rettv->vval.v_list, matchid);
13044 }
13045#endif
13046}
13047
13048/*
13049 * "synstack(lnum, col)" function
13050 */
13051 static void
13052f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13053{
13054#ifdef FEAT_SYN_HL
13055 linenr_T lnum;
13056 colnr_T col;
13057 int i;
13058 int id;
13059#endif
13060
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013061 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013062
13063#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013064 lnum = tv_get_lnum(argvars); /* -1 on type error */
13065 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013066
13067 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13068 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13069 && rettv_list_alloc(rettv) != FAIL)
13070 {
13071 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13072 for (i = 0; ; ++i)
13073 {
13074 id = syn_get_stack_item(i);
13075 if (id < 0)
13076 break;
13077 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13078 break;
13079 }
13080 }
13081#endif
13082}
13083
13084 static void
13085get_cmd_output_as_rettv(
13086 typval_T *argvars,
13087 typval_T *rettv,
13088 int retlist)
13089{
13090 char_u *res = NULL;
13091 char_u *p;
13092 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013093 int err = FALSE;
13094 FILE *fd;
13095 list_T *list = NULL;
13096 int flags = SHELL_SILENT;
13097
13098 rettv->v_type = VAR_STRING;
13099 rettv->vval.v_string = NULL;
13100 if (check_restricted() || check_secure())
13101 goto errret;
13102
13103 if (argvars[1].v_type != VAR_UNKNOWN)
13104 {
13105 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013106 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013107 * command.
13108 */
13109 if ((infile = vim_tempname('i', TRUE)) == NULL)
13110 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013111 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112 goto errret;
13113 }
13114
13115 fd = mch_fopen((char *)infile, WRITEBIN);
13116 if (fd == NULL)
13117 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013118 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013119 goto errret;
13120 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013121 if (argvars[1].v_type == VAR_NUMBER)
13122 {
13123 linenr_T lnum;
13124 buf_T *buf;
13125
13126 buf = buflist_findnr(argvars[1].vval.v_number);
13127 if (buf == NULL)
13128 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013129 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013130 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013131 goto errret;
13132 }
13133
13134 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13135 {
13136 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13137 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13138 {
13139 err = TRUE;
13140 break;
13141 }
13142 if (putc(NL, fd) == EOF)
13143 {
13144 err = TRUE;
13145 break;
13146 }
13147 }
13148 }
13149 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013150 {
13151 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13152 err = TRUE;
13153 }
13154 else
13155 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013156 size_t len;
13157 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013158
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013159 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013160 if (p == NULL)
13161 {
13162 fclose(fd);
13163 goto errret; /* type error; errmsg already given */
13164 }
13165 len = STRLEN(p);
13166 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13167 err = TRUE;
13168 }
13169 if (fclose(fd) != 0)
13170 err = TRUE;
13171 if (err)
13172 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013173 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013174 goto errret;
13175 }
13176 }
13177
13178 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13179 * echoes typeahead, that messes up the display. */
13180 if (!msg_silent)
13181 flags += SHELL_COOKED;
13182
13183 if (retlist)
13184 {
13185 int len;
13186 listitem_T *li;
13187 char_u *s = NULL;
13188 char_u *start;
13189 char_u *end;
13190 int i;
13191
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013192 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013193 if (res == NULL)
13194 goto errret;
13195
13196 list = list_alloc();
13197 if (list == NULL)
13198 goto errret;
13199
13200 for (i = 0; i < len; ++i)
13201 {
13202 start = res + i;
13203 while (i < len && res[i] != NL)
13204 ++i;
13205 end = res + i;
13206
Bram Moolenaar964b3742019-05-24 18:54:09 +020013207 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013208 if (s == NULL)
13209 goto errret;
13210
13211 for (p = s; start < end; ++p, ++start)
13212 *p = *start == NUL ? NL : *start;
13213 *p = NUL;
13214
13215 li = listitem_alloc();
13216 if (li == NULL)
13217 {
13218 vim_free(s);
13219 goto errret;
13220 }
13221 li->li_tv.v_type = VAR_STRING;
13222 li->li_tv.v_lock = 0;
13223 li->li_tv.vval.v_string = s;
13224 list_append(list, li);
13225 }
13226
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013227 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013228 list = NULL;
13229 }
13230 else
13231 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013232 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013233#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013234 /* translate <CR><NL> into <NL> */
13235 if (res != NULL)
13236 {
13237 char_u *s, *d;
13238
13239 d = res;
13240 for (s = res; *s; ++s)
13241 {
13242 if (s[0] == CAR && s[1] == NL)
13243 ++s;
13244 *d++ = *s;
13245 }
13246 *d = NUL;
13247 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013248#endif
13249 rettv->vval.v_string = res;
13250 res = NULL;
13251 }
13252
13253errret:
13254 if (infile != NULL)
13255 {
13256 mch_remove(infile);
13257 vim_free(infile);
13258 }
13259 if (res != NULL)
13260 vim_free(res);
13261 if (list != NULL)
13262 list_free(list);
13263}
13264
13265/*
13266 * "system()" function
13267 */
13268 static void
13269f_system(typval_T *argvars, typval_T *rettv)
13270{
13271 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13272}
13273
13274/*
13275 * "systemlist()" function
13276 */
13277 static void
13278f_systemlist(typval_T *argvars, typval_T *rettv)
13279{
13280 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13281}
13282
13283/*
13284 * "tabpagebuflist()" function
13285 */
13286 static void
13287f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13288{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013289 tabpage_T *tp;
13290 win_T *wp = NULL;
13291
13292 if (argvars[0].v_type == VAR_UNKNOWN)
13293 wp = firstwin;
13294 else
13295 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013296 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013297 if (tp != NULL)
13298 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13299 }
13300 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13301 {
13302 for (; wp != NULL; wp = wp->w_next)
13303 if (list_append_number(rettv->vval.v_list,
13304 wp->w_buffer->b_fnum) == FAIL)
13305 break;
13306 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013307}
13308
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013309/*
13310 * "tabpagenr()" function
13311 */
13312 static void
13313f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13314{
13315 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013316 char_u *arg;
13317
13318 if (argvars[0].v_type != VAR_UNKNOWN)
13319 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013320 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013321 nr = 0;
13322 if (arg != NULL)
13323 {
13324 if (STRCMP(arg, "$") == 0)
13325 nr = tabpage_index(NULL) - 1;
13326 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013327 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013328 }
13329 }
13330 else
13331 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013332 rettv->vval.v_number = nr;
13333}
13334
13335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013336/*
13337 * Common code for tabpagewinnr() and winnr().
13338 */
13339 static int
13340get_winnr(tabpage_T *tp, typval_T *argvar)
13341{
13342 win_T *twin;
13343 int nr = 1;
13344 win_T *wp;
13345 char_u *arg;
13346
13347 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13348 if (argvar->v_type != VAR_UNKNOWN)
13349 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020013350 int invalid_arg = FALSE;
13351
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013352 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013353 if (arg == NULL)
13354 nr = 0; /* type error; errmsg already given */
13355 else if (STRCMP(arg, "$") == 0)
13356 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13357 else if (STRCMP(arg, "#") == 0)
13358 {
13359 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13360 if (twin == NULL)
13361 nr = 0;
13362 }
13363 else
13364 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020013365 long count;
13366 char_u *endp;
13367
13368 // Extract the window count (if specified). e.g. winnr('3j')
13369 count = strtol((char *)arg, (char **)&endp, 10);
13370 if (count <= 0)
13371 count = 1; // if count is not specified, default to 1
13372 if (endp != NULL && *endp != '\0')
13373 {
13374 if (STRCMP(endp, "j") == 0)
13375 twin = win_vert_neighbor(tp, twin, FALSE, count);
13376 else if (STRCMP(endp, "k") == 0)
13377 twin = win_vert_neighbor(tp, twin, TRUE, count);
13378 else if (STRCMP(endp, "h") == 0)
13379 twin = win_horz_neighbor(tp, twin, TRUE, count);
13380 else if (STRCMP(endp, "l") == 0)
13381 twin = win_horz_neighbor(tp, twin, FALSE, count);
13382 else
13383 invalid_arg = TRUE;
13384 }
13385 else
13386 invalid_arg = TRUE;
13387 }
13388
13389 if (invalid_arg)
13390 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013391 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013392 nr = 0;
13393 }
13394 }
13395
13396 if (nr > 0)
13397 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13398 wp != twin; wp = wp->w_next)
13399 {
13400 if (wp == NULL)
13401 {
13402 /* didn't find it in this tabpage */
13403 nr = 0;
13404 break;
13405 }
13406 ++nr;
13407 }
13408 return nr;
13409}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013410
13411/*
13412 * "tabpagewinnr()" function
13413 */
13414 static void
13415f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13416{
13417 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013418 tabpage_T *tp;
13419
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013420 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013421 if (tp == NULL)
13422 nr = 0;
13423 else
13424 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013425 rettv->vval.v_number = nr;
13426}
13427
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013428/*
13429 * "tagfiles()" function
13430 */
13431 static void
13432f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13433{
13434 char_u *fname;
13435 tagname_T tn;
13436 int first;
13437
13438 if (rettv_list_alloc(rettv) == FAIL)
13439 return;
13440 fname = alloc(MAXPATHL);
13441 if (fname == NULL)
13442 return;
13443
13444 for (first = TRUE; ; first = FALSE)
13445 if (get_tagfname(&tn, first, fname) == FAIL
13446 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13447 break;
13448 tagname_free(&tn);
13449 vim_free(fname);
13450}
13451
13452/*
13453 * "taglist()" function
13454 */
13455 static void
13456f_taglist(typval_T *argvars, typval_T *rettv)
13457{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013458 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013459 char_u *tag_pattern;
13460
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013461 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013462
13463 rettv->vval.v_number = FALSE;
13464 if (*tag_pattern == NUL)
13465 return;
13466
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013467 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013468 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013469 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013470 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013471}
13472
13473/*
13474 * "tempname()" function
13475 */
13476 static void
13477f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13478{
13479 static int x = 'A';
13480
13481 rettv->v_type = VAR_STRING;
13482 rettv->vval.v_string = vim_tempname(x, FALSE);
13483
13484 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13485 * names. Skip 'I' and 'O', they are used for shell redirection. */
13486 do
13487 {
13488 if (x == 'Z')
13489 x = '0';
13490 else if (x == '9')
13491 x = 'A';
13492 else
13493 {
13494#ifdef EBCDIC
13495 if (x == 'I')
13496 x = 'J';
13497 else if (x == 'R')
13498 x = 'S';
13499 else
13500#endif
13501 ++x;
13502 }
13503 } while (x == 'I' || x == 'O');
13504}
13505
13506#ifdef FEAT_FLOAT
13507/*
13508 * "tan()" function
13509 */
13510 static void
13511f_tan(typval_T *argvars, typval_T *rettv)
13512{
13513 float_T f = 0.0;
13514
13515 rettv->v_type = VAR_FLOAT;
13516 if (get_float_arg(argvars, &f) == OK)
13517 rettv->vval.v_float = tan(f);
13518 else
13519 rettv->vval.v_float = 0.0;
13520}
13521
13522/*
13523 * "tanh()" function
13524 */
13525 static void
13526f_tanh(typval_T *argvars, typval_T *rettv)
13527{
13528 float_T f = 0.0;
13529
13530 rettv->v_type = VAR_FLOAT;
13531 if (get_float_arg(argvars, &f) == OK)
13532 rettv->vval.v_float = tanh(f);
13533 else
13534 rettv->vval.v_float = 0.0;
13535}
13536#endif
13537
13538/*
13539 * "test_alloc_fail(id, countdown, repeat)" function
13540 */
13541 static void
13542f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13543{
13544 if (argvars[0].v_type != VAR_NUMBER
13545 || argvars[0].vval.v_number <= 0
13546 || argvars[1].v_type != VAR_NUMBER
13547 || argvars[1].vval.v_number < 0
13548 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013549 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013550 else
13551 {
13552 alloc_fail_id = argvars[0].vval.v_number;
13553 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013554 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013555 alloc_fail_countdown = argvars[1].vval.v_number;
13556 alloc_fail_repeat = argvars[2].vval.v_number;
13557 did_outofmem_msg = FALSE;
13558 }
13559}
13560
13561/*
13562 * "test_autochdir()"
13563 */
13564 static void
13565f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13566{
13567#if defined(FEAT_AUTOCHDIR)
13568 test_autochdir = TRUE;
13569#endif
13570}
13571
13572/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013573 * "test_feedinput()"
13574 */
13575 static void
13576f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13577{
13578#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013579 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013580
13581 if (val != NULL)
13582 {
13583 trash_input_buf();
13584 add_to_input_buf_csi(val, (int)STRLEN(val));
13585 }
13586#endif
13587}
13588
13589/*
Bram Moolenaareda65222019-05-16 20:29:44 +020013590 * "test_getvalue({name})" function
13591 */
13592 static void
13593f_test_getvalue(typval_T *argvars, typval_T *rettv)
13594{
13595 if (argvars[0].v_type != VAR_STRING)
13596 emsg(_(e_invarg));
13597 else
13598 {
13599 char_u *name = tv_get_string(&argvars[0]);
13600
13601 if (STRCMP(name, (char_u *)"need_fileinfo") == 0)
13602 rettv->vval.v_number = need_fileinfo;
13603 else
13604 semsg(_(e_invarg2), name);
13605 }
13606}
13607
13608/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013609 * "test_option_not_set({name})" function
13610 */
13611 static void
13612f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13613{
13614 char_u *name = (char_u *)"";
13615
13616 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013617 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013618 else
13619 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013620 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013621 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013622 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013623 }
13624}
13625
13626/*
13627 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013628 */
13629 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013630f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013631{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013632 char_u *name = (char_u *)"";
13633 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013634 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013635
13636 if (argvars[0].v_type != VAR_STRING
13637 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013638 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013639 else
13640 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013641 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013642 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013643
13644 if (STRCMP(name, (char_u *)"redraw") == 0)
13645 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013646 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13647 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013648 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13649 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013650 else if (STRCMP(name, (char_u *)"starting") == 0)
13651 {
13652 if (val)
13653 {
13654 if (save_starting < 0)
13655 save_starting = starting;
13656 starting = 0;
13657 }
13658 else
13659 {
13660 starting = save_starting;
13661 save_starting = -1;
13662 }
13663 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013664 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13665 nfa_fail_for_testing = val;
Bram Moolenaar92fd5992019-05-02 23:00:22 +020013666 else if (STRCMP(name, (char_u *)"no_query_mouse") == 0)
13667 no_query_mouse_for_testing = val;
Bram Moolenaaradc67142019-06-22 01:40:42 +020013668 else if (STRCMP(name, (char_u *)"no_wait_return") == 0)
13669 no_wait_return = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013670 else if (STRCMP(name, (char_u *)"ALL") == 0)
13671 {
13672 disable_char_avail_for_testing = FALSE;
13673 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013674 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013675 nfa_fail_for_testing = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +020013676 no_query_mouse_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013677 if (save_starting >= 0)
13678 {
13679 starting = save_starting;
13680 save_starting = -1;
13681 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013682 }
13683 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013684 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013686}
13687
13688/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010013689 * "test_refcount({expr})" function
13690 */
13691 static void
13692f_test_refcount(typval_T *argvars, typval_T *rettv)
13693{
13694 int retval = -1;
13695
13696 switch (argvars[0].v_type)
13697 {
13698 case VAR_UNKNOWN:
13699 case VAR_NUMBER:
13700 case VAR_FLOAT:
13701 case VAR_SPECIAL:
13702 case VAR_STRING:
13703 break;
13704 case VAR_JOB:
13705#ifdef FEAT_JOB_CHANNEL
13706 if (argvars[0].vval.v_job != NULL)
13707 retval = argvars[0].vval.v_job->jv_refcount - 1;
13708#endif
13709 break;
13710 case VAR_CHANNEL:
13711#ifdef FEAT_JOB_CHANNEL
13712 if (argvars[0].vval.v_channel != NULL)
13713 retval = argvars[0].vval.v_channel->ch_refcount - 1;
13714#endif
13715 break;
13716 case VAR_FUNC:
13717 if (argvars[0].vval.v_string != NULL)
13718 {
13719 ufunc_T *fp;
13720
13721 fp = find_func(argvars[0].vval.v_string);
13722 if (fp != NULL)
13723 retval = fp->uf_refcount;
13724 }
13725 break;
13726 case VAR_PARTIAL:
13727 if (argvars[0].vval.v_partial != NULL)
13728 retval = argvars[0].vval.v_partial->pt_refcount - 1;
13729 break;
13730 case VAR_BLOB:
13731 if (argvars[0].vval.v_blob != NULL)
13732 retval = argvars[0].vval.v_blob->bv_refcount - 1;
13733 break;
13734 case VAR_LIST:
13735 if (argvars[0].vval.v_list != NULL)
13736 retval = argvars[0].vval.v_list->lv_refcount - 1;
13737 break;
13738 case VAR_DICT:
13739 if (argvars[0].vval.v_dict != NULL)
13740 retval = argvars[0].vval.v_dict->dv_refcount - 1;
13741 break;
13742 }
13743
13744 rettv->v_type = VAR_NUMBER;
13745 rettv->vval.v_number = retval;
13746
13747}
13748
13749/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013750 * "test_garbagecollect_now()" function
13751 */
13752 static void
13753f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13754{
13755 /* This is dangerous, any Lists and Dicts used internally may be freed
13756 * while still in use. */
13757 garbage_collect(TRUE);
13758}
13759
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013760/*
Bram Moolenaaradc67142019-06-22 01:40:42 +020013761 * "test_garbagecollect_soon()" function
13762 */
13763 static void
13764f_test_garbagecollect_soon(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13765{
13766 may_garbage_collect = TRUE;
13767}
13768
13769/*
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013770 * "test_ignore_error()" function
13771 */
13772 static void
13773f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
13774{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013775 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010013776}
13777
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010013778 static void
13779f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
13780{
13781 rettv->v_type = VAR_BLOB;
13782 rettv->vval.v_blob = NULL;
13783}
13784
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013785#ifdef FEAT_JOB_CHANNEL
13786 static void
13787f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
13788{
13789 rettv->v_type = VAR_CHANNEL;
13790 rettv->vval.v_channel = NULL;
13791}
13792#endif
13793
13794 static void
13795f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
13796{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013797 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013798}
13799
13800#ifdef FEAT_JOB_CHANNEL
13801 static void
13802f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
13803{
13804 rettv->v_type = VAR_JOB;
13805 rettv->vval.v_job = NULL;
13806}
13807#endif
13808
13809 static void
13810f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
13811{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013812 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013813}
13814
13815 static void
13816f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
13817{
13818 rettv->v_type = VAR_PARTIAL;
13819 rettv->vval.v_partial = NULL;
13820}
13821
13822 static void
13823f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
13824{
13825 rettv->v_type = VAR_STRING;
13826 rettv->vval.v_string = NULL;
13827}
13828
Bram Moolenaarab186732018-09-14 21:27:06 +020013829#ifdef FEAT_GUI
13830 static void
13831f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
13832{
13833 char_u *which;
13834 long value;
13835 int dragging;
13836 scrollbar_T *sb = NULL;
13837
13838 if (argvars[0].v_type != VAR_STRING
13839 || (argvars[1].v_type) != VAR_NUMBER
13840 || (argvars[2].v_type) != VAR_NUMBER)
13841 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013842 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020013843 return;
13844 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013845 which = tv_get_string(&argvars[0]);
13846 value = tv_get_number(&argvars[1]);
13847 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020013848
13849 if (STRCMP(which, "left") == 0)
13850 sb = &curwin->w_scrollbars[SBAR_LEFT];
13851 else if (STRCMP(which, "right") == 0)
13852 sb = &curwin->w_scrollbars[SBAR_RIGHT];
13853 else if (STRCMP(which, "hor") == 0)
13854 sb = &gui.bottom_sbar;
13855 if (sb == NULL)
13856 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013857 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020013858 return;
13859 }
13860 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020013861# ifndef USE_ON_FLY_SCROLL
13862 // need to loop through normal_cmd() to handle the scroll events
13863 exec_normal(FALSE, TRUE, FALSE);
13864# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020013865}
13866#endif
13867
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +020013868#ifdef FEAT_MOUSE
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013869 static void
Bram Moolenaarbb8476b2019-05-04 15:47:48 +020013870f_test_setmouse(typval_T *argvars, typval_T *rettv UNUSED)
13871{
13872 mouse_row = (time_t)tv_get_number(&argvars[0]) - 1;
13873 mouse_col = (time_t)tv_get_number(&argvars[1]) - 1;
13874}
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +020013875#endif
Bram Moolenaarbb8476b2019-05-04 15:47:48 +020013876
13877 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013878f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
13879{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013880 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013881}
13882
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013883/*
13884 * Get a callback from "arg". It can be a Funcref or a function name.
13885 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013886 * "cb_name" is not allocated.
13887 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013888 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013889 callback_T
13890get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013891{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013892 callback_T res;
13893
13894 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013895 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13896 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013897 res.cb_partial = arg->vval.v_partial;
13898 ++res.cb_partial->pt_refcount;
13899 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013900 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013901 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013902 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013903 res.cb_partial = NULL;
13904 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
13905 {
13906 // Note that we don't make a copy of the string.
13907 res.cb_name = arg->vval.v_string;
13908 func_ref(res.cb_name);
13909 }
13910 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13911 {
13912 res.cb_name = (char_u *)"";
13913 }
13914 else
13915 {
13916 emsg(_("E921: Invalid callback argument"));
13917 res.cb_name = NULL;
13918 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013919 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013920 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013921}
13922
13923/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013924 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013925 */
13926 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013927put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013928{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013929 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013930 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013931 tv->v_type = VAR_PARTIAL;
13932 tv->vval.v_partial = cb->cb_partial;
13933 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013934 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013935 else
13936 {
13937 tv->v_type = VAR_FUNC;
13938 tv->vval.v_string = vim_strsave(cb->cb_name);
13939 func_ref(cb->cb_name);
13940 }
13941}
13942
13943/*
13944 * Make a copy of "src" into "dest", allocating the function name if needed,
13945 * without incrementing the refcount.
13946 */
13947 void
13948set_callback(callback_T *dest, callback_T *src)
13949{
13950 if (src->cb_partial == NULL)
13951 {
13952 // just a function name, make a copy
13953 dest->cb_name = vim_strsave(src->cb_name);
13954 dest->cb_free_name = TRUE;
13955 }
13956 else
13957 {
13958 // cb_name is a pointer into cb_partial
13959 dest->cb_name = src->cb_name;
13960 dest->cb_free_name = FALSE;
13961 }
13962 dest->cb_partial = src->cb_partial;
13963}
13964
13965/*
13966 * Unref/free "callback" returned by get_callback() or set_callback().
13967 */
13968 void
13969free_callback(callback_T *callback)
13970{
13971 if (callback->cb_partial != NULL)
13972 {
13973 partial_unref(callback->cb_partial);
13974 callback->cb_partial = NULL;
13975 }
13976 else if (callback->cb_name != NULL)
13977 func_unref(callback->cb_name);
13978 if (callback->cb_free_name)
13979 {
13980 vim_free(callback->cb_name);
13981 callback->cb_free_name = FALSE;
13982 }
13983 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013984}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013985
13986#ifdef FEAT_TIMERS
13987/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013988 * "timer_info([timer])" function
13989 */
13990 static void
13991f_timer_info(typval_T *argvars, typval_T *rettv)
13992{
13993 timer_T *timer = NULL;
13994
13995 if (rettv_list_alloc(rettv) != OK)
13996 return;
13997 if (argvars[0].v_type != VAR_UNKNOWN)
13998 {
13999 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014000 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014001 else
14002 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014003 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014004 if (timer != NULL)
14005 add_timer_info(rettv, timer);
14006 }
14007 }
14008 else
14009 add_timer_info_all(rettv);
14010}
14011
14012/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014013 * "timer_pause(timer, paused)" function
14014 */
14015 static void
14016f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14017{
14018 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014019 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014020
14021 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014022 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014023 else
14024 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014025 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014026 if (timer != NULL)
14027 timer->tr_paused = paused;
14028 }
14029}
14030
14031/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014032 * "timer_start(time, callback [, options])" function
14033 */
14034 static void
14035f_timer_start(typval_T *argvars, typval_T *rettv)
14036{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014037 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014038 timer_T *timer;
14039 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020014040 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014041 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014042
Bram Moolenaar75537a92016-09-05 22:45:28 +020014043 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014044 if (check_secure())
14045 return;
14046 if (argvars[2].v_type != VAR_UNKNOWN)
14047 {
14048 if (argvars[2].v_type != VAR_DICT
14049 || (dict = argvars[2].vval.v_dict) == NULL)
14050 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014051 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014052 return;
14053 }
14054 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014055 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014056 }
14057
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020014058 callback = get_callback(&argvars[1]);
14059 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014060 return;
14061
14062 timer = create_timer(msec, repeat);
14063 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020014064 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014065 else
14066 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020014067 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014068 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014069 }
14070}
14071
14072/*
14073 * "timer_stop(timer)" function
14074 */
14075 static void
14076f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14077{
14078 timer_T *timer;
14079
14080 if (argvars[0].v_type != VAR_NUMBER)
14081 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014082 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014083 return;
14084 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014085 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014086 if (timer != NULL)
14087 stop_timer(timer);
14088}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014089
14090/*
14091 * "timer_stopall()" function
14092 */
14093 static void
14094f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14095{
14096 stop_all_timers();
14097}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014098#endif
14099
14100/*
14101 * "tolower(string)" function
14102 */
14103 static void
14104f_tolower(typval_T *argvars, typval_T *rettv)
14105{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014106 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014107 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014108}
14109
14110/*
14111 * "toupper(string)" function
14112 */
14113 static void
14114f_toupper(typval_T *argvars, typval_T *rettv)
14115{
14116 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014117 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014118}
14119
14120/*
14121 * "tr(string, fromstr, tostr)" function
14122 */
14123 static void
14124f_tr(typval_T *argvars, typval_T *rettv)
14125{
14126 char_u *in_str;
14127 char_u *fromstr;
14128 char_u *tostr;
14129 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014130 int inlen;
14131 int fromlen;
14132 int tolen;
14133 int idx;
14134 char_u *cpstr;
14135 int cplen;
14136 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014137 char_u buf[NUMBUFLEN];
14138 char_u buf2[NUMBUFLEN];
14139 garray_T ga;
14140
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014141 in_str = tv_get_string(&argvars[0]);
14142 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14143 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014144
14145 /* Default return value: empty string. */
14146 rettv->v_type = VAR_STRING;
14147 rettv->vval.v_string = NULL;
14148 if (fromstr == NULL || tostr == NULL)
14149 return; /* type error; errmsg already given */
14150 ga_init2(&ga, (int)sizeof(char), 80);
14151
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014152 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014153 /* not multi-byte: fromstr and tostr must be the same length */
14154 if (STRLEN(fromstr) != STRLEN(tostr))
14155 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014156error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014157 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014158 ga_clear(&ga);
14159 return;
14160 }
14161
14162 /* fromstr and tostr have to contain the same number of chars */
14163 while (*in_str != NUL)
14164 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014165 if (has_mbyte)
14166 {
14167 inlen = (*mb_ptr2len)(in_str);
14168 cpstr = in_str;
14169 cplen = inlen;
14170 idx = 0;
14171 for (p = fromstr; *p != NUL; p += fromlen)
14172 {
14173 fromlen = (*mb_ptr2len)(p);
14174 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14175 {
14176 for (p = tostr; *p != NUL; p += tolen)
14177 {
14178 tolen = (*mb_ptr2len)(p);
14179 if (idx-- == 0)
14180 {
14181 cplen = tolen;
14182 cpstr = p;
14183 break;
14184 }
14185 }
14186 if (*p == NUL) /* tostr is shorter than fromstr */
14187 goto error;
14188 break;
14189 }
14190 ++idx;
14191 }
14192
14193 if (first && cpstr == in_str)
14194 {
14195 /* Check that fromstr and tostr have the same number of
14196 * (multi-byte) characters. Done only once when a character
14197 * of in_str doesn't appear in fromstr. */
14198 first = FALSE;
14199 for (p = tostr; *p != NUL; p += tolen)
14200 {
14201 tolen = (*mb_ptr2len)(p);
14202 --idx;
14203 }
14204 if (idx != 0)
14205 goto error;
14206 }
14207
14208 (void)ga_grow(&ga, cplen);
14209 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14210 ga.ga_len += cplen;
14211
14212 in_str += inlen;
14213 }
14214 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014215 {
14216 /* When not using multi-byte chars we can do it faster. */
14217 p = vim_strchr(fromstr, *in_str);
14218 if (p != NULL)
14219 ga_append(&ga, tostr[p - fromstr]);
14220 else
14221 ga_append(&ga, *in_str);
14222 ++in_str;
14223 }
14224 }
14225
14226 /* add a terminating NUL */
14227 (void)ga_grow(&ga, 1);
14228 ga_append(&ga, NUL);
14229
14230 rettv->vval.v_string = ga.ga_data;
14231}
14232
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014233/*
14234 * "trim({expr})" function
14235 */
14236 static void
14237f_trim(typval_T *argvars, typval_T *rettv)
14238{
14239 char_u buf1[NUMBUFLEN];
14240 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014241 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014242 char_u *mask = NULL;
14243 char_u *tail;
14244 char_u *prev;
14245 char_u *p;
14246 int c1;
14247
14248 rettv->v_type = VAR_STRING;
14249 if (head == NULL)
14250 {
14251 rettv->vval.v_string = NULL;
14252 return;
14253 }
14254
14255 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014256 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014257
14258 while (*head != NUL)
14259 {
14260 c1 = PTR2CHAR(head);
14261 if (mask == NULL)
14262 {
14263 if (c1 > ' ' && c1 != 0xa0)
14264 break;
14265 }
14266 else
14267 {
14268 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14269 if (c1 == PTR2CHAR(p))
14270 break;
14271 if (*p == NUL)
14272 break;
14273 }
14274 MB_PTR_ADV(head);
14275 }
14276
14277 for (tail = head + STRLEN(head); tail > head; tail = prev)
14278 {
14279 prev = tail;
14280 MB_PTR_BACK(head, prev);
14281 c1 = PTR2CHAR(prev);
14282 if (mask == NULL)
14283 {
14284 if (c1 > ' ' && c1 != 0xa0)
14285 break;
14286 }
14287 else
14288 {
14289 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14290 if (c1 == PTR2CHAR(p))
14291 break;
14292 if (*p == NUL)
14293 break;
14294 }
14295 }
14296 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14297}
14298
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014299#ifdef FEAT_FLOAT
14300/*
14301 * "trunc({float})" function
14302 */
14303 static void
14304f_trunc(typval_T *argvars, typval_T *rettv)
14305{
14306 float_T f = 0.0;
14307
14308 rettv->v_type = VAR_FLOAT;
14309 if (get_float_arg(argvars, &f) == OK)
14310 /* trunc() is not in C90, use floor() or ceil() instead. */
14311 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14312 else
14313 rettv->vval.v_float = 0.0;
14314}
14315#endif
14316
14317/*
14318 * "type(expr)" function
14319 */
14320 static void
14321f_type(typval_T *argvars, typval_T *rettv)
14322{
14323 int n = -1;
14324
14325 switch (argvars[0].v_type)
14326 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014327 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14328 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014329 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014330 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14331 case VAR_LIST: n = VAR_TYPE_LIST; break;
14332 case VAR_DICT: n = VAR_TYPE_DICT; break;
14333 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014334 case VAR_SPECIAL:
14335 if (argvars[0].vval.v_number == VVAL_FALSE
14336 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014337 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014338 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014339 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014340 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014341 case VAR_JOB: n = VAR_TYPE_JOB; break;
14342 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014343 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014344 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014345 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014346 n = -1;
14347 break;
14348 }
14349 rettv->vval.v_number = n;
14350}
14351
14352/*
14353 * "undofile(name)" function
14354 */
14355 static void
14356f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14357{
14358 rettv->v_type = VAR_STRING;
14359#ifdef FEAT_PERSISTENT_UNDO
14360 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014361 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014362
14363 if (*fname == NUL)
14364 {
14365 /* If there is no file name there will be no undo file. */
14366 rettv->vval.v_string = NULL;
14367 }
14368 else
14369 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020014370 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014371
14372 if (ffname != NULL)
14373 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14374 vim_free(ffname);
14375 }
14376 }
14377#else
14378 rettv->vval.v_string = NULL;
14379#endif
14380}
14381
14382/*
14383 * "undotree()" function
14384 */
14385 static void
14386f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14387{
14388 if (rettv_dict_alloc(rettv) == OK)
14389 {
14390 dict_T *dict = rettv->vval.v_dict;
14391 list_T *list;
14392
Bram Moolenaare0be1672018-07-08 16:50:37 +020014393 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14394 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14395 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14396 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14397 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14398 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014399
14400 list = list_alloc();
14401 if (list != NULL)
14402 {
14403 u_eval_tree(curbuf->b_u_oldhead, list);
14404 dict_add_list(dict, "entries", list);
14405 }
14406 }
14407}
14408
14409/*
14410 * "values(dict)" function
14411 */
14412 static void
14413f_values(typval_T *argvars, typval_T *rettv)
14414{
14415 dict_list(argvars, rettv, 1);
14416}
14417
14418/*
14419 * "virtcol(string)" function
14420 */
14421 static void
14422f_virtcol(typval_T *argvars, typval_T *rettv)
14423{
14424 colnr_T vcol = 0;
14425 pos_T *fp;
14426 int fnum = curbuf->b_fnum;
14427
14428 fp = var2fpos(&argvars[0], FALSE, &fnum);
14429 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14430 && fnum == curbuf->b_fnum)
14431 {
14432 getvvcol(curwin, fp, NULL, NULL, &vcol);
14433 ++vcol;
14434 }
14435
14436 rettv->vval.v_number = vcol;
14437}
14438
14439/*
14440 * "visualmode()" function
14441 */
14442 static void
14443f_visualmode(typval_T *argvars, typval_T *rettv)
14444{
14445 char_u str[2];
14446
14447 rettv->v_type = VAR_STRING;
14448 str[0] = curbuf->b_visual_mode_eval;
14449 str[1] = NUL;
14450 rettv->vval.v_string = vim_strsave(str);
14451
14452 /* A non-zero number or non-empty string argument: reset mode. */
14453 if (non_zero_arg(&argvars[0]))
14454 curbuf->b_visual_mode_eval = NUL;
14455}
14456
14457/*
14458 * "wildmenumode()" function
14459 */
14460 static void
14461f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14462{
14463#ifdef FEAT_WILDMENU
14464 if (wild_menu_showing)
14465 rettv->vval.v_number = 1;
14466#endif
14467}
14468
14469/*
14470 * "winbufnr(nr)" function
14471 */
14472 static void
14473f_winbufnr(typval_T *argvars, typval_T *rettv)
14474{
14475 win_T *wp;
14476
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014477 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014478 if (wp == NULL)
14479 rettv->vval.v_number = -1;
14480 else
14481 rettv->vval.v_number = wp->w_buffer->b_fnum;
14482}
14483
14484/*
14485 * "wincol()" function
14486 */
14487 static void
14488f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14489{
14490 validate_cursor();
14491 rettv->vval.v_number = curwin->w_wcol + 1;
14492}
14493
14494/*
14495 * "winheight(nr)" function
14496 */
14497 static void
14498f_winheight(typval_T *argvars, typval_T *rettv)
14499{
14500 win_T *wp;
14501
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014502 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014503 if (wp == NULL)
14504 rettv->vval.v_number = -1;
14505 else
14506 rettv->vval.v_number = wp->w_height;
14507}
14508
14509/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014510 * "winlayout()" function
14511 */
14512 static void
14513f_winlayout(typval_T *argvars, typval_T *rettv)
14514{
14515 tabpage_T *tp;
14516
14517 if (rettv_list_alloc(rettv) != OK)
14518 return;
14519
14520 if (argvars[0].v_type == VAR_UNKNOWN)
14521 tp = curtab;
14522 else
14523 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014524 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014525 if (tp == NULL)
14526 return;
14527 }
14528
14529 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14530}
14531
14532/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014533 * "winline()" function
14534 */
14535 static void
14536f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14537{
14538 validate_cursor();
14539 rettv->vval.v_number = curwin->w_wrow + 1;
14540}
14541
14542/*
14543 * "winnr()" function
14544 */
14545 static void
14546f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14547{
14548 int nr = 1;
14549
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014550 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014551 rettv->vval.v_number = nr;
14552}
14553
14554/*
14555 * "winrestcmd()" function
14556 */
14557 static void
14558f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14559{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014560 win_T *wp;
14561 int winnr = 1;
14562 garray_T ga;
14563 char_u buf[50];
14564
14565 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014566 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014567 {
14568 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14569 ga_concat(&ga, buf);
14570 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14571 ga_concat(&ga, buf);
14572 ++winnr;
14573 }
14574 ga_append(&ga, NUL);
14575
14576 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014577 rettv->v_type = VAR_STRING;
14578}
14579
14580/*
14581 * "winrestview()" function
14582 */
14583 static void
14584f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14585{
14586 dict_T *dict;
14587
14588 if (argvars[0].v_type != VAR_DICT
14589 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014590 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014591 else
14592 {
14593 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014594 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014595 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014596 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014597 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014598 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014599 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14600 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014601 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014602 curwin->w_set_curswant = FALSE;
14603 }
14604
14605 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014606 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014607#ifdef FEAT_DIFF
14608 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014609 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014610#endif
14611 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014612 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014613 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014614 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014615
14616 check_cursor();
14617 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014618 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014619 changed_window_setting();
14620
14621 if (curwin->w_topline <= 0)
14622 curwin->w_topline = 1;
14623 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14624 curwin->w_topline = curbuf->b_ml.ml_line_count;
14625#ifdef FEAT_DIFF
14626 check_topfill(curwin, TRUE);
14627#endif
14628 }
14629}
14630
14631/*
14632 * "winsaveview()" function
14633 */
14634 static void
14635f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14636{
14637 dict_T *dict;
14638
14639 if (rettv_dict_alloc(rettv) == FAIL)
14640 return;
14641 dict = rettv->vval.v_dict;
14642
Bram Moolenaare0be1672018-07-08 16:50:37 +020014643 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14644 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014645 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014646 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014647 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014648
Bram Moolenaare0be1672018-07-08 16:50:37 +020014649 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014650#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014651 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014652#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014653 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14654 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014655}
14656
14657/*
14658 * "winwidth(nr)" function
14659 */
14660 static void
14661f_winwidth(typval_T *argvars, typval_T *rettv)
14662{
14663 win_T *wp;
14664
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014665 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014666 if (wp == NULL)
14667 rettv->vval.v_number = -1;
14668 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014669 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014670}
14671
14672/*
14673 * "wordcount()" function
14674 */
14675 static void
14676f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14677{
14678 if (rettv_dict_alloc(rettv) == FAIL)
14679 return;
14680 cursor_pos_info(rettv->vval.v_dict);
14681}
14682
14683/*
14684 * "writefile()" function
14685 */
14686 static void
14687f_writefile(typval_T *argvars, typval_T *rettv)
14688{
14689 int binary = FALSE;
14690 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014691#ifdef HAVE_FSYNC
14692 int do_fsync = p_fs;
14693#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014694 char_u *fname;
14695 FILE *fd;
14696 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014697 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014698 list_T *list = NULL;
14699 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014700
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014701 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014702 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014703 return;
14704
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014705 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014706 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014707 list = argvars[0].vval.v_list;
14708 if (list == NULL)
14709 return;
14710 for (li = list->lv_first; li != NULL; li = li->li_next)
14711 if (tv_get_string_chk(&li->li_tv) == NULL)
14712 return;
14713 }
14714 else if (argvars[0].v_type == VAR_BLOB)
14715 {
14716 blob = argvars[0].vval.v_blob;
14717 if (blob == NULL)
14718 return;
14719 }
14720 else
14721 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014722 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014723 return;
14724 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014725
14726 if (argvars[2].v_type != VAR_UNKNOWN)
14727 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014728 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014729
14730 if (arg2 == NULL)
14731 return;
14732 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014733 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014734 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014735 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014736#ifdef HAVE_FSYNC
14737 if (vim_strchr(arg2, 's') != NULL)
14738 do_fsync = TRUE;
14739 else if (vim_strchr(arg2, 'S') != NULL)
14740 do_fsync = FALSE;
14741#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014742 }
14743
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014744 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014745 if (fname == NULL)
14746 return;
14747
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014748 /* Always open the file in binary mode, library functions have a mind of
14749 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014750 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14751 append ? APPENDBIN : WRITEBIN)) == NULL)
14752 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014753 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014754 ret = -1;
14755 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014756 else if (blob)
14757 {
14758 if (write_blob(fd, blob) == FAIL)
14759 ret = -1;
14760#ifdef HAVE_FSYNC
14761 else if (do_fsync)
14762 // Ignore the error, the user wouldn't know what to do about it.
14763 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010014764 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014765#endif
14766 fclose(fd);
14767 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014768 else
14769 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014770 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014771 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014772#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010014773 else if (do_fsync)
14774 /* Ignore the error, the user wouldn't know what to do about it.
14775 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010014776 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014777#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014778 fclose(fd);
14779 }
14780
14781 rettv->vval.v_number = ret;
14782}
14783
14784/*
14785 * "xor(expr, expr)" function
14786 */
14787 static void
14788f_xor(typval_T *argvars, typval_T *rettv)
14789{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014790 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14791 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014792}
14793
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014794#endif /* FEAT_EVAL */