blob: 8b9fba02c24305ab60b8a1a85b72d9f607336b7c [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
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaard0573012017-10-28 21:11:06 +020023#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020024# include <time.h> /* for time_t */
25#endif
26
Bram Moolenaarbf821bc2019-01-23 21:15:02 +010027static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028static char *e_stringreq = N_("E928: String required");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020029
30#ifdef FEAT_FLOAT
31static void f_abs(typval_T *argvars, typval_T *rettv);
32static void f_acos(typval_T *argvars, typval_T *rettv);
33#endif
34static void f_add(typval_T *argvars, typval_T *rettv);
35static void f_and(typval_T *argvars, typval_T *rettv);
36static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020037static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020038static void f_argc(typval_T *argvars, typval_T *rettv);
39static void f_argidx(typval_T *argvars, typval_T *rettv);
40static void f_arglistid(typval_T *argvars, typval_T *rettv);
41static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020042#ifdef FEAT_FLOAT
43static void f_asin(typval_T *argvars, typval_T *rettv);
44static void f_atan(typval_T *argvars, typval_T *rettv);
45static void f_atan2(typval_T *argvars, typval_T *rettv);
46#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010047#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020048static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010049static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010050# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010051static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010052# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010053#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_browse(typval_T *argvars, typval_T *rettv);
55static void f_browsedir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020056static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_bufexists(typval_T *argvars, typval_T *rettv);
58static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020059static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020060static void f_bufloaded(typval_T *argvars, typval_T *rettv);
61static void f_bufname(typval_T *argvars, typval_T *rettv);
62static void f_bufnr(typval_T *argvars, typval_T *rettv);
63static void f_bufwinid(typval_T *argvars, typval_T *rettv);
64static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
65static void f_byte2line(typval_T *argvars, typval_T *rettv);
66static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
67static void f_byteidx(typval_T *argvars, typval_T *rettv);
68static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
69static void f_call(typval_T *argvars, typval_T *rettv);
70#ifdef FEAT_FLOAT
71static void f_ceil(typval_T *argvars, typval_T *rettv);
72#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_changenr(typval_T *argvars, typval_T *rettv);
74static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020075static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_cindent(typval_T *argvars, typval_T *rettv);
77static void f_clearmatches(typval_T *argvars, typval_T *rettv);
78static void f_col(typval_T *argvars, typval_T *rettv);
79#if defined(FEAT_INS_EXPAND)
80static void f_complete(typval_T *argvars, typval_T *rettv);
81static void f_complete_add(typval_T *argvars, typval_T *rettv);
82static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +010083static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020084#endif
85static void f_confirm(typval_T *argvars, typval_T *rettv);
86static void f_copy(typval_T *argvars, typval_T *rettv);
87#ifdef FEAT_FLOAT
88static void f_cos(typval_T *argvars, typval_T *rettv);
89static void f_cosh(typval_T *argvars, typval_T *rettv);
90#endif
91static void f_count(typval_T *argvars, typval_T *rettv);
92static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
93static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010094#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020095static void f_debugbreak(typval_T *argvars, typval_T *rettv);
96#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020097static void f_deepcopy(typval_T *argvars, typval_T *rettv);
98static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020099static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_did_filetype(typval_T *argvars, typval_T *rettv);
101static void f_diff_filler(typval_T *argvars, typval_T *rettv);
102static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
103static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200104static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_escape(typval_T *argvars, typval_T *rettv);
106static void f_eval(typval_T *argvars, typval_T *rettv);
107static void f_eventhandler(typval_T *argvars, typval_T *rettv);
108static void f_executable(typval_T *argvars, typval_T *rettv);
109static void f_execute(typval_T *argvars, typval_T *rettv);
110static void f_exepath(typval_T *argvars, typval_T *rettv);
111static void f_exists(typval_T *argvars, typval_T *rettv);
112#ifdef FEAT_FLOAT
113static void f_exp(typval_T *argvars, typval_T *rettv);
114#endif
115static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200116static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_extend(typval_T *argvars, typval_T *rettv);
118static void f_feedkeys(typval_T *argvars, typval_T *rettv);
119static void f_filereadable(typval_T *argvars, typval_T *rettv);
120static void f_filewritable(typval_T *argvars, typval_T *rettv);
121static void f_filter(typval_T *argvars, typval_T *rettv);
122static void f_finddir(typval_T *argvars, typval_T *rettv);
123static void f_findfile(typval_T *argvars, typval_T *rettv);
124#ifdef FEAT_FLOAT
125static void f_float2nr(typval_T *argvars, typval_T *rettv);
126static void f_floor(typval_T *argvars, typval_T *rettv);
127static void f_fmod(typval_T *argvars, typval_T *rettv);
128#endif
129static void f_fnameescape(typval_T *argvars, typval_T *rettv);
130static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
131static void f_foldclosed(typval_T *argvars, typval_T *rettv);
132static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
133static void f_foldlevel(typval_T *argvars, typval_T *rettv);
134static void f_foldtext(typval_T *argvars, typval_T *rettv);
135static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
136static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200137static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_function(typval_T *argvars, typval_T *rettv);
139static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
140static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200141static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200142static void f_getbufline(typval_T *argvars, typval_T *rettv);
143static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100144static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200145static void f_getchar(typval_T *argvars, typval_T *rettv);
146static void f_getcharmod(typval_T *argvars, typval_T *rettv);
147static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
148static void f_getcmdline(typval_T *argvars, typval_T *rettv);
149#if defined(FEAT_CMDL_COMPL)
150static void f_getcompletion(typval_T *argvars, typval_T *rettv);
151#endif
152static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
153static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
154static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
155static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200156static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200157static void f_getfontname(typval_T *argvars, typval_T *rettv);
158static void f_getfperm(typval_T *argvars, typval_T *rettv);
159static void f_getfsize(typval_T *argvars, typval_T *rettv);
160static void f_getftime(typval_T *argvars, typval_T *rettv);
161static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100162static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200164static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_getpid(typval_T *argvars, typval_T *rettv);
166static void f_getcurpos(typval_T *argvars, typval_T *rettv);
167static void f_getpos(typval_T *argvars, typval_T *rettv);
168static void f_getqflist(typval_T *argvars, typval_T *rettv);
169static void f_getreg(typval_T *argvars, typval_T *rettv);
170static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200171static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_gettabvar(typval_T *argvars, typval_T *rettv);
173static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100174static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200175static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100176static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_getwinposx(typval_T *argvars, typval_T *rettv);
178static void f_getwinposy(typval_T *argvars, typval_T *rettv);
179static void f_getwinvar(typval_T *argvars, typval_T *rettv);
180static void f_glob(typval_T *argvars, typval_T *rettv);
181static void f_globpath(typval_T *argvars, typval_T *rettv);
182static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
183static void f_has(typval_T *argvars, typval_T *rettv);
184static void f_has_key(typval_T *argvars, typval_T *rettv);
185static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
186static void f_hasmapto(typval_T *argvars, typval_T *rettv);
187static void f_histadd(typval_T *argvars, typval_T *rettv);
188static void f_histdel(typval_T *argvars, typval_T *rettv);
189static void f_histget(typval_T *argvars, typval_T *rettv);
190static void f_histnr(typval_T *argvars, typval_T *rettv);
191static void f_hlID(typval_T *argvars, typval_T *rettv);
192static void f_hlexists(typval_T *argvars, typval_T *rettv);
193static void f_hostname(typval_T *argvars, typval_T *rettv);
194static void f_iconv(typval_T *argvars, typval_T *rettv);
195static void f_indent(typval_T *argvars, typval_T *rettv);
196static void f_index(typval_T *argvars, typval_T *rettv);
197static void f_input(typval_T *argvars, typval_T *rettv);
198static void f_inputdialog(typval_T *argvars, typval_T *rettv);
199static void f_inputlist(typval_T *argvars, typval_T *rettv);
200static void f_inputrestore(typval_T *argvars, typval_T *rettv);
201static void f_inputsave(typval_T *argvars, typval_T *rettv);
202static void f_inputsecret(typval_T *argvars, typval_T *rettv);
203static void f_insert(typval_T *argvars, typval_T *rettv);
204static void f_invert(typval_T *argvars, typval_T *rettv);
205static void f_isdirectory(typval_T *argvars, typval_T *rettv);
206static void f_islocked(typval_T *argvars, typval_T *rettv);
207#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200208static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_isnan(typval_T *argvars, typval_T *rettv);
210#endif
211static void f_items(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212static void f_join(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_keys(typval_T *argvars, typval_T *rettv);
214static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
215static void f_len(typval_T *argvars, typval_T *rettv);
216static void f_libcall(typval_T *argvars, typval_T *rettv);
217static void f_libcallnr(typval_T *argvars, typval_T *rettv);
218static void f_line(typval_T *argvars, typval_T *rettv);
219static void f_line2byte(typval_T *argvars, typval_T *rettv);
220static void f_lispindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar9d401282019-04-06 13:18:12 +0200221static void f_list2str(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_localtime(typval_T *argvars, typval_T *rettv);
223#ifdef FEAT_FLOAT
224static void f_log(typval_T *argvars, typval_T *rettv);
225static void f_log10(typval_T *argvars, typval_T *rettv);
226#endif
227#ifdef FEAT_LUA
228static void f_luaeval(typval_T *argvars, typval_T *rettv);
229#endif
230static void f_map(typval_T *argvars, typval_T *rettv);
231static void f_maparg(typval_T *argvars, typval_T *rettv);
232static void f_mapcheck(typval_T *argvars, typval_T *rettv);
233static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_matchend(typval_T *argvars, typval_T *rettv);
235static void f_matchlist(typval_T *argvars, typval_T *rettv);
236static void f_matchstr(typval_T *argvars, typval_T *rettv);
237static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
238static void f_max(typval_T *argvars, typval_T *rettv);
239static void f_min(typval_T *argvars, typval_T *rettv);
240#ifdef vim_mkdir
241static void f_mkdir(typval_T *argvars, typval_T *rettv);
242#endif
243static void f_mode(typval_T *argvars, typval_T *rettv);
244#ifdef FEAT_MZSCHEME
245static void f_mzeval(typval_T *argvars, typval_T *rettv);
246#endif
247static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
248static void f_nr2char(typval_T *argvars, typval_T *rettv);
249static void f_or(typval_T *argvars, typval_T *rettv);
250static void f_pathshorten(typval_T *argvars, typval_T *rettv);
251#ifdef FEAT_PERL
252static void f_perleval(typval_T *argvars, typval_T *rettv);
253#endif
254#ifdef FEAT_FLOAT
255static void f_pow(typval_T *argvars, typval_T *rettv);
256#endif
257static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
258static void f_printf(typval_T *argvars, typval_T *rettv);
259static void f_pumvisible(typval_T *argvars, typval_T *rettv);
260#ifdef FEAT_PYTHON3
261static void f_py3eval(typval_T *argvars, typval_T *rettv);
262#endif
263#ifdef FEAT_PYTHON
264static void f_pyeval(typval_T *argvars, typval_T *rettv);
265#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100266#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
267static void f_pyxeval(typval_T *argvars, typval_T *rettv);
268#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200269static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200270static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200271static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200272static void f_reg_executing(typval_T *argvars, typval_T *rettv);
273static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200274static void f_reltime(typval_T *argvars, typval_T *rettv);
275#ifdef FEAT_FLOAT
276static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
277#endif
278static void f_reltimestr(typval_T *argvars, typval_T *rettv);
279static void f_remote_expr(typval_T *argvars, typval_T *rettv);
280static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
281static void f_remote_peek(typval_T *argvars, typval_T *rettv);
282static void f_remote_read(typval_T *argvars, typval_T *rettv);
283static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100284static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200285static void f_remove(typval_T *argvars, typval_T *rettv);
286static void f_rename(typval_T *argvars, typval_T *rettv);
287static void f_repeat(typval_T *argvars, typval_T *rettv);
288static void f_resolve(typval_T *argvars, typval_T *rettv);
289static void f_reverse(typval_T *argvars, typval_T *rettv);
290#ifdef FEAT_FLOAT
291static void f_round(typval_T *argvars, typval_T *rettv);
292#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100293#ifdef FEAT_RUBY
294static void f_rubyeval(typval_T *argvars, typval_T *rettv);
295#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296static void f_screenattr(typval_T *argvars, typval_T *rettv);
297static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100298static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299static void f_screencol(typval_T *argvars, typval_T *rettv);
300static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100301static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_search(typval_T *argvars, typval_T *rettv);
303static void f_searchdecl(typval_T *argvars, typval_T *rettv);
304static void f_searchpair(typval_T *argvars, typval_T *rettv);
305static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
306static void f_searchpos(typval_T *argvars, typval_T *rettv);
307static void f_server2client(typval_T *argvars, typval_T *rettv);
308static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200309static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310static void f_setbufvar(typval_T *argvars, typval_T *rettv);
311static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
312static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200313static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200314static void f_setfperm(typval_T *argvars, typval_T *rettv);
315static void f_setline(typval_T *argvars, typval_T *rettv);
316static void f_setloclist(typval_T *argvars, typval_T *rettv);
317static void f_setmatches(typval_T *argvars, typval_T *rettv);
318static void f_setpos(typval_T *argvars, typval_T *rettv);
319static void f_setqflist(typval_T *argvars, typval_T *rettv);
320static void f_setreg(typval_T *argvars, typval_T *rettv);
321static void f_settabvar(typval_T *argvars, typval_T *rettv);
322static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100323static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200324static void f_setwinvar(typval_T *argvars, typval_T *rettv);
325#ifdef FEAT_CRYPT
326static void f_sha256(typval_T *argvars, typval_T *rettv);
327#endif /* FEAT_CRYPT */
328static void f_shellescape(typval_T *argvars, typval_T *rettv);
329static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
330static void f_simplify(typval_T *argvars, typval_T *rettv);
331#ifdef FEAT_FLOAT
332static void f_sin(typval_T *argvars, typval_T *rettv);
333static void f_sinh(typval_T *argvars, typval_T *rettv);
334#endif
335static void f_sort(typval_T *argvars, typval_T *rettv);
336static void f_soundfold(typval_T *argvars, typval_T *rettv);
337static void f_spellbadword(typval_T *argvars, typval_T *rettv);
338static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
339static void f_split(typval_T *argvars, typval_T *rettv);
340#ifdef FEAT_FLOAT
341static void f_sqrt(typval_T *argvars, typval_T *rettv);
342static void f_str2float(typval_T *argvars, typval_T *rettv);
343#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200344static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200345static void f_str2nr(typval_T *argvars, typval_T *rettv);
346static void f_strchars(typval_T *argvars, typval_T *rettv);
347#ifdef HAVE_STRFTIME
348static void f_strftime(typval_T *argvars, typval_T *rettv);
349#endif
350static void f_strgetchar(typval_T *argvars, typval_T *rettv);
351static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352static void f_strlen(typval_T *argvars, typval_T *rettv);
353static void f_strcharpart(typval_T *argvars, typval_T *rettv);
354static void f_strpart(typval_T *argvars, typval_T *rettv);
355static void f_strridx(typval_T *argvars, typval_T *rettv);
356static void f_strtrans(typval_T *argvars, typval_T *rettv);
357static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
358static void f_strwidth(typval_T *argvars, typval_T *rettv);
359static void f_submatch(typval_T *argvars, typval_T *rettv);
360static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200361static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200362static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200363static void f_synID(typval_T *argvars, typval_T *rettv);
364static void f_synIDattr(typval_T *argvars, typval_T *rettv);
365static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
366static void f_synstack(typval_T *argvars, typval_T *rettv);
367static void f_synconcealed(typval_T *argvars, typval_T *rettv);
368static void f_system(typval_T *argvars, typval_T *rettv);
369static void f_systemlist(typval_T *argvars, typval_T *rettv);
370static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
371static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
372static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
373static void f_taglist(typval_T *argvars, typval_T *rettv);
374static void f_tagfiles(typval_T *argvars, typval_T *rettv);
375static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200376#ifdef FEAT_FLOAT
377static void f_tan(typval_T *argvars, typval_T *rettv);
378static void f_tanh(typval_T *argvars, typval_T *rettv);
379#endif
380#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200381static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200382static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200383static void f_timer_start(typval_T *argvars, typval_T *rettv);
384static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200385static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200386#endif
387static void f_tolower(typval_T *argvars, typval_T *rettv);
388static void f_toupper(typval_T *argvars, typval_T *rettv);
389static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100390static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
392static void f_trunc(typval_T *argvars, typval_T *rettv);
393#endif
394static void f_type(typval_T *argvars, typval_T *rettv);
395static void f_undofile(typval_T *argvars, typval_T *rettv);
396static void f_undotree(typval_T *argvars, typval_T *rettv);
397static void f_uniq(typval_T *argvars, typval_T *rettv);
398static void f_values(typval_T *argvars, typval_T *rettv);
399static void f_virtcol(typval_T *argvars, typval_T *rettv);
400static void f_visualmode(typval_T *argvars, typval_T *rettv);
401static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200402static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200403static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
404static void f_win_getid(typval_T *argvars, typval_T *rettv);
405static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
406static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
407static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100408static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409static void f_winbufnr(typval_T *argvars, typval_T *rettv);
410static void f_wincol(typval_T *argvars, typval_T *rettv);
411static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200412static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200413static void f_winline(typval_T *argvars, typval_T *rettv);
414static void f_winnr(typval_T *argvars, typval_T *rettv);
415static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
416static void f_winrestview(typval_T *argvars, typval_T *rettv);
417static void f_winsaveview(typval_T *argvars, typval_T *rettv);
418static void f_winwidth(typval_T *argvars, typval_T *rettv);
419static void f_writefile(typval_T *argvars, typval_T *rettv);
420static void f_wordcount(typval_T *argvars, typval_T *rettv);
421static void f_xor(typval_T *argvars, typval_T *rettv);
422
423/*
424 * Array with names and number of arguments of all internal functions
425 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
426 */
427static struct fst
428{
429 char *f_name; /* function name */
430 char f_min_argc; /* minimal number of arguments */
431 char f_max_argc; /* maximal number of arguments */
432 void (*f_func)(typval_T *args, typval_T *rvar);
433 /* implementation of function */
434} functions[] =
435{
436#ifdef FEAT_FLOAT
437 {"abs", 1, 1, f_abs},
438 {"acos", 1, 1, f_acos}, /* WJMc */
439#endif
440 {"add", 2, 2, f_add},
441 {"and", 2, 2, f_and},
442 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200443 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200444 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200445 {"argidx", 0, 0, f_argidx},
446 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200447 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200448#ifdef FEAT_FLOAT
449 {"asin", 1, 1, f_asin}, /* WJMc */
450#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100451 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200452 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100453 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200454 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200455 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200456 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100457 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200458 {"assert_match", 2, 3, f_assert_match},
459 {"assert_notequal", 2, 3, f_assert_notequal},
460 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100461 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200462 {"assert_true", 1, 2, f_assert_true},
463#ifdef FEAT_FLOAT
464 {"atan", 1, 1, f_atan},
465 {"atan2", 2, 2, f_atan2},
466#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100467#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +0200468 {"balloon_gettext", 0, 0, f_balloon_gettext},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100469 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100470# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100471 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100472# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200474 {"browse", 4, 4, f_browse},
475 {"browsedir", 2, 2, f_browsedir},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200476 {"bufadd", 1, 1, f_bufadd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200477 {"bufexists", 1, 1, f_bufexists},
478 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
479 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
480 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
481 {"buflisted", 1, 1, f_buflisted},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200482 {"bufload", 1, 1, f_bufload},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200483 {"bufloaded", 1, 1, f_bufloaded},
484 {"bufname", 1, 1, f_bufname},
485 {"bufnr", 1, 2, f_bufnr},
486 {"bufwinid", 1, 1, f_bufwinid},
487 {"bufwinnr", 1, 1, f_bufwinnr},
488 {"byte2line", 1, 1, f_byte2line},
489 {"byteidx", 2, 2, f_byteidx},
490 {"byteidxcomp", 2, 2, f_byteidxcomp},
491 {"call", 2, 3, f_call},
492#ifdef FEAT_FLOAT
493 {"ceil", 1, 1, f_ceil},
494#endif
495#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100496 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200497 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200498 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200499 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
500 {"ch_evalraw", 2, 3, f_ch_evalraw},
501 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
502 {"ch_getjob", 1, 1, f_ch_getjob},
503 {"ch_info", 1, 1, f_ch_info},
504 {"ch_log", 1, 2, f_ch_log},
505 {"ch_logfile", 1, 2, f_ch_logfile},
506 {"ch_open", 1, 2, f_ch_open},
507 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100508 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509 {"ch_readraw", 1, 2, f_ch_readraw},
510 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
511 {"ch_sendraw", 2, 3, f_ch_sendraw},
512 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200513 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200514#endif
515 {"changenr", 0, 0, f_changenr},
516 {"char2nr", 1, 2, f_char2nr},
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200517 {"chdir", 1, 1, f_chdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200518 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100519 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520 {"col", 1, 1, f_col},
521#if defined(FEAT_INS_EXPAND)
522 {"complete", 2, 2, f_complete},
523 {"complete_add", 1, 1, f_complete_add},
524 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100525 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#endif
527 {"confirm", 1, 4, f_confirm},
528 {"copy", 1, 1, f_copy},
529#ifdef FEAT_FLOAT
530 {"cos", 1, 1, f_cos},
531 {"cosh", 1, 1, f_cosh},
532#endif
533 {"count", 2, 4, f_count},
534 {"cscope_connection",0,3, f_cscope_connection},
535 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100536#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200537 {"debugbreak", 1, 1, f_debugbreak},
538#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200539 {"deepcopy", 1, 2, f_deepcopy},
540 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200541 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200542 {"did_filetype", 0, 0, f_did_filetype},
543 {"diff_filler", 1, 1, f_diff_filler},
544 {"diff_hlID", 2, 2, f_diff_hlID},
545 {"empty", 1, 1, f_empty},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200546 {"environ", 0, 0, f_environ},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547 {"escape", 2, 2, f_escape},
548 {"eval", 1, 1, f_eval},
549 {"eventhandler", 0, 0, f_eventhandler},
550 {"executable", 1, 1, f_executable},
551 {"execute", 1, 2, f_execute},
552 {"exepath", 1, 1, f_exepath},
553 {"exists", 1, 1, f_exists},
554#ifdef FEAT_FLOAT
555 {"exp", 1, 1, f_exp},
556#endif
557 {"expand", 1, 3, f_expand},
Bram Moolenaar80dad482019-06-09 17:22:31 +0200558 {"expandcmd", 1, 1, f_expandcmd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200559 {"extend", 2, 3, f_extend},
560 {"feedkeys", 1, 2, f_feedkeys},
561 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
562 {"filereadable", 1, 1, f_filereadable},
563 {"filewritable", 1, 1, f_filewritable},
564 {"filter", 2, 2, f_filter},
565 {"finddir", 1, 3, f_finddir},
566 {"findfile", 1, 3, f_findfile},
567#ifdef FEAT_FLOAT
568 {"float2nr", 1, 1, f_float2nr},
569 {"floor", 1, 1, f_floor},
570 {"fmod", 2, 2, f_fmod},
571#endif
572 {"fnameescape", 1, 1, f_fnameescape},
573 {"fnamemodify", 2, 2, f_fnamemodify},
574 {"foldclosed", 1, 1, f_foldclosed},
575 {"foldclosedend", 1, 1, f_foldclosedend},
576 {"foldlevel", 1, 1, f_foldlevel},
577 {"foldtext", 0, 0, f_foldtext},
578 {"foldtextresult", 1, 1, f_foldtextresult},
579 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200580 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581 {"function", 1, 3, f_function},
582 {"garbagecollect", 0, 1, f_garbagecollect},
583 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200584 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200585 {"getbufline", 2, 3, f_getbufline},
586 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100587 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588 {"getchar", 0, 1, f_getchar},
589 {"getcharmod", 0, 0, f_getcharmod},
590 {"getcharsearch", 0, 0, f_getcharsearch},
591 {"getcmdline", 0, 0, f_getcmdline},
592 {"getcmdpos", 0, 0, f_getcmdpos},
593 {"getcmdtype", 0, 0, f_getcmdtype},
594 {"getcmdwintype", 0, 0, f_getcmdwintype},
595#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200596 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200597#endif
598 {"getcurpos", 0, 0, f_getcurpos},
599 {"getcwd", 0, 2, f_getcwd},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200600 {"getenv", 1, 1, f_getenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601 {"getfontname", 0, 1, f_getfontname},
602 {"getfperm", 1, 1, f_getfperm},
603 {"getfsize", 1, 1, f_getfsize},
604 {"getftime", 1, 1, f_getftime},
605 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100606 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200607 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200608 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100609 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610 {"getpid", 0, 0, f_getpid},
611 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200612 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613 {"getreg", 0, 3, f_getreg},
614 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200615 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200616 {"gettabvar", 2, 3, f_gettabvar},
617 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100618 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200619 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100620 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200621 {"getwinposx", 0, 0, f_getwinposx},
622 {"getwinposy", 0, 0, f_getwinposy},
623 {"getwinvar", 2, 3, f_getwinvar},
624 {"glob", 1, 4, f_glob},
625 {"glob2regpat", 1, 1, f_glob2regpat},
626 {"globpath", 2, 5, f_globpath},
627 {"has", 1, 1, f_has},
628 {"has_key", 2, 2, f_has_key},
629 {"haslocaldir", 0, 2, f_haslocaldir},
630 {"hasmapto", 1, 3, f_hasmapto},
631 {"highlightID", 1, 1, f_hlID}, /* obsolete */
632 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
633 {"histadd", 2, 2, f_histadd},
634 {"histdel", 1, 2, f_histdel},
635 {"histget", 1, 2, f_histget},
636 {"histnr", 1, 1, f_histnr},
637 {"hlID", 1, 1, f_hlID},
638 {"hlexists", 1, 1, f_hlexists},
639 {"hostname", 0, 0, f_hostname},
640 {"iconv", 3, 3, f_iconv},
641 {"indent", 1, 1, f_indent},
642 {"index", 2, 4, f_index},
643 {"input", 1, 3, f_input},
644 {"inputdialog", 1, 3, f_inputdialog},
645 {"inputlist", 1, 1, f_inputlist},
646 {"inputrestore", 0, 0, f_inputrestore},
647 {"inputsave", 0, 0, f_inputsave},
648 {"inputsecret", 1, 2, f_inputsecret},
649 {"insert", 2, 3, f_insert},
650 {"invert", 1, 1, f_invert},
651 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200652#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
653 {"isinf", 1, 1, f_isinf},
654#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655 {"islocked", 1, 1, f_islocked},
656#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
657 {"isnan", 1, 1, f_isnan},
658#endif
659 {"items", 1, 1, f_items},
660#ifdef FEAT_JOB_CHANNEL
661 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200662 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200663 {"job_setoptions", 2, 2, f_job_setoptions},
664 {"job_start", 1, 2, f_job_start},
665 {"job_status", 1, 1, f_job_status},
666 {"job_stop", 1, 2, f_job_stop},
667#endif
668 {"join", 1, 2, f_join},
669 {"js_decode", 1, 1, f_js_decode},
670 {"js_encode", 1, 1, f_js_encode},
671 {"json_decode", 1, 1, f_json_decode},
672 {"json_encode", 1, 1, f_json_encode},
673 {"keys", 1, 1, f_keys},
674 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
675 {"len", 1, 1, f_len},
676 {"libcall", 3, 3, f_libcall},
677 {"libcallnr", 3, 3, f_libcallnr},
678 {"line", 1, 1, f_line},
679 {"line2byte", 1, 1, f_line2byte},
680 {"lispindent", 1, 1, f_lispindent},
Bram Moolenaar9d401282019-04-06 13:18:12 +0200681 {"list2str", 1, 2, f_list2str},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200682 {"listener_add", 1, 2, f_listener_add},
Bram Moolenaarfe1ade02019-05-14 21:20:36 +0200683 {"listener_flush", 0, 1, f_listener_flush},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200684 {"listener_remove", 1, 1, f_listener_remove},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685 {"localtime", 0, 0, f_localtime},
686#ifdef FEAT_FLOAT
687 {"log", 1, 1, f_log},
688 {"log10", 1, 1, f_log10},
689#endif
690#ifdef FEAT_LUA
691 {"luaeval", 1, 2, f_luaeval},
692#endif
693 {"map", 2, 2, f_map},
694 {"maparg", 1, 4, f_maparg},
695 {"mapcheck", 1, 3, f_mapcheck},
696 {"match", 2, 4, f_match},
697 {"matchadd", 2, 5, f_matchadd},
698 {"matchaddpos", 2, 5, f_matchaddpos},
699 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100700 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200701 {"matchend", 2, 4, f_matchend},
702 {"matchlist", 2, 4, f_matchlist},
703 {"matchstr", 2, 4, f_matchstr},
704 {"matchstrpos", 2, 4, f_matchstrpos},
705 {"max", 1, 1, f_max},
706 {"min", 1, 1, f_min},
707#ifdef vim_mkdir
708 {"mkdir", 1, 3, f_mkdir},
709#endif
710 {"mode", 0, 1, f_mode},
711#ifdef FEAT_MZSCHEME
712 {"mzeval", 1, 1, f_mzeval},
713#endif
714 {"nextnonblank", 1, 1, f_nextnonblank},
715 {"nr2char", 1, 2, f_nr2char},
716 {"or", 2, 2, f_or},
717 {"pathshorten", 1, 1, f_pathshorten},
718#ifdef FEAT_PERL
719 {"perleval", 1, 1, f_perleval},
720#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200721#ifdef FEAT_TEXT_PROP
Bram Moolenaarcc31ad92019-05-30 19:25:06 +0200722 {"popup_atcursor", 2, 2, f_popup_atcursor},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200723 {"popup_beval", 2, 2, f_popup_beval},
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200724 {"popup_clear", 0, 0, f_popup_clear},
Bram Moolenaar9eaac892019-06-01 22:49:29 +0200725 {"popup_close", 1, 2, f_popup_close},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200726 {"popup_create", 2, 2, f_popup_create},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200727 {"popup_dialog", 2, 2, f_popup_dialog},
Bram Moolenaara730e552019-06-16 19:05:31 +0200728 {"popup_filter_menu", 2, 2, f_popup_filter_menu},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200729 {"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
Bram Moolenaar8c2a6002019-05-30 14:29:45 +0200730 {"popup_getoptions", 1, 1, f_popup_getoptions},
Bram Moolenaarccd6e342019-05-30 22:35:18 +0200731 {"popup_getpos", 1, 1, f_popup_getpos},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200732 {"popup_hide", 1, 1, f_popup_hide},
Bram Moolenaarb4f06282019-07-12 21:07:54 +0200733 {"popup_locate", 2, 2, f_popup_locate},
Bram Moolenaara730e552019-06-16 19:05:31 +0200734 {"popup_menu", 2, 2, f_popup_menu},
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200735 {"popup_move", 2, 2, f_popup_move},
Bram Moolenaar68d48f42019-06-12 22:42:41 +0200736 {"popup_notification", 2, 2, f_popup_notification},
Bram Moolenaarae943152019-06-16 22:54:14 +0200737 {"popup_setoptions", 2, 2, f_popup_setoptions},
Bram Moolenaardc2ce582019-06-16 15:32:14 +0200738 {"popup_settext", 2, 2, f_popup_settext},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200739 {"popup_show", 1, 1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200740#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#ifdef FEAT_FLOAT
742 {"pow", 2, 2, f_pow},
743#endif
744 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100745 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200746#ifdef FEAT_JOB_CHANNEL
747 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200748 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200749 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
750#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100751#ifdef FEAT_TEXT_PROP
752 {"prop_add", 3, 3, f_prop_add},
753 {"prop_clear", 1, 3, f_prop_clear},
754 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100755 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100756 {"prop_type_add", 2, 2, f_prop_type_add},
757 {"prop_type_change", 2, 2, f_prop_type_change},
758 {"prop_type_delete", 1, 2, f_prop_type_delete},
759 {"prop_type_get", 1, 2, f_prop_type_get},
760 {"prop_type_list", 0, 1, f_prop_type_list},
761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762 {"pumvisible", 0, 0, f_pumvisible},
763#ifdef FEAT_PYTHON3
764 {"py3eval", 1, 1, f_py3eval},
765#endif
766#ifdef FEAT_PYTHON
767 {"pyeval", 1, 1, f_pyeval},
768#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100769#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
770 {"pyxeval", 1, 1, f_pyxeval},
771#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200773 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200774 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200775 {"reg_executing", 0, 0, f_reg_executing},
776 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777 {"reltime", 0, 2, f_reltime},
778#ifdef FEAT_FLOAT
779 {"reltimefloat", 1, 1, f_reltimefloat},
780#endif
781 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100782 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783 {"remote_foreground", 1, 1, f_remote_foreground},
784 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100785 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200786 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100787 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"remove", 2, 3, f_remove},
789 {"rename", 2, 2, f_rename},
790 {"repeat", 2, 2, f_repeat},
791 {"resolve", 1, 1, f_resolve},
792 {"reverse", 1, 1, f_reverse},
793#ifdef FEAT_FLOAT
794 {"round", 1, 1, f_round},
795#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100796#ifdef FEAT_RUBY
797 {"rubyeval", 1, 1, f_rubyeval},
798#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200799 {"screenattr", 2, 2, f_screenattr},
800 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100801 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200802 {"screencol", 0, 0, f_screencol},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200803 {"screenpos", 3, 3, f_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100805 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806 {"search", 1, 4, f_search},
807 {"searchdecl", 1, 3, f_searchdecl},
808 {"searchpair", 3, 7, f_searchpair},
809 {"searchpairpos", 3, 7, f_searchpairpos},
810 {"searchpos", 1, 4, f_searchpos},
811 {"server2client", 2, 2, f_server2client},
812 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200813 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814 {"setbufvar", 3, 3, f_setbufvar},
815 {"setcharsearch", 1, 1, f_setcharsearch},
816 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200817 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200818 {"setfperm", 2, 2, f_setfperm},
819 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200820 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100821 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200823 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824 {"setreg", 2, 3, f_setreg},
825 {"settabvar", 3, 3, f_settabvar},
826 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100827 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200828 {"setwinvar", 3, 3, f_setwinvar},
829#ifdef FEAT_CRYPT
830 {"sha256", 1, 1, f_sha256},
831#endif
832 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100833 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100834#ifdef FEAT_SIGNS
835 {"sign_define", 1, 2, f_sign_define},
836 {"sign_getdefined", 0, 1, f_sign_getdefined},
837 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100838 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100839 {"sign_place", 4, 5, f_sign_place},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200840 {"sign_placelist", 1, 1, f_sign_placelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100841 {"sign_undefine", 0, 1, f_sign_undefine},
842 {"sign_unplace", 1, 2, f_sign_unplace},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200843 {"sign_unplacelist", 1, 2, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100844#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200845 {"simplify", 1, 1, f_simplify},
846#ifdef FEAT_FLOAT
847 {"sin", 1, 1, f_sin},
848 {"sinh", 1, 1, f_sinh},
849#endif
850 {"sort", 1, 3, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200851#ifdef FEAT_SOUND
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200852 {"sound_clear", 0, 0, f_sound_clear},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200853 {"sound_playevent", 1, 2, f_sound_playevent},
854 {"sound_playfile", 1, 2, f_sound_playfile},
855 {"sound_stop", 1, 1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200856#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200857 {"soundfold", 1, 1, f_soundfold},
858 {"spellbadword", 0, 1, f_spellbadword},
859 {"spellsuggest", 1, 3, f_spellsuggest},
860 {"split", 1, 3, f_split},
861#ifdef FEAT_FLOAT
862 {"sqrt", 1, 1, f_sqrt},
863 {"str2float", 1, 1, f_str2float},
864#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200865 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866 {"str2nr", 1, 2, f_str2nr},
867 {"strcharpart", 2, 3, f_strcharpart},
868 {"strchars", 1, 2, f_strchars},
869 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
870#ifdef HAVE_STRFTIME
871 {"strftime", 1, 2, f_strftime},
872#endif
873 {"strgetchar", 2, 2, f_strgetchar},
874 {"stridx", 2, 3, f_stridx},
875 {"string", 1, 1, f_string},
876 {"strlen", 1, 1, f_strlen},
877 {"strpart", 2, 3, f_strpart},
878 {"strridx", 2, 3, f_strridx},
879 {"strtrans", 1, 1, f_strtrans},
880 {"strwidth", 1, 1, f_strwidth},
881 {"submatch", 1, 2, f_submatch},
882 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200883 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200884 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200885 {"synID", 3, 3, f_synID},
886 {"synIDattr", 2, 3, f_synIDattr},
887 {"synIDtrans", 1, 1, f_synIDtrans},
888 {"synconcealed", 2, 2, f_synconcealed},
889 {"synstack", 2, 2, f_synstack},
890 {"system", 1, 2, f_system},
891 {"systemlist", 1, 2, f_systemlist},
892 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
893 {"tabpagenr", 0, 1, f_tabpagenr},
894 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
895 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100896 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200897#ifdef FEAT_FLOAT
898 {"tan", 1, 1, f_tan},
899 {"tanh", 1, 1, f_tanh},
900#endif
901 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200902#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100903 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
904 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100905 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200906 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200907# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
908 {"term_getansicolors", 1, 1, f_term_getansicolors},
909# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200910 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200911 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200912 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200913 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200914 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200915 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200916 {"term_getstatus", 1, 1, f_term_getstatus},
917 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200918 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200919 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200920 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200921 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200922# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
923 {"term_setansicolors", 2, 2, f_term_setansicolors},
924# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100925 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100926 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200927 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200928 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200929 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200930#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
932 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200933 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200934 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaaradc67142019-06-22 01:40:42 +0200935 {"test_garbagecollect_soon", 0, 0, f_test_garbagecollect_soon},
Bram Moolenaareda65222019-05-16 20:29:44 +0200936 {"test_getvalue", 1, 1, f_test_getvalue},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100937 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100938 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939#ifdef FEAT_JOB_CHANNEL
940 {"test_null_channel", 0, 0, f_test_null_channel},
941#endif
942 {"test_null_dict", 0, 0, f_test_null_dict},
943#ifdef FEAT_JOB_CHANNEL
944 {"test_null_job", 0, 0, f_test_null_job},
945#endif
946 {"test_null_list", 0, 0, f_test_null_list},
947 {"test_null_partial", 0, 0, f_test_null_partial},
948 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200949 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100950 {"test_override", 2, 2, f_test_override},
951 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200952#ifdef FEAT_GUI
953 {"test_scrollbar", 3, 3, f_test_scrollbar},
954#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200955#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +0200956 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200957#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200958 {"test_settime", 1, 1, f_test_settime},
959#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200960 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200961 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962 {"timer_start", 2, 3, f_timer_start},
963 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200964 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965#endif
966 {"tolower", 1, 1, f_tolower},
967 {"toupper", 1, 1, f_toupper},
968 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100969 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970#ifdef FEAT_FLOAT
971 {"trunc", 1, 1, f_trunc},
972#endif
973 {"type", 1, 1, f_type},
974 {"undofile", 1, 1, f_undofile},
975 {"undotree", 0, 0, f_undotree},
976 {"uniq", 1, 3, f_uniq},
977 {"values", 1, 1, f_values},
978 {"virtcol", 1, 1, f_virtcol},
979 {"visualmode", 0, 1, f_visualmode},
980 {"wildmenumode", 0, 0, f_wildmenumode},
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200981 {"win_execute", 2, 3, f_win_execute},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200982 {"win_findbuf", 1, 1, f_win_findbuf},
983 {"win_getid", 0, 2, f_win_getid},
984 {"win_gotoid", 1, 1, f_win_gotoid},
985 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
986 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100987 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200988 {"winbufnr", 1, 1, f_winbufnr},
989 {"wincol", 0, 0, f_wincol},
990 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200991 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200992 {"winline", 0, 0, f_winline},
993 {"winnr", 0, 1, f_winnr},
994 {"winrestcmd", 0, 0, f_winrestcmd},
995 {"winrestview", 1, 1, f_winrestview},
996 {"winsaveview", 0, 0, f_winsaveview},
997 {"winwidth", 1, 1, f_winwidth},
998 {"wordcount", 0, 0, f_wordcount},
999 {"writefile", 2, 3, f_writefile},
1000 {"xor", 2, 2, f_xor},
1001};
1002
1003#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1004
1005/*
1006 * Function given to ExpandGeneric() to obtain the list of internal
1007 * or user defined function names.
1008 */
1009 char_u *
1010get_function_name(expand_T *xp, int idx)
1011{
1012 static int intidx = -1;
1013 char_u *name;
1014
1015 if (idx == 0)
1016 intidx = -1;
1017 if (intidx < 0)
1018 {
1019 name = get_user_func_name(xp, idx);
1020 if (name != NULL)
1021 return name;
1022 }
1023 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1024 {
1025 STRCPY(IObuff, functions[intidx].f_name);
1026 STRCAT(IObuff, "(");
1027 if (functions[intidx].f_max_argc == 0)
1028 STRCAT(IObuff, ")");
1029 return IObuff;
1030 }
1031
1032 return NULL;
1033}
1034
1035/*
1036 * Function given to ExpandGeneric() to obtain the list of internal or
1037 * user defined variable or function names.
1038 */
1039 char_u *
1040get_expr_name(expand_T *xp, int idx)
1041{
1042 static int intidx = -1;
1043 char_u *name;
1044
1045 if (idx == 0)
1046 intidx = -1;
1047 if (intidx < 0)
1048 {
1049 name = get_function_name(xp, idx);
1050 if (name != NULL)
1051 return name;
1052 }
1053 return get_user_var_name(xp, ++intidx);
1054}
1055
1056#endif /* FEAT_CMDL_COMPL */
1057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001058/*
1059 * Find internal function in table above.
1060 * Return index, or -1 if not found
1061 */
1062 int
1063find_internal_func(
1064 char_u *name) /* name of the function */
1065{
1066 int first = 0;
1067 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1068 int cmp;
1069 int x;
1070
1071 /*
1072 * Find the function name in the table. Binary search.
1073 */
1074 while (first <= last)
1075 {
1076 x = first + ((unsigned)(last - first) >> 1);
1077 cmp = STRCMP(name, functions[x].f_name);
1078 if (cmp < 0)
1079 last = x - 1;
1080 else if (cmp > 0)
1081 first = x + 1;
1082 else
1083 return x;
1084 }
1085 return -1;
1086}
1087
1088 int
1089call_internal_func(
1090 char_u *name,
1091 int argcount,
1092 typval_T *argvars,
1093 typval_T *rettv)
1094{
1095 int i;
1096
1097 i = find_internal_func(name);
1098 if (i < 0)
1099 return ERROR_UNKNOWN;
1100 if (argcount < functions[i].f_min_argc)
1101 return ERROR_TOOFEW;
1102 if (argcount > functions[i].f_max_argc)
1103 return ERROR_TOOMANY;
1104 argvars[argcount].v_type = VAR_UNKNOWN;
1105 functions[i].f_func(argvars, rettv);
1106 return ERROR_NONE;
1107}
1108
1109/*
1110 * Return TRUE for a non-zero Number and a non-empty String.
1111 */
1112 static int
1113non_zero_arg(typval_T *argvars)
1114{
1115 return ((argvars[0].v_type == VAR_NUMBER
1116 && argvars[0].vval.v_number != 0)
1117 || (argvars[0].v_type == VAR_SPECIAL
1118 && argvars[0].vval.v_number == VVAL_TRUE)
1119 || (argvars[0].v_type == VAR_STRING
1120 && argvars[0].vval.v_string != NULL
1121 && *argvars[0].vval.v_string != NUL));
1122}
1123
1124/*
1125 * Get the lnum from the first argument.
1126 * Also accepts ".", "$", etc., but that only works for the current buffer.
1127 * Returns -1 on error.
1128 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001129 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001130tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001131{
1132 typval_T rettv;
1133 linenr_T lnum;
1134
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001135 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001136 if (lnum == 0) /* no valid number, try using line() */
1137 {
1138 rettv.v_type = VAR_NUMBER;
1139 f_line(argvars, &rettv);
1140 lnum = (linenr_T)rettv.vval.v_number;
1141 clear_tv(&rettv);
1142 }
1143 return lnum;
1144}
1145
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001146/*
1147 * Get the lnum from the first argument.
1148 * Also accepts "$", then "buf" is used.
1149 * Returns 0 on error.
1150 */
1151 static linenr_T
1152tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1153{
1154 if (argvars[0].v_type == VAR_STRING
1155 && argvars[0].vval.v_string != NULL
1156 && argvars[0].vval.v_string[0] == '$'
1157 && buf != NULL)
1158 return buf->b_ml.ml_line_count;
1159 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1160}
1161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001162#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163/*
1164 * Get the float value of "argvars[0]" into "f".
1165 * Returns FAIL when the argument is not a Number or Float.
1166 */
1167 static int
1168get_float_arg(typval_T *argvars, float_T *f)
1169{
1170 if (argvars[0].v_type == VAR_FLOAT)
1171 {
1172 *f = argvars[0].vval.v_float;
1173 return OK;
1174 }
1175 if (argvars[0].v_type == VAR_NUMBER)
1176 {
1177 *f = (float_T)argvars[0].vval.v_number;
1178 return OK;
1179 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001180 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001181 return FAIL;
1182}
1183
1184/*
1185 * "abs(expr)" function
1186 */
1187 static void
1188f_abs(typval_T *argvars, typval_T *rettv)
1189{
1190 if (argvars[0].v_type == VAR_FLOAT)
1191 {
1192 rettv->v_type = VAR_FLOAT;
1193 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1194 }
1195 else
1196 {
1197 varnumber_T n;
1198 int error = FALSE;
1199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001200 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001201 if (error)
1202 rettv->vval.v_number = -1;
1203 else if (n > 0)
1204 rettv->vval.v_number = n;
1205 else
1206 rettv->vval.v_number = -n;
1207 }
1208}
1209
1210/*
1211 * "acos()" function
1212 */
1213 static void
1214f_acos(typval_T *argvars, typval_T *rettv)
1215{
1216 float_T f = 0.0;
1217
1218 rettv->v_type = VAR_FLOAT;
1219 if (get_float_arg(argvars, &f) == OK)
1220 rettv->vval.v_float = acos(f);
1221 else
1222 rettv->vval.v_float = 0.0;
1223}
1224#endif
1225
1226/*
1227 * "add(list, item)" function
1228 */
1229 static void
1230f_add(typval_T *argvars, typval_T *rettv)
1231{
1232 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001233 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234
1235 rettv->vval.v_number = 1; /* Default: Failed */
1236 if (argvars[0].v_type == VAR_LIST)
1237 {
1238 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001239 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001240 (char_u *)N_("add() argument"), TRUE)
1241 && list_append_tv(l, &argvars[1]) == OK)
1242 copy_tv(&argvars[0], rettv);
1243 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001244 else if (argvars[0].v_type == VAR_BLOB)
1245 {
1246 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001247 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001248 (char_u *)N_("add() argument"), TRUE))
1249 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001250 int error = FALSE;
1251 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1252
1253 if (!error)
1254 {
1255 ga_append(&b->bv_ga, (int)n);
1256 copy_tv(&argvars[0], rettv);
1257 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001258 }
1259 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001260 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001261 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262}
1263
1264/*
1265 * "and(expr, expr)" function
1266 */
1267 static void
1268f_and(typval_T *argvars, typval_T *rettv)
1269{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001270 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1271 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001272}
1273
1274/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001275 * If there is a window for "curbuf", make it the current window.
1276 */
1277 static void
1278find_win_for_curbuf(void)
1279{
1280 wininfo_T *wip;
1281
1282 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1283 {
1284 if (wip->wi_win != NULL)
1285 {
1286 curwin = wip->wi_win;
1287 break;
1288 }
1289 }
1290}
1291
1292/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001293 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001294 */
1295 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001296set_buffer_lines(
1297 buf_T *buf,
1298 linenr_T lnum_arg,
1299 int append,
1300 typval_T *lines,
1301 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302{
Bram Moolenaarca851592018-06-06 21:04:07 +02001303 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1304 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 list_T *l = NULL;
1306 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001308 linenr_T append_lnum;
1309 buf_T *curbuf_save = NULL;
1310 win_T *curwin_save = NULL;
1311 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001312
Bram Moolenaarca851592018-06-06 21:04:07 +02001313 /* When using the current buffer ml_mfp will be set if needed. Useful when
1314 * setline() is used on startup. For other buffers the buffer must be
1315 * loaded. */
1316 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001317 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001318 rettv->vval.v_number = 1; /* FAIL */
1319 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001320 }
1321
Bram Moolenaarca851592018-06-06 21:04:07 +02001322 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001323 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001324 curbuf_save = curbuf;
1325 curwin_save = curwin;
1326 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001327 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001328 }
1329
1330 if (append)
1331 // appendbufline() uses the line number below which we insert
1332 append_lnum = lnum - 1;
1333 else
1334 // setbufline() uses the line number above which we insert, we only
1335 // append if it's below the last line
1336 append_lnum = curbuf->b_ml.ml_line_count;
1337
1338 if (lines->v_type == VAR_LIST)
1339 {
1340 l = lines->vval.v_list;
1341 li = l->lv_first;
1342 }
1343 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001344 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001345
1346 /* default result is zero == OK */
1347 for (;;)
1348 {
1349 if (l != NULL)
1350 {
1351 /* list argument, get next string */
1352 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001354 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355 li = li->li_next;
1356 }
1357
Bram Moolenaarca851592018-06-06 21:04:07 +02001358 rettv->vval.v_number = 1; /* FAIL */
1359 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1360 break;
1361
1362 /* When coming here from Insert mode, sync undo, so that this can be
1363 * undone separately from what was previously inserted. */
1364 if (u_sync_once == 2)
1365 {
1366 u_sync_once = 1; /* notify that u_sync() was called */
1367 u_sync(TRUE);
1368 }
1369
1370 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1371 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001372 // Existing line, replace it.
1373 // Removes any existing text properties.
1374 if (u_savesub(lnum) == OK && ml_replace_len(
1375 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001376 {
1377 changed_bytes(lnum, 0);
1378 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1379 check_cursor_col();
1380 rettv->vval.v_number = 0; /* OK */
1381 }
1382 }
1383 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1384 {
1385 /* append the line */
1386 ++added;
1387 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1388 rettv->vval.v_number = 0; /* OK */
1389 }
1390
1391 if (l == NULL) /* only one string argument */
1392 break;
1393 ++lnum;
1394 }
1395
1396 if (added > 0)
1397 {
1398 win_T *wp;
1399 tabpage_T *tp;
1400
1401 appended_lines_mark(append_lnum, added);
1402 FOR_ALL_TAB_WINDOWS(tp, wp)
1403 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1404 wp->w_cursor.lnum += added;
1405 check_cursor_col();
1406
Bram Moolenaarf2732452018-06-03 14:47:35 +02001407#ifdef FEAT_JOB_CHANNEL
1408 if (bt_prompt(curbuf) && (State & INSERT))
1409 // show the line with the prompt
1410 update_topline();
1411#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001412 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001413
1414 if (!is_curbuf)
1415 {
1416 curbuf = curbuf_save;
1417 curwin = curwin_save;
1418 }
1419}
1420
1421/*
1422 * "append(lnum, string/list)" function
1423 */
1424 static void
1425f_append(typval_T *argvars, typval_T *rettv)
1426{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001427 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001428
1429 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1430}
1431
1432/*
1433 * "appendbufline(buf, lnum, string/list)" function
1434 */
1435 static void
1436f_appendbufline(typval_T *argvars, typval_T *rettv)
1437{
1438 linenr_T lnum;
1439 buf_T *buf;
1440
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001441 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001442 if (buf == NULL)
1443 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001444 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001445 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001446 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001447 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1448 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001449}
1450
1451/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001452 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001453 */
1454 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001455f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001456{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001457 win_T *wp;
1458
1459 if (argvars[0].v_type == VAR_UNKNOWN)
1460 // use the current window
1461 rettv->vval.v_number = ARGCOUNT;
1462 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001463 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001464 // use the global argument list
1465 rettv->vval.v_number = GARGCOUNT;
1466 else
1467 {
1468 // use the argument list of the specified window
1469 wp = find_win_by_nr_or_id(&argvars[0]);
1470 if (wp != NULL)
1471 rettv->vval.v_number = WARGCOUNT(wp);
1472 else
1473 rettv->vval.v_number = -1;
1474 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001475}
1476
1477/*
1478 * "argidx()" function
1479 */
1480 static void
1481f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1482{
1483 rettv->vval.v_number = curwin->w_arg_idx;
1484}
1485
1486/*
1487 * "arglistid()" function
1488 */
1489 static void
1490f_arglistid(typval_T *argvars, typval_T *rettv)
1491{
1492 win_T *wp;
1493
1494 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001495 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496 if (wp != NULL)
1497 rettv->vval.v_number = wp->w_alist->id;
1498}
1499
1500/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001501 * Get the argument list for a given window
1502 */
1503 static void
1504get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1505{
1506 int idx;
1507
1508 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1509 for (idx = 0; idx < argcount; ++idx)
1510 list_append_string(rettv->vval.v_list,
1511 alist_name(&arglist[idx]), -1);
1512}
1513
1514/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001515 * "argv(nr)" function
1516 */
1517 static void
1518f_argv(typval_T *argvars, typval_T *rettv)
1519{
1520 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001521 aentry_T *arglist = NULL;
1522 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523
1524 if (argvars[0].v_type != VAR_UNKNOWN)
1525 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001526 if (argvars[1].v_type == VAR_UNKNOWN)
1527 {
1528 arglist = ARGLIST;
1529 argcount = ARGCOUNT;
1530 }
1531 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001532 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001533 {
1534 arglist = GARGLIST;
1535 argcount = GARGCOUNT;
1536 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001537 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001538 {
1539 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1540
1541 if (wp != NULL)
1542 {
1543 /* Use the argument list of the specified window */
1544 arglist = WARGLIST(wp);
1545 argcount = WARGCOUNT(wp);
1546 }
1547 }
1548
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001550 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001551 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001552 if (arglist != NULL && idx >= 0 && idx < argcount)
1553 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1554 else if (idx == -1)
1555 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001557 else
1558 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001559}
1560
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001561#ifdef FEAT_FLOAT
1562/*
1563 * "asin()" function
1564 */
1565 static void
1566f_asin(typval_T *argvars, typval_T *rettv)
1567{
1568 float_T f = 0.0;
1569
1570 rettv->v_type = VAR_FLOAT;
1571 if (get_float_arg(argvars, &f) == OK)
1572 rettv->vval.v_float = asin(f);
1573 else
1574 rettv->vval.v_float = 0.0;
1575}
1576
1577/*
1578 * "atan()" function
1579 */
1580 static void
1581f_atan(typval_T *argvars, typval_T *rettv)
1582{
1583 float_T f = 0.0;
1584
1585 rettv->v_type = VAR_FLOAT;
1586 if (get_float_arg(argvars, &f) == OK)
1587 rettv->vval.v_float = atan(f);
1588 else
1589 rettv->vval.v_float = 0.0;
1590}
1591
1592/*
1593 * "atan2()" function
1594 */
1595 static void
1596f_atan2(typval_T *argvars, typval_T *rettv)
1597{
1598 float_T fx = 0.0, fy = 0.0;
1599
1600 rettv->v_type = VAR_FLOAT;
1601 if (get_float_arg(argvars, &fx) == OK
1602 && get_float_arg(&argvars[1], &fy) == OK)
1603 rettv->vval.v_float = atan2(fx, fy);
1604 else
1605 rettv->vval.v_float = 0.0;
1606}
1607#endif
1608
1609/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001610 * "balloon_show()" function
1611 */
1612#ifdef FEAT_BEVAL
1613 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001614f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1615{
1616 rettv->v_type = VAR_STRING;
1617 if (balloonEval != NULL)
1618 {
1619 if (balloonEval->msg == NULL)
1620 rettv->vval.v_string = NULL;
1621 else
1622 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1623 }
1624}
1625
1626 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001627f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1628{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001629 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001630 {
1631 if (argvars[0].v_type == VAR_LIST
1632# ifdef FEAT_GUI
1633 && !gui.in_use
1634# endif
1635 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001636 {
1637 list_T *l = argvars[0].vval.v_list;
1638
1639 // empty list removes the balloon
1640 post_balloon(balloonEval, NULL,
1641 l == NULL || l->lv_len == 0 ? NULL : l);
1642 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001643 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001644 {
1645 char_u *mesg = tv_get_string_chk(&argvars[0]);
1646
1647 if (mesg != NULL)
1648 // empty string removes the balloon
1649 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1650 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001651 }
1652}
1653
Bram Moolenaar669a8282017-11-19 20:13:05 +01001654# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001655 static void
1656f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1657{
1658 if (rettv_list_alloc(rettv) == OK)
1659 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001660 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001661
1662 if (msg != NULL)
1663 {
1664 pumitem_T *array;
1665 int size = split_message(msg, &array);
1666 int i;
1667
1668 /* Skip the first and last item, they are always empty. */
1669 for (i = 1; i < size - 1; ++i)
1670 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001671 while (size > 0)
1672 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001673 vim_free(array);
1674 }
1675 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001676}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001677# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001678#endif
1679
1680/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 * "browse(save, title, initdir, default)" function
1682 */
1683 static void
1684f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1685{
1686#ifdef FEAT_BROWSE
1687 int save;
1688 char_u *title;
1689 char_u *initdir;
1690 char_u *defname;
1691 char_u buf[NUMBUFLEN];
1692 char_u buf2[NUMBUFLEN];
1693 int error = FALSE;
1694
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001695 save = (int)tv_get_number_chk(&argvars[0], &error);
1696 title = tv_get_string_chk(&argvars[1]);
1697 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1698 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001699
1700 if (error || title == NULL || initdir == NULL || defname == NULL)
1701 rettv->vval.v_string = NULL;
1702 else
1703 rettv->vval.v_string =
1704 do_browse(save ? BROWSE_SAVE : 0,
1705 title, defname, NULL, initdir, NULL, curbuf);
1706#else
1707 rettv->vval.v_string = NULL;
1708#endif
1709 rettv->v_type = VAR_STRING;
1710}
1711
1712/*
1713 * "browsedir(title, initdir)" function
1714 */
1715 static void
1716f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1717{
1718#ifdef FEAT_BROWSE
1719 char_u *title;
1720 char_u *initdir;
1721 char_u buf[NUMBUFLEN];
1722
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001723 title = tv_get_string_chk(&argvars[0]);
1724 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725
1726 if (title == NULL || initdir == NULL)
1727 rettv->vval.v_string = NULL;
1728 else
1729 rettv->vval.v_string = do_browse(BROWSE_DIR,
1730 title, NULL, NULL, initdir, NULL, curbuf);
1731#else
1732 rettv->vval.v_string = NULL;
1733#endif
1734 rettv->v_type = VAR_STRING;
1735}
1736
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001737/*
1738 * Find a buffer by number or exact name.
1739 */
1740 static buf_T *
1741find_buffer(typval_T *avar)
1742{
1743 buf_T *buf = NULL;
1744
1745 if (avar->v_type == VAR_NUMBER)
1746 buf = buflist_findnr((int)avar->vval.v_number);
1747 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1748 {
1749 buf = buflist_findname_exp(avar->vval.v_string);
1750 if (buf == NULL)
1751 {
1752 /* No full path name match, try a match with a URL or a "nofile"
1753 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001754 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001755 if (buf->b_fname != NULL
1756 && (path_with_url(buf->b_fname)
1757#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001758 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001759#endif
1760 )
1761 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1762 break;
1763 }
1764 }
1765 return buf;
1766}
1767
1768/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001769 * "bufadd(expr)" function
1770 */
1771 static void
1772f_bufadd(typval_T *argvars, typval_T *rettv)
1773{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001774 char_u *name = tv_get_string(&argvars[0]);
1775
1776 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001777}
1778
1779/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001780 * "bufexists(expr)" function
1781 */
1782 static void
1783f_bufexists(typval_T *argvars, typval_T *rettv)
1784{
1785 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1786}
1787
1788/*
1789 * "buflisted(expr)" function
1790 */
1791 static void
1792f_buflisted(typval_T *argvars, typval_T *rettv)
1793{
1794 buf_T *buf;
1795
1796 buf = find_buffer(&argvars[0]);
1797 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1798}
1799
1800/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001801 * "bufload(expr)" function
1802 */
1803 static void
1804f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1805{
1806 buf_T *buf = get_buf_arg(&argvars[0]);
1807
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001808 if (buf != NULL)
1809 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001810}
1811
1812/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 * "bufloaded(expr)" function
1814 */
1815 static void
1816f_bufloaded(typval_T *argvars, typval_T *rettv)
1817{
1818 buf_T *buf;
1819
1820 buf = find_buffer(&argvars[0]);
1821 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1822}
1823
1824 buf_T *
1825buflist_find_by_name(char_u *name, int curtab_only)
1826{
1827 int save_magic;
1828 char_u *save_cpo;
1829 buf_T *buf;
1830
1831 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1832 save_magic = p_magic;
1833 p_magic = TRUE;
1834 save_cpo = p_cpo;
1835 p_cpo = (char_u *)"";
1836
1837 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1838 TRUE, FALSE, curtab_only));
1839
1840 p_magic = save_magic;
1841 p_cpo = save_cpo;
1842 return buf;
1843}
1844
1845/*
1846 * Get buffer by number or pattern.
1847 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001848 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001849tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001850{
1851 char_u *name = tv->vval.v_string;
1852 buf_T *buf;
1853
1854 if (tv->v_type == VAR_NUMBER)
1855 return buflist_findnr((int)tv->vval.v_number);
1856 if (tv->v_type != VAR_STRING)
1857 return NULL;
1858 if (name == NULL || *name == NUL)
1859 return curbuf;
1860 if (name[0] == '$' && name[1] == NUL)
1861 return lastbuf;
1862
1863 buf = buflist_find_by_name(name, curtab_only);
1864
1865 /* If not found, try expanding the name, like done for bufexists(). */
1866 if (buf == NULL)
1867 buf = find_buffer(tv);
1868
1869 return buf;
1870}
1871
1872/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001873 * Get the buffer from "arg" and give an error and return NULL if it is not
1874 * valid.
1875 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001876 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001877get_buf_arg(typval_T *arg)
1878{
1879 buf_T *buf;
1880
1881 ++emsg_off;
1882 buf = tv_get_buf(arg, FALSE);
1883 --emsg_off;
1884 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001885 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001886 return buf;
1887}
1888
1889/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001890 * "bufname(expr)" function
1891 */
1892 static void
1893f_bufname(typval_T *argvars, typval_T *rettv)
1894{
1895 buf_T *buf;
1896
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001897 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001899 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900 rettv->v_type = VAR_STRING;
1901 if (buf != NULL && buf->b_fname != NULL)
1902 rettv->vval.v_string = vim_strsave(buf->b_fname);
1903 else
1904 rettv->vval.v_string = NULL;
1905 --emsg_off;
1906}
1907
1908/*
1909 * "bufnr(expr)" function
1910 */
1911 static void
1912f_bufnr(typval_T *argvars, typval_T *rettv)
1913{
1914 buf_T *buf;
1915 int error = FALSE;
1916 char_u *name;
1917
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001918 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001919 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001920 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001921 --emsg_off;
1922
1923 /* If the buffer isn't found and the second argument is not zero create a
1924 * new buffer. */
1925 if (buf == NULL
1926 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001927 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001929 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001930 && !error)
1931 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1932
1933 if (buf != NULL)
1934 rettv->vval.v_number = buf->b_fnum;
1935 else
1936 rettv->vval.v_number = -1;
1937}
1938
1939 static void
1940buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1941{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942 win_T *wp;
1943 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001944 buf_T *buf;
1945
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001946 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001947 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001948 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001949 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001950 {
1951 ++winnr;
1952 if (wp->w_buffer == buf)
1953 break;
1954 }
1955 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001956 --emsg_off;
1957}
1958
1959/*
1960 * "bufwinid(nr)" function
1961 */
1962 static void
1963f_bufwinid(typval_T *argvars, typval_T *rettv)
1964{
1965 buf_win_common(argvars, rettv, FALSE);
1966}
1967
1968/*
1969 * "bufwinnr(nr)" function
1970 */
1971 static void
1972f_bufwinnr(typval_T *argvars, typval_T *rettv)
1973{
1974 buf_win_common(argvars, rettv, TRUE);
1975}
1976
1977/*
1978 * "byte2line(byte)" function
1979 */
1980 static void
1981f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1982{
1983#ifndef FEAT_BYTEOFF
1984 rettv->vval.v_number = -1;
1985#else
1986 long boff = 0;
1987
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001988 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989 if (boff < 0)
1990 rettv->vval.v_number = -1;
1991 else
1992 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1993 (linenr_T)0, &boff);
1994#endif
1995}
1996
1997 static void
1998byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1999{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002000 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002001 char_u *str;
2002 varnumber_T idx;
2003
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002004 str = tv_get_string_chk(&argvars[0]);
2005 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006 rettv->vval.v_number = -1;
2007 if (str == NULL || idx < 0)
2008 return;
2009
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 t = str;
2011 for ( ; idx > 0; idx--)
2012 {
2013 if (*t == NUL) /* EOL reached */
2014 return;
2015 if (enc_utf8 && comp)
2016 t += utf_ptr2len(t);
2017 else
2018 t += (*mb_ptr2len)(t);
2019 }
2020 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021}
2022
2023/*
2024 * "byteidx()" function
2025 */
2026 static void
2027f_byteidx(typval_T *argvars, typval_T *rettv)
2028{
2029 byteidx(argvars, rettv, FALSE);
2030}
2031
2032/*
2033 * "byteidxcomp()" function
2034 */
2035 static void
2036f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2037{
2038 byteidx(argvars, rettv, TRUE);
2039}
2040
2041/*
2042 * "call(func, arglist [, dict])" function
2043 */
2044 static void
2045f_call(typval_T *argvars, typval_T *rettv)
2046{
2047 char_u *func;
2048 partial_T *partial = NULL;
2049 dict_T *selfdict = NULL;
2050
2051 if (argvars[1].v_type != VAR_LIST)
2052 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002053 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002054 return;
2055 }
2056 if (argvars[1].vval.v_list == NULL)
2057 return;
2058
2059 if (argvars[0].v_type == VAR_FUNC)
2060 func = argvars[0].vval.v_string;
2061 else if (argvars[0].v_type == VAR_PARTIAL)
2062 {
2063 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002064 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002065 }
2066 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002067 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002068 if (*func == NUL)
2069 return; /* type error or empty name */
2070
2071 if (argvars[2].v_type != VAR_UNKNOWN)
2072 {
2073 if (argvars[2].v_type != VAR_DICT)
2074 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002075 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002076 return;
2077 }
2078 selfdict = argvars[2].vval.v_dict;
2079 }
2080
2081 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2082}
2083
2084#ifdef FEAT_FLOAT
2085/*
2086 * "ceil({float})" function
2087 */
2088 static void
2089f_ceil(typval_T *argvars, typval_T *rettv)
2090{
2091 float_T f = 0.0;
2092
2093 rettv->v_type = VAR_FLOAT;
2094 if (get_float_arg(argvars, &f) == OK)
2095 rettv->vval.v_float = ceil(f);
2096 else
2097 rettv->vval.v_float = 0.0;
2098}
2099#endif
2100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002101/*
2102 * "changenr()" function
2103 */
2104 static void
2105f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2106{
2107 rettv->vval.v_number = curbuf->b_u_seq_cur;
2108}
2109
2110/*
2111 * "char2nr(string)" function
2112 */
2113 static void
2114f_char2nr(typval_T *argvars, typval_T *rettv)
2115{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002116 if (has_mbyte)
2117 {
2118 int utf8 = 0;
2119
2120 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002121 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122
2123 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002124 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002125 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002126 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002127 }
2128 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002129 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002130}
2131
2132/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002133 * "chdir(dir)" function
2134 */
2135 static void
2136f_chdir(typval_T *argvars, typval_T *rettv)
2137{
2138 char_u *cwd;
2139 cdscope_T scope = CDSCOPE_GLOBAL;
2140
2141 rettv->v_type = VAR_STRING;
2142 rettv->vval.v_string = NULL;
2143
2144 if (argvars[0].v_type != VAR_STRING)
2145 return;
2146
2147 // Return the current directory
2148 cwd = alloc(MAXPATHL);
2149 if (cwd != NULL)
2150 {
2151 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2152 {
2153#ifdef BACKSLASH_IN_FILENAME
2154 slash_adjust(cwd);
2155#endif
2156 rettv->vval.v_string = vim_strsave(cwd);
2157 }
2158 vim_free(cwd);
2159 }
2160
2161 if (curwin->w_localdir != NULL)
2162 scope = CDSCOPE_WINDOW;
2163 else if (curtab->tp_localdir != NULL)
2164 scope = CDSCOPE_TABPAGE;
2165
2166 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2167 // Directory change failed
2168 VIM_CLEAR(rettv->vval.v_string);
2169}
2170
2171/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 * "cindent(lnum)" function
2173 */
2174 static void
2175f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2176{
2177#ifdef FEAT_CINDENT
2178 pos_T pos;
2179 linenr_T lnum;
2180
2181 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002182 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2184 {
2185 curwin->w_cursor.lnum = lnum;
2186 rettv->vval.v_number = get_c_indent();
2187 curwin->w_cursor = pos;
2188 }
2189 else
2190#endif
2191 rettv->vval.v_number = -1;
2192}
2193
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002194 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002195get_optional_window(typval_T *argvars, int idx)
2196{
2197 win_T *win = curwin;
2198
2199 if (argvars[idx].v_type != VAR_UNKNOWN)
2200 {
2201 win = find_win_by_nr_or_id(&argvars[idx]);
2202 if (win == NULL)
2203 {
2204 emsg(_(e_invalwindow));
2205 return NULL;
2206 }
2207 }
2208 return win;
2209}
2210
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211/*
2212 * "clearmatches()" function
2213 */
2214 static void
2215f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2216{
2217#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002218 win_T *win = get_optional_window(argvars, 0);
2219
2220 if (win != NULL)
2221 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002222#endif
2223}
2224
2225/*
2226 * "col(string)" function
2227 */
2228 static void
2229f_col(typval_T *argvars, typval_T *rettv)
2230{
2231 colnr_T col = 0;
2232 pos_T *fp;
2233 int fnum = curbuf->b_fnum;
2234
2235 fp = var2fpos(&argvars[0], FALSE, &fnum);
2236 if (fp != NULL && fnum == curbuf->b_fnum)
2237 {
2238 if (fp->col == MAXCOL)
2239 {
2240 /* '> can be MAXCOL, get the length of the line then */
2241 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2242 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2243 else
2244 col = MAXCOL;
2245 }
2246 else
2247 {
2248 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002249 /* col(".") when the cursor is on the NUL at the end of the line
2250 * because of "coladd" can be seen as an extra column. */
2251 if (virtual_active() && fp == &curwin->w_cursor)
2252 {
2253 char_u *p = ml_get_cursor();
2254
2255 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2256 curwin->w_virtcol - curwin->w_cursor.coladd))
2257 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258 int l;
2259
2260 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2261 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002262 }
2263 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002264 }
2265 }
2266 rettv->vval.v_number = col;
2267}
2268
2269#if defined(FEAT_INS_EXPAND)
2270/*
2271 * "complete()" function
2272 */
2273 static void
2274f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2275{
2276 int startcol;
2277
2278 if ((State & INSERT) == 0)
2279 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002280 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 return;
2282 }
2283
2284 /* Check for undo allowed here, because if something was already inserted
2285 * the line was already saved for undo and this check isn't done. */
2286 if (!undo_allowed())
2287 return;
2288
2289 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2290 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002291 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 return;
2293 }
2294
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002295 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 if (startcol <= 0)
2297 return;
2298
2299 set_completion(startcol - 1, argvars[1].vval.v_list);
2300}
2301
2302/*
2303 * "complete_add()" function
2304 */
2305 static void
2306f_complete_add(typval_T *argvars, typval_T *rettv)
2307{
2308 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2309}
2310
2311/*
2312 * "complete_check()" function
2313 */
2314 static void
2315f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2316{
2317 int saved = RedrawingDisabled;
2318
2319 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002320 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002321 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002322 RedrawingDisabled = saved;
2323}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002324
2325/*
2326 * "complete_info()" function
2327 */
2328 static void
2329f_complete_info(typval_T *argvars, typval_T *rettv)
2330{
2331 list_T *what_list = NULL;
2332
2333 if (rettv_dict_alloc(rettv) != OK)
2334 return;
2335
2336 if (argvars[0].v_type != VAR_UNKNOWN)
2337 {
2338 if (argvars[0].v_type != VAR_LIST)
2339 {
2340 emsg(_(e_listreq));
2341 return;
2342 }
2343 what_list = argvars[0].vval.v_list;
2344 }
2345 get_complete_info(what_list, rettv->vval.v_dict);
2346}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347#endif
2348
2349/*
2350 * "confirm(message, buttons[, default [, type]])" function
2351 */
2352 static void
2353f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2354{
2355#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2356 char_u *message;
2357 char_u *buttons = NULL;
2358 char_u buf[NUMBUFLEN];
2359 char_u buf2[NUMBUFLEN];
2360 int def = 1;
2361 int type = VIM_GENERIC;
2362 char_u *typestr;
2363 int error = FALSE;
2364
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002365 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002366 if (message == NULL)
2367 error = TRUE;
2368 if (argvars[1].v_type != VAR_UNKNOWN)
2369 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002370 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002371 if (buttons == NULL)
2372 error = TRUE;
2373 if (argvars[2].v_type != VAR_UNKNOWN)
2374 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002375 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002376 if (argvars[3].v_type != VAR_UNKNOWN)
2377 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002378 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002379 if (typestr == NULL)
2380 error = TRUE;
2381 else
2382 {
2383 switch (TOUPPER_ASC(*typestr))
2384 {
2385 case 'E': type = VIM_ERROR; break;
2386 case 'Q': type = VIM_QUESTION; break;
2387 case 'I': type = VIM_INFO; break;
2388 case 'W': type = VIM_WARNING; break;
2389 case 'G': type = VIM_GENERIC; break;
2390 }
2391 }
2392 }
2393 }
2394 }
2395
2396 if (buttons == NULL || *buttons == NUL)
2397 buttons = (char_u *)_("&Ok");
2398
2399 if (!error)
2400 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2401 def, NULL, FALSE);
2402#endif
2403}
2404
2405/*
2406 * "copy()" function
2407 */
2408 static void
2409f_copy(typval_T *argvars, typval_T *rettv)
2410{
2411 item_copy(&argvars[0], rettv, FALSE, 0);
2412}
2413
2414#ifdef FEAT_FLOAT
2415/*
2416 * "cos()" function
2417 */
2418 static void
2419f_cos(typval_T *argvars, typval_T *rettv)
2420{
2421 float_T f = 0.0;
2422
2423 rettv->v_type = VAR_FLOAT;
2424 if (get_float_arg(argvars, &f) == OK)
2425 rettv->vval.v_float = cos(f);
2426 else
2427 rettv->vval.v_float = 0.0;
2428}
2429
2430/*
2431 * "cosh()" function
2432 */
2433 static void
2434f_cosh(typval_T *argvars, typval_T *rettv)
2435{
2436 float_T f = 0.0;
2437
2438 rettv->v_type = VAR_FLOAT;
2439 if (get_float_arg(argvars, &f) == OK)
2440 rettv->vval.v_float = cosh(f);
2441 else
2442 rettv->vval.v_float = 0.0;
2443}
2444#endif
2445
2446/*
2447 * "count()" function
2448 */
2449 static void
2450f_count(typval_T *argvars, typval_T *rettv)
2451{
2452 long n = 0;
2453 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002454 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455
Bram Moolenaar9966b212017-07-28 16:46:57 +02002456 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002457 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002458
2459 if (argvars[0].v_type == VAR_STRING)
2460 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002461 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002462 char_u *p = argvars[0].vval.v_string;
2463 char_u *next;
2464
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002465 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002466 {
2467 if (ic)
2468 {
2469 size_t len = STRLEN(expr);
2470
2471 while (*p != NUL)
2472 {
2473 if (MB_STRNICMP(p, expr, len) == 0)
2474 {
2475 ++n;
2476 p += len;
2477 }
2478 else
2479 MB_PTR_ADV(p);
2480 }
2481 }
2482 else
2483 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2484 != NULL)
2485 {
2486 ++n;
2487 p = next + STRLEN(expr);
2488 }
2489 }
2490
2491 }
2492 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 {
2494 listitem_T *li;
2495 list_T *l;
2496 long idx;
2497
2498 if ((l = argvars[0].vval.v_list) != NULL)
2499 {
2500 li = l->lv_first;
2501 if (argvars[2].v_type != VAR_UNKNOWN)
2502 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002503 if (argvars[3].v_type != VAR_UNKNOWN)
2504 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002505 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002506 if (!error)
2507 {
2508 li = list_find(l, idx);
2509 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002510 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511 }
2512 }
2513 if (error)
2514 li = NULL;
2515 }
2516
2517 for ( ; li != NULL; li = li->li_next)
2518 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2519 ++n;
2520 }
2521 }
2522 else if (argvars[0].v_type == VAR_DICT)
2523 {
2524 int todo;
2525 dict_T *d;
2526 hashitem_T *hi;
2527
2528 if ((d = argvars[0].vval.v_dict) != NULL)
2529 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002530 if (argvars[2].v_type != VAR_UNKNOWN)
2531 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002533 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002534 }
2535
2536 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2537 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2538 {
2539 if (!HASHITEM_EMPTY(hi))
2540 {
2541 --todo;
2542 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2543 ++n;
2544 }
2545 }
2546 }
2547 }
2548 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002549 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002550 rettv->vval.v_number = n;
2551}
2552
2553/*
2554 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2555 *
2556 * Checks the existence of a cscope connection.
2557 */
2558 static void
2559f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2560{
2561#ifdef FEAT_CSCOPE
2562 int num = 0;
2563 char_u *dbpath = NULL;
2564 char_u *prepend = NULL;
2565 char_u buf[NUMBUFLEN];
2566
2567 if (argvars[0].v_type != VAR_UNKNOWN
2568 && argvars[1].v_type != VAR_UNKNOWN)
2569 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002570 num = (int)tv_get_number(&argvars[0]);
2571 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002572 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002573 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 }
2575
2576 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2577#endif
2578}
2579
2580/*
2581 * "cursor(lnum, col)" function, or
2582 * "cursor(list)"
2583 *
2584 * Moves the cursor to the specified line and column.
2585 * Returns 0 when the position could be set, -1 otherwise.
2586 */
2587 static void
2588f_cursor(typval_T *argvars, typval_T *rettv)
2589{
2590 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 int set_curswant = TRUE;
2593
2594 rettv->vval.v_number = -1;
2595 if (argvars[1].v_type == VAR_UNKNOWN)
2596 {
2597 pos_T pos;
2598 colnr_T curswant = -1;
2599
2600 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2601 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002602 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 return;
2604 }
2605 line = pos.lnum;
2606 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608 if (curswant >= 0)
2609 {
2610 curwin->w_curswant = curswant - 1;
2611 set_curswant = FALSE;
2612 }
2613 }
2614 else
2615 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002616 line = tv_get_lnum(argvars);
2617 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002619 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002621 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002622 return; /* type error; errmsg already given */
2623 if (line > 0)
2624 curwin->w_cursor.lnum = line;
2625 if (col > 0)
2626 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002628
2629 /* Make sure the cursor is in a valid position. */
2630 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631 /* Correct cursor for multi-byte character. */
2632 if (has_mbyte)
2633 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002634
2635 curwin->w_set_curswant = set_curswant;
2636 rettv->vval.v_number = 0;
2637}
2638
Bram Moolenaar4f974752019-02-17 17:44:42 +01002639#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002640/*
2641 * "debugbreak()" function
2642 */
2643 static void
2644f_debugbreak(typval_T *argvars, typval_T *rettv)
2645{
2646 int pid;
2647
2648 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002649 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002650 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002651 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002652 else
2653 {
2654 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2655
2656 if (hProcess != NULL)
2657 {
2658 DebugBreakProcess(hProcess);
2659 CloseHandle(hProcess);
2660 rettv->vval.v_number = OK;
2661 }
2662 }
2663}
2664#endif
2665
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666/*
2667 * "deepcopy()" function
2668 */
2669 static void
2670f_deepcopy(typval_T *argvars, typval_T *rettv)
2671{
2672 int noref = 0;
2673 int copyID;
2674
2675 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002676 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002678 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002679 else
2680 {
2681 copyID = get_copyID();
2682 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2683 }
2684}
2685
2686/*
2687 * "delete()" function
2688 */
2689 static void
2690f_delete(typval_T *argvars, typval_T *rettv)
2691{
2692 char_u nbuf[NUMBUFLEN];
2693 char_u *name;
2694 char_u *flags;
2695
2696 rettv->vval.v_number = -1;
2697 if (check_restricted() || check_secure())
2698 return;
2699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002700 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701 if (name == NULL || *name == NUL)
2702 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002703 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 return;
2705 }
2706
2707 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002708 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709 else
2710 flags = (char_u *)"";
2711
2712 if (*flags == NUL)
2713 /* delete a file */
2714 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2715 else if (STRCMP(flags, "d") == 0)
2716 /* delete an empty directory */
2717 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2718 else if (STRCMP(flags, "rf") == 0)
2719 /* delete a directory recursively */
2720 rettv->vval.v_number = delete_recursive(name);
2721 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002722 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002723}
2724
2725/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002726 * "deletebufline()" function
2727 */
2728 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002729f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002730{
2731 buf_T *buf;
2732 linenr_T first, last;
2733 linenr_T lnum;
2734 long count;
2735 int is_curbuf;
2736 buf_T *curbuf_save = NULL;
2737 win_T *curwin_save = NULL;
2738 tabpage_T *tp;
2739 win_T *wp;
2740
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002741 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002742 if (buf == NULL)
2743 {
2744 rettv->vval.v_number = 1; /* FAIL */
2745 return;
2746 }
2747 is_curbuf = buf == curbuf;
2748
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002749 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002750 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002751 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002752 else
2753 last = first;
2754
2755 if (buf->b_ml.ml_mfp == NULL || first < 1
2756 || first > buf->b_ml.ml_line_count || last < first)
2757 {
2758 rettv->vval.v_number = 1; /* FAIL */
2759 return;
2760 }
2761
2762 if (!is_curbuf)
2763 {
2764 curbuf_save = curbuf;
2765 curwin_save = curwin;
2766 curbuf = buf;
2767 find_win_for_curbuf();
2768 }
2769 if (last > curbuf->b_ml.ml_line_count)
2770 last = curbuf->b_ml.ml_line_count;
2771 count = last - first + 1;
2772
2773 // When coming here from Insert mode, sync undo, so that this can be
2774 // undone separately from what was previously inserted.
2775 if (u_sync_once == 2)
2776 {
2777 u_sync_once = 1; // notify that u_sync() was called
2778 u_sync(TRUE);
2779 }
2780
2781 if (u_save(first - 1, last + 1) == FAIL)
2782 {
2783 rettv->vval.v_number = 1; /* FAIL */
2784 return;
2785 }
2786
2787 for (lnum = first; lnum <= last; ++lnum)
2788 ml_delete(first, TRUE);
2789
2790 FOR_ALL_TAB_WINDOWS(tp, wp)
2791 if (wp->w_buffer == buf)
2792 {
2793 if (wp->w_cursor.lnum > last)
2794 wp->w_cursor.lnum -= count;
2795 else if (wp->w_cursor.lnum> first)
2796 wp->w_cursor.lnum = first;
2797 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2798 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2799 }
2800 check_cursor_col();
2801 deleted_lines_mark(first, count);
2802
2803 if (!is_curbuf)
2804 {
2805 curbuf = curbuf_save;
2806 curwin = curwin_save;
2807 }
2808}
2809
2810/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002811 * "did_filetype()" function
2812 */
2813 static void
2814f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2815{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002816 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817}
2818
2819/*
2820 * "diff_filler()" function
2821 */
2822 static void
2823f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2824{
2825#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002826 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002827#endif
2828}
2829
2830/*
2831 * "diff_hlID()" function
2832 */
2833 static void
2834f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2835{
2836#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002837 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002839 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 static int fnum = 0;
2841 static int change_start = 0;
2842 static int change_end = 0;
2843 static hlf_T hlID = (hlf_T)0;
2844 int filler_lines;
2845 int col;
2846
2847 if (lnum < 0) /* ignore type error in {lnum} arg */
2848 lnum = 0;
2849 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002850 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851 || fnum != curbuf->b_fnum)
2852 {
2853 /* New line, buffer, change: need to get the values. */
2854 filler_lines = diff_check(curwin, lnum);
2855 if (filler_lines < 0)
2856 {
2857 if (filler_lines == -1)
2858 {
2859 change_start = MAXCOL;
2860 change_end = -1;
2861 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2862 hlID = HLF_ADD; /* added line */
2863 else
2864 hlID = HLF_CHD; /* changed line */
2865 }
2866 else
2867 hlID = HLF_ADD; /* added line */
2868 }
2869 else
2870 hlID = (hlf_T)0;
2871 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002872 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002873 fnum = curbuf->b_fnum;
2874 }
2875
2876 if (hlID == HLF_CHD || hlID == HLF_TXD)
2877 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002878 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002879 if (col >= change_start && col <= change_end)
2880 hlID = HLF_TXD; /* changed text */
2881 else
2882 hlID = HLF_CHD; /* changed line */
2883 }
2884 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2885#endif
2886}
2887
2888/*
2889 * "empty({expr})" function
2890 */
2891 static void
2892f_empty(typval_T *argvars, typval_T *rettv)
2893{
2894 int n = FALSE;
2895
2896 switch (argvars[0].v_type)
2897 {
2898 case VAR_STRING:
2899 case VAR_FUNC:
2900 n = argvars[0].vval.v_string == NULL
2901 || *argvars[0].vval.v_string == NUL;
2902 break;
2903 case VAR_PARTIAL:
2904 n = FALSE;
2905 break;
2906 case VAR_NUMBER:
2907 n = argvars[0].vval.v_number == 0;
2908 break;
2909 case VAR_FLOAT:
2910#ifdef FEAT_FLOAT
2911 n = argvars[0].vval.v_float == 0.0;
2912 break;
2913#endif
2914 case VAR_LIST:
2915 n = argvars[0].vval.v_list == NULL
2916 || argvars[0].vval.v_list->lv_first == NULL;
2917 break;
2918 case VAR_DICT:
2919 n = argvars[0].vval.v_dict == NULL
2920 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2921 break;
2922 case VAR_SPECIAL:
2923 n = argvars[0].vval.v_number != VVAL_TRUE;
2924 break;
2925
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002926 case VAR_BLOB:
2927 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002928 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2929 break;
2930
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002931 case VAR_JOB:
2932#ifdef FEAT_JOB_CHANNEL
2933 n = argvars[0].vval.v_job == NULL
2934 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2935 break;
2936#endif
2937 case VAR_CHANNEL:
2938#ifdef FEAT_JOB_CHANNEL
2939 n = argvars[0].vval.v_channel == NULL
2940 || !channel_is_open(argvars[0].vval.v_channel);
2941 break;
2942#endif
2943 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002944 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002945 n = TRUE;
2946 break;
2947 }
2948
2949 rettv->vval.v_number = n;
2950}
2951
2952/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002953 * "environ()" function
2954 */
2955 static void
2956f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2957{
2958#if !defined(AMIGA)
2959 int i = 0;
2960 char_u *entry, *value;
2961# ifdef MSWIN
2962 extern wchar_t **_wenviron;
2963# else
2964 extern char **environ;
2965# endif
2966
2967 if (rettv_dict_alloc(rettv) != OK)
2968 return;
2969
2970# ifdef MSWIN
2971 if (*_wenviron == NULL)
2972 return;
2973# else
2974 if (*environ == NULL)
2975 return;
2976# endif
2977
2978 for (i = 0; ; ++i)
2979 {
2980# ifdef MSWIN
2981 short_u *p;
2982
2983 if ((p = (short_u *)_wenviron[i]) == NULL)
2984 return;
2985 entry = utf16_to_enc(p, NULL);
2986# else
2987 if ((entry = (char_u *)environ[i]) == NULL)
2988 return;
2989 entry = vim_strsave(entry);
2990# endif
2991 if (entry == NULL) // out of memory
2992 return;
2993 if ((value = vim_strchr(entry, '=')) == NULL)
2994 {
2995 vim_free(entry);
2996 continue;
2997 }
2998 *value++ = NUL;
2999 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3000 vim_free(entry);
3001 }
3002#endif
3003}
3004
3005/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006 * "escape({string}, {chars})" function
3007 */
3008 static void
3009f_escape(typval_T *argvars, typval_T *rettv)
3010{
3011 char_u buf[NUMBUFLEN];
3012
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003013 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3014 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003015 rettv->v_type = VAR_STRING;
3016}
3017
3018/*
3019 * "eval()" function
3020 */
3021 static void
3022f_eval(typval_T *argvars, typval_T *rettv)
3023{
3024 char_u *s, *p;
3025
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003026 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003027 if (s != NULL)
3028 s = skipwhite(s);
3029
3030 p = s;
3031 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3032 {
3033 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003034 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003035 need_clr_eos = FALSE;
3036 rettv->v_type = VAR_NUMBER;
3037 rettv->vval.v_number = 0;
3038 }
3039 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003040 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003041}
3042
3043/*
3044 * "eventhandler()" function
3045 */
3046 static void
3047f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3048{
3049 rettv->vval.v_number = vgetc_busy;
3050}
3051
3052/*
3053 * "executable()" function
3054 */
3055 static void
3056f_executable(typval_T *argvars, typval_T *rettv)
3057{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003058 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059
3060 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003061 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062}
3063
3064static garray_T redir_execute_ga;
3065
3066/*
3067 * Append "value[value_len]" to the execute() output.
3068 */
3069 void
3070execute_redir_str(char_u *value, int value_len)
3071{
3072 int len;
3073
3074 if (value_len == -1)
3075 len = (int)STRLEN(value); /* Append the entire string */
3076 else
3077 len = value_len; /* Append only "value_len" characters */
3078 if (ga_grow(&redir_execute_ga, len) == OK)
3079 {
3080 mch_memmove((char *)redir_execute_ga.ga_data
3081 + redir_execute_ga.ga_len, value, len);
3082 redir_execute_ga.ga_len += len;
3083 }
3084}
3085
3086/*
3087 * Get next line from a list.
3088 * Called by do_cmdline() to get the next line.
3089 * Returns allocated string, or NULL for end of function.
3090 */
3091
3092 static char_u *
3093get_list_line(
3094 int c UNUSED,
3095 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003096 int indent UNUSED,
3097 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098{
3099 listitem_T **p = (listitem_T **)cookie;
3100 listitem_T *item = *p;
3101 char_u buf[NUMBUFLEN];
3102 char_u *s;
3103
3104 if (item == NULL)
3105 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003106 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 *p = item->li_next;
3108 return s == NULL ? NULL : vim_strsave(s);
3109}
3110
3111/*
3112 * "execute()" function
3113 */
3114 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003115execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003116{
3117 char_u *cmd = NULL;
3118 list_T *list = NULL;
3119 int save_msg_silent = msg_silent;
3120 int save_emsg_silent = emsg_silent;
3121 int save_emsg_noredir = emsg_noredir;
3122 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003123 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003124 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003125 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003126 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003127
3128 rettv->vval.v_string = NULL;
3129 rettv->v_type = VAR_STRING;
3130
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003131 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003132 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003133 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003134 if (list == NULL || list->lv_first == NULL)
3135 /* empty list, no commands, empty output */
3136 return;
3137 ++list->lv_refcount;
3138 }
3139 else
3140 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003141 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003142 if (cmd == NULL)
3143 return;
3144 }
3145
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003146 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003147 {
3148 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003149 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003150
3151 if (s == NULL)
3152 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003153 if (*s == NUL)
3154 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003155 if (STRNCMP(s, "silent", 6) == 0)
3156 ++msg_silent;
3157 if (STRCMP(s, "silent!") == 0)
3158 {
3159 emsg_silent = TRUE;
3160 emsg_noredir = TRUE;
3161 }
3162 }
3163 else
3164 ++msg_silent;
3165
3166 if (redir_execute)
3167 save_ga = redir_execute_ga;
3168 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3169 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003170 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003171 if (!echo_output)
3172 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003173
3174 if (cmd != NULL)
3175 do_cmdline_cmd(cmd);
3176 else
3177 {
3178 listitem_T *item = list->lv_first;
3179
3180 do_cmdline(NULL, get_list_line, (void *)&item,
3181 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3182 --list->lv_refcount;
3183 }
3184
Bram Moolenaard297f352017-01-29 20:31:21 +01003185 /* Need to append a NUL to the result. */
3186 if (ga_grow(&redir_execute_ga, 1) == OK)
3187 {
3188 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3189 rettv->vval.v_string = redir_execute_ga.ga_data;
3190 }
3191 else
3192 {
3193 ga_clear(&redir_execute_ga);
3194 rettv->vval.v_string = NULL;
3195 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003196 msg_silent = save_msg_silent;
3197 emsg_silent = save_emsg_silent;
3198 emsg_noredir = save_emsg_noredir;
3199
3200 redir_execute = save_redir_execute;
3201 if (redir_execute)
3202 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003203 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003204
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003205 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003206 if (echo_output)
3207 // When not working silently: put it in column zero. A following
3208 // "echon" will overwrite the message, unavoidably.
3209 msg_col = 0;
3210 else
3211 // When working silently: Put it back where it was, since nothing
3212 // should have been written.
3213 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003214}
3215
3216/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003217 * "execute()" function
3218 */
3219 static void
3220f_execute(typval_T *argvars, typval_T *rettv)
3221{
3222 execute_common(argvars, rettv, 0);
3223}
3224
3225/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003226 * "exepath()" function
3227 */
3228 static void
3229f_exepath(typval_T *argvars, typval_T *rettv)
3230{
3231 char_u *p = NULL;
3232
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003233 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003234 rettv->v_type = VAR_STRING;
3235 rettv->vval.v_string = p;
3236}
3237
3238/*
3239 * "exists()" function
3240 */
3241 static void
3242f_exists(typval_T *argvars, typval_T *rettv)
3243{
3244 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003245 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003246
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003247 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248 if (*p == '$') /* environment variable */
3249 {
3250 /* first try "normal" environment variables (fast) */
3251 if (mch_getenv(p + 1) != NULL)
3252 n = TRUE;
3253 else
3254 {
3255 /* try expanding things like $VIM and ${HOME} */
3256 p = expand_env_save(p);
3257 if (p != NULL && *p != '$')
3258 n = TRUE;
3259 vim_free(p);
3260 }
3261 }
3262 else if (*p == '&' || *p == '+') /* option */
3263 {
3264 n = (get_option_tv(&p, NULL, TRUE) == OK);
3265 if (*skipwhite(p) != NUL)
3266 n = FALSE; /* trailing garbage */
3267 }
3268 else if (*p == '*') /* internal or user defined function */
3269 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003270 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 }
3272 else if (*p == ':')
3273 {
3274 n = cmd_exists(p + 1);
3275 }
3276 else if (*p == '#')
3277 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003278 if (p[1] == '#')
3279 n = autocmd_supported(p + 2);
3280 else
3281 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003282 }
3283 else /* internal variable */
3284 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003285 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003286 }
3287
3288 rettv->vval.v_number = n;
3289}
3290
3291#ifdef FEAT_FLOAT
3292/*
3293 * "exp()" function
3294 */
3295 static void
3296f_exp(typval_T *argvars, typval_T *rettv)
3297{
3298 float_T f = 0.0;
3299
3300 rettv->v_type = VAR_FLOAT;
3301 if (get_float_arg(argvars, &f) == OK)
3302 rettv->vval.v_float = exp(f);
3303 else
3304 rettv->vval.v_float = 0.0;
3305}
3306#endif
3307
3308/*
3309 * "expand()" function
3310 */
3311 static void
3312f_expand(typval_T *argvars, typval_T *rettv)
3313{
3314 char_u *s;
3315 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003316 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3318 expand_T xpc;
3319 int error = FALSE;
3320 char_u *result;
3321
3322 rettv->v_type = VAR_STRING;
3323 if (argvars[1].v_type != VAR_UNKNOWN
3324 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003325 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003326 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003327 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003328
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003329 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003330 if (*s == '%' || *s == '#' || *s == '<')
3331 {
3332 ++emsg_off;
3333 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3334 --emsg_off;
3335 if (rettv->v_type == VAR_LIST)
3336 {
3337 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3338 list_append_string(rettv->vval.v_list, result, -1);
3339 else
3340 vim_free(result);
3341 }
3342 else
3343 rettv->vval.v_string = result;
3344 }
3345 else
3346 {
3347 /* When the optional second argument is non-zero, don't remove matches
3348 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3349 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003350 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003351 options |= WILD_KEEP_ALL;
3352 if (!error)
3353 {
3354 ExpandInit(&xpc);
3355 xpc.xp_context = EXPAND_FILES;
3356 if (p_wic)
3357 options += WILD_ICASE;
3358 if (rettv->v_type == VAR_STRING)
3359 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3360 options, WILD_ALL);
3361 else if (rettv_list_alloc(rettv) != FAIL)
3362 {
3363 int i;
3364
3365 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3366 for (i = 0; i < xpc.xp_numfiles; i++)
3367 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3368 ExpandCleanup(&xpc);
3369 }
3370 }
3371 else
3372 rettv->vval.v_string = NULL;
3373 }
3374}
3375
3376/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003377 * "expandcmd()" function
3378 * Expand all the special characters in a command string.
3379 */
3380 static void
3381f_expandcmd(typval_T *argvars, typval_T *rettv)
3382{
3383 exarg_T eap;
3384 char_u *cmdstr;
3385 char *errormsg = NULL;
3386
3387 rettv->v_type = VAR_STRING;
3388 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3389
3390 memset(&eap, 0, sizeof(eap));
3391 eap.cmd = cmdstr;
3392 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003393 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003394 eap.usefilter = FALSE;
3395 eap.nextcmd = NULL;
3396 eap.cmdidx = CMD_USER;
3397
3398 expand_filename(&eap, &cmdstr, &errormsg);
3399 if (errormsg != NULL && *errormsg != NUL)
3400 emsg(errormsg);
3401
3402 rettv->vval.v_string = cmdstr;
3403}
3404
3405/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003406 * "extend(list, list [, idx])" function
3407 * "extend(dict, dict [, action])" function
3408 */
3409 static void
3410f_extend(typval_T *argvars, typval_T *rettv)
3411{
3412 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3413
3414 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3415 {
3416 list_T *l1, *l2;
3417 listitem_T *item;
3418 long before;
3419 int error = FALSE;
3420
3421 l1 = argvars[0].vval.v_list;
3422 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003423 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424 && l2 != NULL)
3425 {
3426 if (argvars[2].v_type != VAR_UNKNOWN)
3427 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003428 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003429 if (error)
3430 return; /* type error; errmsg already given */
3431
3432 if (before == l1->lv_len)
3433 item = NULL;
3434 else
3435 {
3436 item = list_find(l1, before);
3437 if (item == NULL)
3438 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003439 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440 return;
3441 }
3442 }
3443 }
3444 else
3445 item = NULL;
3446 list_extend(l1, l2, item);
3447
3448 copy_tv(&argvars[0], rettv);
3449 }
3450 }
3451 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3452 {
3453 dict_T *d1, *d2;
3454 char_u *action;
3455 int i;
3456
3457 d1 = argvars[0].vval.v_dict;
3458 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003459 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003460 && d2 != NULL)
3461 {
3462 /* Check the third argument. */
3463 if (argvars[2].v_type != VAR_UNKNOWN)
3464 {
3465 static char *(av[]) = {"keep", "force", "error"};
3466
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003467 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468 if (action == NULL)
3469 return; /* type error; errmsg already given */
3470 for (i = 0; i < 3; ++i)
3471 if (STRCMP(action, av[i]) == 0)
3472 break;
3473 if (i == 3)
3474 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003475 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003476 return;
3477 }
3478 }
3479 else
3480 action = (char_u *)"force";
3481
3482 dict_extend(d1, d2, action);
3483
3484 copy_tv(&argvars[0], rettv);
3485 }
3486 }
3487 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003488 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489}
3490
3491/*
3492 * "feedkeys()" function
3493 */
3494 static void
3495f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3496{
3497 int remap = TRUE;
3498 int insert = FALSE;
3499 char_u *keys, *flags;
3500 char_u nbuf[NUMBUFLEN];
3501 int typed = FALSE;
3502 int execute = FALSE;
3503 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003504 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 char_u *keys_esc;
3506
3507 /* This is not allowed in the sandbox. If the commands would still be
3508 * executed in the sandbox it would be OK, but it probably happens later,
3509 * when "sandbox" is no longer set. */
3510 if (check_secure())
3511 return;
3512
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003513 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514
3515 if (argvars[1].v_type != VAR_UNKNOWN)
3516 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003517 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518 for ( ; *flags != NUL; ++flags)
3519 {
3520 switch (*flags)
3521 {
3522 case 'n': remap = FALSE; break;
3523 case 'm': remap = TRUE; break;
3524 case 't': typed = TRUE; break;
3525 case 'i': insert = TRUE; break;
3526 case 'x': execute = TRUE; break;
3527 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003528 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003529 }
3530 }
3531 }
3532
3533 if (*keys != NUL || execute)
3534 {
3535 /* Need to escape K_SPECIAL and CSI before putting the string in the
3536 * typeahead buffer. */
3537 keys_esc = vim_strsave_escape_csi(keys);
3538 if (keys_esc != NULL)
3539 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003540 if (lowlevel)
3541 {
3542#ifdef USE_INPUT_BUF
3543 add_to_input_buf(keys, (int)STRLEN(keys));
3544#else
3545 emsg(_("E980: lowlevel input not supported"));
3546#endif
3547 }
3548 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003549 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003550 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003551 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003552 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003553#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003554 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003555#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003556 )
3557 typebuf_was_filled = TRUE;
3558 }
3559 vim_free(keys_esc);
3560
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 if (execute)
3562 {
3563 int save_msg_scroll = msg_scroll;
3564
3565 /* Avoid a 1 second delay when the keys start Insert mode. */
3566 msg_scroll = FALSE;
3567
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003568 if (!dangerous)
3569 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003570 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003571 if (!dangerous)
3572 --ex_normal_busy;
3573
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574 msg_scroll |= save_msg_scroll;
3575 }
3576 }
3577 }
3578}
3579
3580/*
3581 * "filereadable()" function
3582 */
3583 static void
3584f_filereadable(typval_T *argvars, typval_T *rettv)
3585{
3586 int fd;
3587 char_u *p;
3588 int n;
3589
3590#ifndef O_NONBLOCK
3591# define O_NONBLOCK 0
3592#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003593 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003594 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3595 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3596 {
3597 n = TRUE;
3598 close(fd);
3599 }
3600 else
3601 n = FALSE;
3602
3603 rettv->vval.v_number = n;
3604}
3605
3606/*
3607 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3608 * rights to write into.
3609 */
3610 static void
3611f_filewritable(typval_T *argvars, typval_T *rettv)
3612{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003613 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003614}
3615
3616 static void
3617findfilendir(
3618 typval_T *argvars UNUSED,
3619 typval_T *rettv,
3620 int find_what UNUSED)
3621{
3622#ifdef FEAT_SEARCHPATH
3623 char_u *fname;
3624 char_u *fresult = NULL;
3625 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3626 char_u *p;
3627 char_u pathbuf[NUMBUFLEN];
3628 int count = 1;
3629 int first = TRUE;
3630 int error = FALSE;
3631#endif
3632
3633 rettv->vval.v_string = NULL;
3634 rettv->v_type = VAR_STRING;
3635
3636#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003637 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638
3639 if (argvars[1].v_type != VAR_UNKNOWN)
3640 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003641 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642 if (p == NULL)
3643 error = TRUE;
3644 else
3645 {
3646 if (*p != NUL)
3647 path = p;
3648
3649 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003650 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651 }
3652 }
3653
3654 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3655 error = TRUE;
3656
3657 if (*fname != NUL && !error)
3658 {
3659 do
3660 {
3661 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3662 vim_free(fresult);
3663 fresult = find_file_in_path_option(first ? fname : NULL,
3664 first ? (int)STRLEN(fname) : 0,
3665 0, first, path,
3666 find_what,
3667 curbuf->b_ffname,
3668 find_what == FINDFILE_DIR
3669 ? (char_u *)"" : curbuf->b_p_sua);
3670 first = FALSE;
3671
3672 if (fresult != NULL && rettv->v_type == VAR_LIST)
3673 list_append_string(rettv->vval.v_list, fresult, -1);
3674
3675 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3676 }
3677
3678 if (rettv->v_type == VAR_STRING)
3679 rettv->vval.v_string = fresult;
3680#endif
3681}
3682
3683/*
3684 * "filter()" function
3685 */
3686 static void
3687f_filter(typval_T *argvars, typval_T *rettv)
3688{
3689 filter_map(argvars, rettv, FALSE);
3690}
3691
3692/*
3693 * "finddir({fname}[, {path}[, {count}]])" function
3694 */
3695 static void
3696f_finddir(typval_T *argvars, typval_T *rettv)
3697{
3698 findfilendir(argvars, rettv, FINDFILE_DIR);
3699}
3700
3701/*
3702 * "findfile({fname}[, {path}[, {count}]])" function
3703 */
3704 static void
3705f_findfile(typval_T *argvars, typval_T *rettv)
3706{
3707 findfilendir(argvars, rettv, FINDFILE_FILE);
3708}
3709
3710#ifdef FEAT_FLOAT
3711/*
3712 * "float2nr({float})" function
3713 */
3714 static void
3715f_float2nr(typval_T *argvars, typval_T *rettv)
3716{
3717 float_T f = 0.0;
3718
3719 if (get_float_arg(argvars, &f) == OK)
3720 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003721 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003722 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003723 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003724 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725 else
3726 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 }
3728}
3729
3730/*
3731 * "floor({float})" function
3732 */
3733 static void
3734f_floor(typval_T *argvars, typval_T *rettv)
3735{
3736 float_T f = 0.0;
3737
3738 rettv->v_type = VAR_FLOAT;
3739 if (get_float_arg(argvars, &f) == OK)
3740 rettv->vval.v_float = floor(f);
3741 else
3742 rettv->vval.v_float = 0.0;
3743}
3744
3745/*
3746 * "fmod()" function
3747 */
3748 static void
3749f_fmod(typval_T *argvars, typval_T *rettv)
3750{
3751 float_T fx = 0.0, fy = 0.0;
3752
3753 rettv->v_type = VAR_FLOAT;
3754 if (get_float_arg(argvars, &fx) == OK
3755 && get_float_arg(&argvars[1], &fy) == OK)
3756 rettv->vval.v_float = fmod(fx, fy);
3757 else
3758 rettv->vval.v_float = 0.0;
3759}
3760#endif
3761
3762/*
3763 * "fnameescape({string})" function
3764 */
3765 static void
3766f_fnameescape(typval_T *argvars, typval_T *rettv)
3767{
3768 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003769 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770 rettv->v_type = VAR_STRING;
3771}
3772
3773/*
3774 * "fnamemodify({fname}, {mods})" function
3775 */
3776 static void
3777f_fnamemodify(typval_T *argvars, typval_T *rettv)
3778{
3779 char_u *fname;
3780 char_u *mods;
3781 int usedlen = 0;
3782 int len;
3783 char_u *fbuf = NULL;
3784 char_u buf[NUMBUFLEN];
3785
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003786 fname = tv_get_string_chk(&argvars[0]);
3787 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003788 if (fname == NULL || mods == NULL)
3789 fname = NULL;
3790 else
3791 {
3792 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003793 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003794 }
3795
3796 rettv->v_type = VAR_STRING;
3797 if (fname == NULL)
3798 rettv->vval.v_string = NULL;
3799 else
3800 rettv->vval.v_string = vim_strnsave(fname, len);
3801 vim_free(fbuf);
3802}
3803
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003804/*
3805 * "foldclosed()" function
3806 */
3807 static void
3808foldclosed_both(
3809 typval_T *argvars UNUSED,
3810 typval_T *rettv,
3811 int end UNUSED)
3812{
3813#ifdef FEAT_FOLDING
3814 linenr_T lnum;
3815 linenr_T first, last;
3816
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003817 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003818 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3819 {
3820 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3821 {
3822 if (end)
3823 rettv->vval.v_number = (varnumber_T)last;
3824 else
3825 rettv->vval.v_number = (varnumber_T)first;
3826 return;
3827 }
3828 }
3829#endif
3830 rettv->vval.v_number = -1;
3831}
3832
3833/*
3834 * "foldclosed()" function
3835 */
3836 static void
3837f_foldclosed(typval_T *argvars, typval_T *rettv)
3838{
3839 foldclosed_both(argvars, rettv, FALSE);
3840}
3841
3842/*
3843 * "foldclosedend()" function
3844 */
3845 static void
3846f_foldclosedend(typval_T *argvars, typval_T *rettv)
3847{
3848 foldclosed_both(argvars, rettv, TRUE);
3849}
3850
3851/*
3852 * "foldlevel()" function
3853 */
3854 static void
3855f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3856{
3857#ifdef FEAT_FOLDING
3858 linenr_T lnum;
3859
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003860 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3862 rettv->vval.v_number = foldLevel(lnum);
3863#endif
3864}
3865
3866/*
3867 * "foldtext()" function
3868 */
3869 static void
3870f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3871{
3872#ifdef FEAT_FOLDING
3873 linenr_T foldstart;
3874 linenr_T foldend;
3875 char_u *dashes;
3876 linenr_T lnum;
3877 char_u *s;
3878 char_u *r;
3879 int len;
3880 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003881 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003882#endif
3883
3884 rettv->v_type = VAR_STRING;
3885 rettv->vval.v_string = NULL;
3886#ifdef FEAT_FOLDING
3887 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3888 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3889 dashes = get_vim_var_str(VV_FOLDDASHES);
3890 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3891 && dashes != NULL)
3892 {
3893 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003894 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003895 if (!linewhite(lnum))
3896 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897
3898 /* Find interesting text in this line. */
3899 s = skipwhite(ml_get(lnum));
3900 /* skip C comment-start */
3901 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3902 {
3903 s = skipwhite(s + 2);
3904 if (*skipwhite(s) == NUL
3905 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3906 {
3907 s = skipwhite(ml_get(lnum + 1));
3908 if (*s == '*')
3909 s = skipwhite(s + 1);
3910 }
3911 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003912 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003913 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003914 r = alloc(STRLEN(txt)
3915 + STRLEN(dashes) // for %s
3916 + 20 // for %3ld
3917 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003918 if (r != NULL)
3919 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003920 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 len = (int)STRLEN(r);
3922 STRCAT(r, s);
3923 /* remove 'foldmarker' and 'commentstring' */
3924 foldtext_cleanup(r + len);
3925 rettv->vval.v_string = r;
3926 }
3927 }
3928#endif
3929}
3930
3931/*
3932 * "foldtextresult(lnum)" function
3933 */
3934 static void
3935f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3936{
3937#ifdef FEAT_FOLDING
3938 linenr_T lnum;
3939 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003940 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941 foldinfo_T foldinfo;
3942 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003943 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944#endif
3945
3946 rettv->v_type = VAR_STRING;
3947 rettv->vval.v_string = NULL;
3948#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003949 if (entered)
3950 return; /* reject recursive use */
3951 entered = TRUE;
3952
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003953 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954 /* treat illegal types and illegal string values for {lnum} the same */
3955 if (lnum < 0)
3956 lnum = 0;
3957 fold_count = foldedCount(curwin, lnum, &foldinfo);
3958 if (fold_count > 0)
3959 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003960 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3961 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003962 if (text == buf)
3963 text = vim_strsave(text);
3964 rettv->vval.v_string = text;
3965 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003966
3967 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003968#endif
3969}
3970
3971/*
3972 * "foreground()" function
3973 */
3974 static void
3975f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3976{
3977#ifdef FEAT_GUI
3978 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003979 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003980 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003981 return;
3982 }
3983#endif
3984#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003986#endif
3987}
3988
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003989 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003990common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003991{
3992 char_u *s;
3993 char_u *name;
3994 int use_string = FALSE;
3995 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003996 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997
3998 if (argvars[0].v_type == VAR_FUNC)
3999 {
4000 /* function(MyFunc, [arg], dict) */
4001 s = argvars[0].vval.v_string;
4002 }
4003 else if (argvars[0].v_type == VAR_PARTIAL
4004 && argvars[0].vval.v_partial != NULL)
4005 {
4006 /* function(dict.MyFunc, [arg]) */
4007 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004008 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004009 }
4010 else
4011 {
4012 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004013 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014 use_string = TRUE;
4015 }
4016
Bram Moolenaar843b8842016-08-21 14:36:15 +02004017 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004018 {
4019 name = s;
4020 trans_name = trans_function_name(&name, FALSE,
4021 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4022 if (*name != NUL)
4023 s = NULL;
4024 }
4025
Bram Moolenaar843b8842016-08-21 14:36:15 +02004026 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4027 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004028 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004029 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004030 else if (trans_name != NULL && (is_funcref
4031 ? find_func(trans_name) == NULL
4032 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004033 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034 else
4035 {
4036 int dict_idx = 0;
4037 int arg_idx = 0;
4038 list_T *list = NULL;
4039
4040 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4041 {
4042 char sid_buf[25];
4043 int off = *s == 's' ? 2 : 5;
4044
4045 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4046 * also be called from another script. Using trans_function_name()
4047 * would also work, but some plugins depend on the name being
4048 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004049 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004050 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004051 if (name != NULL)
4052 {
4053 STRCPY(name, sid_buf);
4054 STRCAT(name, s + off);
4055 }
4056 }
4057 else
4058 name = vim_strsave(s);
4059
4060 if (argvars[1].v_type != VAR_UNKNOWN)
4061 {
4062 if (argvars[2].v_type != VAR_UNKNOWN)
4063 {
4064 /* function(name, [args], dict) */
4065 arg_idx = 1;
4066 dict_idx = 2;
4067 }
4068 else if (argvars[1].v_type == VAR_DICT)
4069 /* function(name, dict) */
4070 dict_idx = 1;
4071 else
4072 /* function(name, [args]) */
4073 arg_idx = 1;
4074 if (dict_idx > 0)
4075 {
4076 if (argvars[dict_idx].v_type != VAR_DICT)
4077 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004078 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004079 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004080 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004081 }
4082 if (argvars[dict_idx].vval.v_dict == NULL)
4083 dict_idx = 0;
4084 }
4085 if (arg_idx > 0)
4086 {
4087 if (argvars[arg_idx].v_type != VAR_LIST)
4088 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004089 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004090 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004091 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004092 }
4093 list = argvars[arg_idx].vval.v_list;
4094 if (list == NULL || list->lv_len == 0)
4095 arg_idx = 0;
4096 }
4097 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004098 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004100 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004101
4102 /* result is a VAR_PARTIAL */
4103 if (pt == NULL)
4104 vim_free(name);
4105 else
4106 {
4107 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4108 {
4109 listitem_T *li;
4110 int i = 0;
4111 int arg_len = 0;
4112 int lv_len = 0;
4113
4114 if (arg_pt != NULL)
4115 arg_len = arg_pt->pt_argc;
4116 if (list != NULL)
4117 lv_len = list->lv_len;
4118 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004119 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004120 if (pt->pt_argv == NULL)
4121 {
4122 vim_free(pt);
4123 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004124 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004125 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004126 for (i = 0; i < arg_len; i++)
4127 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4128 if (lv_len > 0)
4129 for (li = list->lv_first; li != NULL;
4130 li = li->li_next)
4131 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004132 }
4133
4134 /* For "function(dict.func, [], dict)" and "func" is a partial
4135 * use "dict". That is backwards compatible. */
4136 if (dict_idx > 0)
4137 {
4138 /* The dict is bound explicitly, pt_auto is FALSE. */
4139 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4140 ++pt->pt_dict->dv_refcount;
4141 }
4142 else if (arg_pt != NULL)
4143 {
4144 /* If the dict was bound automatically the result is also
4145 * bound automatically. */
4146 pt->pt_dict = arg_pt->pt_dict;
4147 pt->pt_auto = arg_pt->pt_auto;
4148 if (pt->pt_dict != NULL)
4149 ++pt->pt_dict->dv_refcount;
4150 }
4151
4152 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004153 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4154 {
4155 pt->pt_func = arg_pt->pt_func;
4156 func_ptr_ref(pt->pt_func);
4157 vim_free(name);
4158 }
4159 else if (is_funcref)
4160 {
4161 pt->pt_func = find_func(trans_name);
4162 func_ptr_ref(pt->pt_func);
4163 vim_free(name);
4164 }
4165 else
4166 {
4167 pt->pt_name = name;
4168 func_ref(name);
4169 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004170 }
4171 rettv->v_type = VAR_PARTIAL;
4172 rettv->vval.v_partial = pt;
4173 }
4174 else
4175 {
4176 /* result is a VAR_FUNC */
4177 rettv->v_type = VAR_FUNC;
4178 rettv->vval.v_string = name;
4179 func_ref(name);
4180 }
4181 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004182theend:
4183 vim_free(trans_name);
4184}
4185
4186/*
4187 * "funcref()" function
4188 */
4189 static void
4190f_funcref(typval_T *argvars, typval_T *rettv)
4191{
4192 common_function(argvars, rettv, TRUE);
4193}
4194
4195/*
4196 * "function()" function
4197 */
4198 static void
4199f_function(typval_T *argvars, typval_T *rettv)
4200{
4201 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004202}
4203
4204/*
4205 * "garbagecollect()" function
4206 */
4207 static void
4208f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4209{
4210 /* This is postponed until we are back at the toplevel, because we may be
4211 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4212 want_garbage_collect = TRUE;
4213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004214 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004215 garbage_collect_at_exit = TRUE;
4216}
4217
4218/*
4219 * "get()" function
4220 */
4221 static void
4222f_get(typval_T *argvars, typval_T *rettv)
4223{
4224 listitem_T *li;
4225 list_T *l;
4226 dictitem_T *di;
4227 dict_T *d;
4228 typval_T *tv = NULL;
4229
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004230 if (argvars[0].v_type == VAR_BLOB)
4231 {
4232 int error = FALSE;
4233 int idx = tv_get_number_chk(&argvars[1], &error);
4234
4235 if (!error)
4236 {
4237 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004238 if (idx < 0)
4239 idx = blob_len(argvars[0].vval.v_blob) + idx;
4240 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4241 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004242 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004243 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004244 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004245 tv = rettv;
4246 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004247 }
4248 }
4249 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004250 {
4251 if ((l = argvars[0].vval.v_list) != NULL)
4252 {
4253 int error = FALSE;
4254
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004255 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256 if (!error && li != NULL)
4257 tv = &li->li_tv;
4258 }
4259 }
4260 else if (argvars[0].v_type == VAR_DICT)
4261 {
4262 if ((d = argvars[0].vval.v_dict) != NULL)
4263 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004264 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 if (di != NULL)
4266 tv = &di->di_tv;
4267 }
4268 }
4269 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4270 {
4271 partial_T *pt;
4272 partial_T fref_pt;
4273
4274 if (argvars[0].v_type == VAR_PARTIAL)
4275 pt = argvars[0].vval.v_partial;
4276 else
4277 {
4278 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4279 fref_pt.pt_name = argvars[0].vval.v_string;
4280 pt = &fref_pt;
4281 }
4282
4283 if (pt != NULL)
4284 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004285 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004286 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004287
4288 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4289 {
4290 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004291 n = partial_name(pt);
4292 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293 rettv->vval.v_string = NULL;
4294 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004295 {
4296 rettv->vval.v_string = vim_strsave(n);
4297 if (rettv->v_type == VAR_FUNC)
4298 func_ref(rettv->vval.v_string);
4299 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004300 }
4301 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004302 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004303 else if (STRCMP(what, "args") == 0)
4304 {
4305 rettv->v_type = VAR_LIST;
4306 if (rettv_list_alloc(rettv) == OK)
4307 {
4308 int i;
4309
4310 for (i = 0; i < pt->pt_argc; ++i)
4311 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4312 }
4313 }
4314 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004315 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004316 return;
4317 }
4318 }
4319 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004320 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004321
4322 if (tv == NULL)
4323 {
4324 if (argvars[2].v_type != VAR_UNKNOWN)
4325 copy_tv(&argvars[2], rettv);
4326 }
4327 else
4328 copy_tv(tv, rettv);
4329}
4330
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004331/*
4332 * Returns buffer options, variables and other attributes in a dictionary.
4333 */
4334 static dict_T *
4335get_buffer_info(buf_T *buf)
4336{
4337 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004338 tabpage_T *tp;
4339 win_T *wp;
4340 list_T *windows;
4341
4342 dict = dict_alloc();
4343 if (dict == NULL)
4344 return NULL;
4345
Bram Moolenaare0be1672018-07-08 16:50:37 +02004346 dict_add_number(dict, "bufnr", buf->b_fnum);
4347 dict_add_string(dict, "name", buf->b_ffname);
4348 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4349 : buflist_findlnum(buf));
4350 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4351 dict_add_number(dict, "listed", buf->b_p_bl);
4352 dict_add_number(dict, "changed", bufIsChanged(buf));
4353 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4354 dict_add_number(dict, "hidden",
4355 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004356
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004357 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004358 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004359
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004360 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004361 windows = list_alloc();
4362 if (windows != NULL)
4363 {
4364 FOR_ALL_TAB_WINDOWS(tp, wp)
4365 if (wp->w_buffer == buf)
4366 list_append_number(windows, (varnumber_T)wp->w_id);
4367 dict_add_list(dict, "windows", windows);
4368 }
4369
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004370#ifdef FEAT_TEXT_PROP
4371 // List of popup windows displaying this buffer
4372 windows = list_alloc();
4373 if (windows != NULL)
4374 {
4375 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4376 if (wp->w_buffer == buf)
4377 list_append_number(windows, (varnumber_T)wp->w_id);
4378 FOR_ALL_TABPAGES(tp)
4379 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4380 if (wp->w_buffer == buf)
4381 list_append_number(windows, (varnumber_T)wp->w_id);
4382
4383 dict_add_list(dict, "popups", windows);
4384 }
4385#endif
4386
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004387#ifdef FEAT_SIGNS
4388 if (buf->b_signlist != NULL)
4389 {
4390 /* List of signs placed in this buffer */
4391 list_T *signs = list_alloc();
4392 if (signs != NULL)
4393 {
4394 get_buffer_signs(buf, signs);
4395 dict_add_list(dict, "signs", signs);
4396 }
4397 }
4398#endif
4399
4400 return dict;
4401}
4402
4403/*
4404 * "getbufinfo()" function
4405 */
4406 static void
4407f_getbufinfo(typval_T *argvars, typval_T *rettv)
4408{
4409 buf_T *buf = NULL;
4410 buf_T *argbuf = NULL;
4411 dict_T *d;
4412 int filtered = FALSE;
4413 int sel_buflisted = FALSE;
4414 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004415 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004416
4417 if (rettv_list_alloc(rettv) != OK)
4418 return;
4419
4420 /* List of all the buffers or selected buffers */
4421 if (argvars[0].v_type == VAR_DICT)
4422 {
4423 dict_T *sel_d = argvars[0].vval.v_dict;
4424
4425 if (sel_d != NULL)
4426 {
4427 dictitem_T *di;
4428
4429 filtered = TRUE;
4430
4431 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004432 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004433 sel_buflisted = TRUE;
4434
4435 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004436 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004437 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004438
4439 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004440 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004441 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004442 }
4443 }
4444 else if (argvars[0].v_type != VAR_UNKNOWN)
4445 {
4446 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004447 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004448 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004449 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004450 --emsg_off;
4451 if (argbuf == NULL)
4452 return;
4453 }
4454
4455 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004456 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004457 {
4458 if (argbuf != NULL && argbuf != buf)
4459 continue;
4460 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004461 || (sel_buflisted && !buf->b_p_bl)
4462 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004463 continue;
4464
4465 d = get_buffer_info(buf);
4466 if (d != NULL)
4467 list_append_dict(rettv->vval.v_list, d);
4468 if (argbuf != NULL)
4469 return;
4470 }
4471}
4472
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004473/*
4474 * Get line or list of lines from buffer "buf" into "rettv".
4475 * Return a range (from start to end) of lines in rettv from the specified
4476 * buffer.
4477 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4478 */
4479 static void
4480get_buffer_lines(
4481 buf_T *buf,
4482 linenr_T start,
4483 linenr_T end,
4484 int retlist,
4485 typval_T *rettv)
4486{
4487 char_u *p;
4488
4489 rettv->v_type = VAR_STRING;
4490 rettv->vval.v_string = NULL;
4491 if (retlist && rettv_list_alloc(rettv) == FAIL)
4492 return;
4493
4494 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4495 return;
4496
4497 if (!retlist)
4498 {
4499 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4500 p = ml_get_buf(buf, start, FALSE);
4501 else
4502 p = (char_u *)"";
4503 rettv->vval.v_string = vim_strsave(p);
4504 }
4505 else
4506 {
4507 if (end < start)
4508 return;
4509
4510 if (start < 1)
4511 start = 1;
4512 if (end > buf->b_ml.ml_line_count)
4513 end = buf->b_ml.ml_line_count;
4514 while (start <= end)
4515 if (list_append_string(rettv->vval.v_list,
4516 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4517 break;
4518 }
4519}
4520
4521/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522 * "getbufline()" function
4523 */
4524 static void
4525f_getbufline(typval_T *argvars, typval_T *rettv)
4526{
4527 linenr_T lnum;
4528 linenr_T end;
4529 buf_T *buf;
4530
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004531 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004532 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004533 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534 --emsg_off;
4535
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004536 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004537 if (argvars[2].v_type == VAR_UNKNOWN)
4538 end = lnum;
4539 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004540 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004541
4542 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4543}
4544
4545/*
4546 * "getbufvar()" function
4547 */
4548 static void
4549f_getbufvar(typval_T *argvars, typval_T *rettv)
4550{
4551 buf_T *buf;
4552 buf_T *save_curbuf;
4553 char_u *varname;
4554 dictitem_T *v;
4555 int done = FALSE;
4556
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004557 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4558 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004559 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004560 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004561
4562 rettv->v_type = VAR_STRING;
4563 rettv->vval.v_string = NULL;
4564
4565 if (buf != NULL && varname != NULL)
4566 {
4567 /* set curbuf to be our buf, temporarily */
4568 save_curbuf = curbuf;
4569 curbuf = buf;
4570
Bram Moolenaar30567352016-08-27 21:25:44 +02004571 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004572 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004573 if (varname[1] == NUL)
4574 {
4575 /* get all buffer-local options in a dict */
4576 dict_T *opts = get_winbuf_options(TRUE);
4577
4578 if (opts != NULL)
4579 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004580 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004581 done = TRUE;
4582 }
4583 }
4584 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4585 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586 done = TRUE;
4587 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004588 else
4589 {
4590 /* Look up the variable. */
4591 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4592 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4593 'b', varname, FALSE);
4594 if (v != NULL)
4595 {
4596 copy_tv(&v->di_tv, rettv);
4597 done = TRUE;
4598 }
4599 }
4600
4601 /* restore previous notion of curbuf */
4602 curbuf = save_curbuf;
4603 }
4604
4605 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4606 /* use the default value */
4607 copy_tv(&argvars[2], rettv);
4608
4609 --emsg_off;
4610}
4611
4612/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004613 * "getchangelist()" function
4614 */
4615 static void
4616f_getchangelist(typval_T *argvars, typval_T *rettv)
4617{
4618#ifdef FEAT_JUMPLIST
4619 buf_T *buf;
4620 int i;
4621 list_T *l;
4622 dict_T *d;
4623#endif
4624
4625 if (rettv_list_alloc(rettv) != OK)
4626 return;
4627
4628#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004629 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004630 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004631 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004632 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004633 if (buf == NULL)
4634 return;
4635
4636 l = list_alloc();
4637 if (l == NULL)
4638 return;
4639
4640 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4641 return;
4642 /*
4643 * The current window change list index tracks only the position in the
4644 * current buffer change list. For other buffers, use the change list
4645 * length as the current index.
4646 */
4647 list_append_number(rettv->vval.v_list,
4648 (varnumber_T)((buf == curwin->w_buffer)
4649 ? curwin->w_changelistidx : buf->b_changelistlen));
4650
4651 for (i = 0; i < buf->b_changelistlen; ++i)
4652 {
4653 if (buf->b_changelist[i].lnum == 0)
4654 continue;
4655 if ((d = dict_alloc()) == NULL)
4656 return;
4657 if (list_append_dict(l, d) == FAIL)
4658 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004659 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4660 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004661 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004662 }
4663#endif
4664}
4665/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004666 * "getchar()" function
4667 */
4668 static void
4669f_getchar(typval_T *argvars, typval_T *rettv)
4670{
4671 varnumber_T n;
4672 int error = FALSE;
4673
Bram Moolenaar84d93902018-09-11 20:10:20 +02004674#ifdef MESSAGE_QUEUE
4675 // vpeekc() used to check for messages, but that caused problems, invoking
4676 // a callback where it was not expected. Some plugins use getchar(1) in a
4677 // loop to await a message, therefore make sure we check for messages here.
4678 parse_queued_messages();
4679#endif
4680
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681 /* Position the cursor. Needed after a message that ends in a space. */
4682 windgoto(msg_row, msg_col);
4683
4684 ++no_mapping;
4685 ++allow_keys;
4686 for (;;)
4687 {
4688 if (argvars[0].v_type == VAR_UNKNOWN)
4689 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004690 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004691 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004692 /* getchar(1): only check if char avail */
4693 n = vpeekc_any();
4694 else if (error || vpeekc_any() == NUL)
4695 /* illegal argument or getchar(0) and no char avail: return zero */
4696 n = 0;
4697 else
4698 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004699 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700
4701 if (n == K_IGNORE)
4702 continue;
4703 break;
4704 }
4705 --no_mapping;
4706 --allow_keys;
4707
4708 set_vim_var_nr(VV_MOUSE_WIN, 0);
4709 set_vim_var_nr(VV_MOUSE_WINID, 0);
4710 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4711 set_vim_var_nr(VV_MOUSE_COL, 0);
4712
4713 rettv->vval.v_number = n;
4714 if (IS_SPECIAL(n) || mod_mask != 0)
4715 {
4716 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4717 int i = 0;
4718
4719 /* Turn a special key into three bytes, plus modifier. */
4720 if (mod_mask != 0)
4721 {
4722 temp[i++] = K_SPECIAL;
4723 temp[i++] = KS_MODIFIER;
4724 temp[i++] = mod_mask;
4725 }
4726 if (IS_SPECIAL(n))
4727 {
4728 temp[i++] = K_SPECIAL;
4729 temp[i++] = K_SECOND(n);
4730 temp[i++] = K_THIRD(n);
4731 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732 else if (has_mbyte)
4733 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 else
4735 temp[i++] = n;
4736 temp[i++] = NUL;
4737 rettv->v_type = VAR_STRING;
4738 rettv->vval.v_string = vim_strsave(temp);
4739
4740#ifdef FEAT_MOUSE
4741 if (is_mouse_key(n))
4742 {
4743 int row = mouse_row;
4744 int col = mouse_col;
4745 win_T *win;
4746 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004747 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748 int winnr = 1;
4749
4750 if (row >= 0 && col >= 0)
4751 {
4752 /* Find the window at the mouse coordinates and compute the
4753 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004754 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004755 if (win == NULL)
4756 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004757 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004758# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004759 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004760 winnr = 0;
4761 else
4762# endif
4763 for (wp = firstwin; wp != win && wp != NULL;
4764 wp = wp->w_next)
4765 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4767 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4768 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4769 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4770 }
4771 }
4772#endif
4773 }
4774}
4775
4776/*
4777 * "getcharmod()" function
4778 */
4779 static void
4780f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4781{
4782 rettv->vval.v_number = mod_mask;
4783}
4784
4785/*
4786 * "getcharsearch()" function
4787 */
4788 static void
4789f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4790{
4791 if (rettv_dict_alloc(rettv) != FAIL)
4792 {
4793 dict_T *dict = rettv->vval.v_dict;
4794
Bram Moolenaare0be1672018-07-08 16:50:37 +02004795 dict_add_string(dict, "char", last_csearch());
4796 dict_add_number(dict, "forward", last_csearch_forward());
4797 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004798 }
4799}
4800
4801/*
4802 * "getcmdline()" function
4803 */
4804 static void
4805f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4806{
4807 rettv->v_type = VAR_STRING;
4808 rettv->vval.v_string = get_cmdline_str();
4809}
4810
4811/*
4812 * "getcmdpos()" function
4813 */
4814 static void
4815f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4816{
4817 rettv->vval.v_number = get_cmdline_pos() + 1;
4818}
4819
4820/*
4821 * "getcmdtype()" function
4822 */
4823 static void
4824f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4825{
4826 rettv->v_type = VAR_STRING;
4827 rettv->vval.v_string = alloc(2);
4828 if (rettv->vval.v_string != NULL)
4829 {
4830 rettv->vval.v_string[0] = get_cmdline_type();
4831 rettv->vval.v_string[1] = NUL;
4832 }
4833}
4834
4835/*
4836 * "getcmdwintype()" function
4837 */
4838 static void
4839f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4840{
4841 rettv->v_type = VAR_STRING;
4842 rettv->vval.v_string = NULL;
4843#ifdef FEAT_CMDWIN
4844 rettv->vval.v_string = alloc(2);
4845 if (rettv->vval.v_string != NULL)
4846 {
4847 rettv->vval.v_string[0] = cmdwin_type;
4848 rettv->vval.v_string[1] = NUL;
4849 }
4850#endif
4851}
4852
4853#if defined(FEAT_CMDL_COMPL)
4854/*
4855 * "getcompletion()" function
4856 */
4857 static void
4858f_getcompletion(typval_T *argvars, typval_T *rettv)
4859{
4860 char_u *pat;
4861 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004862 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004863 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4864 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004865
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004866 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004867 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004869 if (p_wic)
4870 options |= WILD_ICASE;
4871
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004872 /* For filtered results, 'wildignore' is used */
4873 if (!filtered)
4874 options |= WILD_KEEP_ALL;
4875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004876 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004877 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004879 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004880 if (xpc.xp_context == EXPAND_NOTHING)
4881 {
4882 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004883 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004884 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004885 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886 return;
4887 }
4888
4889# if defined(FEAT_MENU)
4890 if (xpc.xp_context == EXPAND_MENUS)
4891 {
4892 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4893 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4894 }
4895# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004896#ifdef FEAT_CSCOPE
4897 if (xpc.xp_context == EXPAND_CSCOPE)
4898 {
4899 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4900 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4901 }
4902#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004903#ifdef FEAT_SIGNS
4904 if (xpc.xp_context == EXPAND_SIGN)
4905 {
4906 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4907 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4908 }
4909#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910
4911 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4912 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4913 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004914 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915
4916 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4917
4918 for (i = 0; i < xpc.xp_numfiles; i++)
4919 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4920 }
4921 vim_free(pat);
4922 ExpandCleanup(&xpc);
4923}
4924#endif
4925
4926/*
4927 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004928 *
4929 * Return the current working directory of a window in a tab page.
4930 * First optional argument 'winnr' is the window number or -1 and the second
4931 * optional argument 'tabnr' is the tab page number.
4932 *
4933 * If no arguments are supplied, then return the directory of the current
4934 * window.
4935 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4936 * the specified window.
4937 * If 'winnr' is 0 then return the directory of the current window.
4938 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4939 * directory of the specified tab page. Otherwise return the directory of the
4940 * specified window in the specified tab page.
4941 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 */
4943 static void
4944f_getcwd(typval_T *argvars, typval_T *rettv)
4945{
4946 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004947 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004948 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004949 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004950
4951 rettv->v_type = VAR_STRING;
4952 rettv->vval.v_string = NULL;
4953
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004954 if (argvars[0].v_type == VAR_NUMBER
4955 && argvars[0].vval.v_number == -1
4956 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004957 global = TRUE;
4958 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004959 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004960
4961 if (wp != NULL && wp->w_localdir != NULL)
4962 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004963 else if (tp != NULL && tp->tp_localdir != NULL)
4964 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4965 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004966 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004967 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004968 rettv->vval.v_string = vim_strsave(globaldir);
4969 else
4970 {
4971 cwd = alloc(MAXPATHL);
4972 if (cwd != NULL)
4973 {
4974 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4975 rettv->vval.v_string = vim_strsave(cwd);
4976 vim_free(cwd);
4977 }
4978 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004979 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004980#ifdef BACKSLASH_IN_FILENAME
4981 if (rettv->vval.v_string != NULL)
4982 slash_adjust(rettv->vval.v_string);
4983#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984}
4985
4986/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004987 * "getenv()" function
4988 */
4989 static void
4990f_getenv(typval_T *argvars, typval_T *rettv)
4991{
4992 int mustfree = FALSE;
4993 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4994
4995 if (p == NULL)
4996 {
4997 rettv->v_type = VAR_SPECIAL;
4998 rettv->vval.v_number = VVAL_NULL;
4999 return;
5000 }
5001 if (!mustfree)
5002 p = vim_strsave(p);
5003 rettv->vval.v_string = p;
5004 rettv->v_type = VAR_STRING;
5005}
5006
5007/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005008 * "getfontname()" function
5009 */
5010 static void
5011f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5012{
5013 rettv->v_type = VAR_STRING;
5014 rettv->vval.v_string = NULL;
5015#ifdef FEAT_GUI
5016 if (gui.in_use)
5017 {
5018 GuiFont font;
5019 char_u *name = NULL;
5020
5021 if (argvars[0].v_type == VAR_UNKNOWN)
5022 {
5023 /* Get the "Normal" font. Either the name saved by
5024 * hl_set_font_name() or from the font ID. */
5025 font = gui.norm_font;
5026 name = hl_get_font_name();
5027 }
5028 else
5029 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005030 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5032 return;
5033 font = gui_mch_get_font(name, FALSE);
5034 if (font == NOFONT)
5035 return; /* Invalid font name, return empty string. */
5036 }
5037 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5038 if (argvars[0].v_type != VAR_UNKNOWN)
5039 gui_mch_free_font(font);
5040 }
5041#endif
5042}
5043
5044/*
5045 * "getfperm({fname})" function
5046 */
5047 static void
5048f_getfperm(typval_T *argvars, typval_T *rettv)
5049{
5050 char_u *fname;
5051 stat_T st;
5052 char_u *perm = NULL;
5053 char_u flags[] = "rwx";
5054 int i;
5055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005056 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005057
5058 rettv->v_type = VAR_STRING;
5059 if (mch_stat((char *)fname, &st) >= 0)
5060 {
5061 perm = vim_strsave((char_u *)"---------");
5062 if (perm != NULL)
5063 {
5064 for (i = 0; i < 9; i++)
5065 {
5066 if (st.st_mode & (1 << (8 - i)))
5067 perm[i] = flags[i % 3];
5068 }
5069 }
5070 }
5071 rettv->vval.v_string = perm;
5072}
5073
5074/*
5075 * "getfsize({fname})" function
5076 */
5077 static void
5078f_getfsize(typval_T *argvars, typval_T *rettv)
5079{
5080 char_u *fname;
5081 stat_T st;
5082
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005083 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005084
5085 rettv->v_type = VAR_NUMBER;
5086
5087 if (mch_stat((char *)fname, &st) >= 0)
5088 {
5089 if (mch_isdir(fname))
5090 rettv->vval.v_number = 0;
5091 else
5092 {
5093 rettv->vval.v_number = (varnumber_T)st.st_size;
5094
5095 /* non-perfect check for overflow */
5096 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5097 rettv->vval.v_number = -2;
5098 }
5099 }
5100 else
5101 rettv->vval.v_number = -1;
5102}
5103
5104/*
5105 * "getftime({fname})" function
5106 */
5107 static void
5108f_getftime(typval_T *argvars, typval_T *rettv)
5109{
5110 char_u *fname;
5111 stat_T st;
5112
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005113 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114
5115 if (mch_stat((char *)fname, &st) >= 0)
5116 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5117 else
5118 rettv->vval.v_number = -1;
5119}
5120
5121/*
5122 * "getftype({fname})" function
5123 */
5124 static void
5125f_getftype(typval_T *argvars, typval_T *rettv)
5126{
5127 char_u *fname;
5128 stat_T st;
5129 char_u *type = NULL;
5130 char *t;
5131
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005132 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005133
5134 rettv->v_type = VAR_STRING;
5135 if (mch_lstat((char *)fname, &st) >= 0)
5136 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 if (S_ISREG(st.st_mode))
5138 t = "file";
5139 else if (S_ISDIR(st.st_mode))
5140 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005141 else if (S_ISLNK(st.st_mode))
5142 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005143 else if (S_ISBLK(st.st_mode))
5144 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 else if (S_ISCHR(st.st_mode))
5146 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005147 else if (S_ISFIFO(st.st_mode))
5148 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005149 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005150 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005151 else
5152 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005153 type = vim_strsave((char_u *)t);
5154 }
5155 rettv->vval.v_string = type;
5156}
5157
5158/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005159 * "getjumplist()" function
5160 */
5161 static void
5162f_getjumplist(typval_T *argvars, typval_T *rettv)
5163{
5164#ifdef FEAT_JUMPLIST
5165 win_T *wp;
5166 int i;
5167 list_T *l;
5168 dict_T *d;
5169#endif
5170
5171 if (rettv_list_alloc(rettv) != OK)
5172 return;
5173
5174#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005175 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005176 if (wp == NULL)
5177 return;
5178
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005179 cleanup_jumplist(wp, TRUE);
5180
Bram Moolenaar4f505882018-02-10 21:06:32 +01005181 l = list_alloc();
5182 if (l == NULL)
5183 return;
5184
5185 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5186 return;
5187 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5188
5189 for (i = 0; i < wp->w_jumplistlen; ++i)
5190 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005191 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5192 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005193 if ((d = dict_alloc()) == NULL)
5194 return;
5195 if (list_append_dict(l, d) == FAIL)
5196 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005197 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5198 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005199 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005200 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005201 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005202 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005203 }
5204#endif
5205}
5206
5207/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005208 * "getline(lnum, [end])" function
5209 */
5210 static void
5211f_getline(typval_T *argvars, typval_T *rettv)
5212{
5213 linenr_T lnum;
5214 linenr_T end;
5215 int retlist;
5216
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005217 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005218 if (argvars[1].v_type == VAR_UNKNOWN)
5219 {
5220 end = 0;
5221 retlist = FALSE;
5222 }
5223 else
5224 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005225 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005226 retlist = TRUE;
5227 }
5228
5229 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5230}
5231
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005232#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005233 static void
5234get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5235{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005236 if (what_arg->v_type == VAR_UNKNOWN)
5237 {
5238 if (rettv_list_alloc(rettv) == OK)
5239 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005240 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005241 }
5242 else
5243 {
5244 if (rettv_dict_alloc(rettv) == OK)
5245 if (is_qf || (wp != NULL))
5246 {
5247 if (what_arg->v_type == VAR_DICT)
5248 {
5249 dict_T *d = what_arg->vval.v_dict;
5250
5251 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005252 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005253 }
5254 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005255 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005256 }
5257 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005258}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005259#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005260
5261/*
5262 * "getloclist()" function
5263 */
5264 static void
5265f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5266{
5267#ifdef FEAT_QUICKFIX
5268 win_T *wp;
5269
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005270 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005271 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5272#endif
5273}
5274
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005275/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005276 * "getpid()" function
5277 */
5278 static void
5279f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5280{
5281 rettv->vval.v_number = mch_get_pid();
5282}
5283
5284 static void
5285getpos_both(
5286 typval_T *argvars,
5287 typval_T *rettv,
5288 int getcurpos)
5289{
5290 pos_T *fp;
5291 list_T *l;
5292 int fnum = -1;
5293
5294 if (rettv_list_alloc(rettv) == OK)
5295 {
5296 l = rettv->vval.v_list;
5297 if (getcurpos)
5298 fp = &curwin->w_cursor;
5299 else
5300 fp = var2fpos(&argvars[0], TRUE, &fnum);
5301 if (fnum != -1)
5302 list_append_number(l, (varnumber_T)fnum);
5303 else
5304 list_append_number(l, (varnumber_T)0);
5305 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5306 : (varnumber_T)0);
5307 list_append_number(l, (fp != NULL)
5308 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5309 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005310 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005311 (varnumber_T)0);
5312 if (getcurpos)
5313 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005314 int save_set_curswant = curwin->w_set_curswant;
5315 colnr_T save_curswant = curwin->w_curswant;
5316 colnr_T save_virtcol = curwin->w_virtcol;
5317
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 update_curswant();
5319 list_append_number(l, curwin->w_curswant == MAXCOL ?
5320 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005321
5322 // Do not change "curswant", as it is unexpected that a get
5323 // function has a side effect.
5324 if (save_set_curswant)
5325 {
5326 curwin->w_set_curswant = save_set_curswant;
5327 curwin->w_curswant = save_curswant;
5328 curwin->w_virtcol = save_virtcol;
5329 curwin->w_valid &= ~VALID_VIRTCOL;
5330 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005331 }
5332 }
5333 else
5334 rettv->vval.v_number = FALSE;
5335}
5336
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005337/*
5338 * "getcurpos()" function
5339 */
5340 static void
5341f_getcurpos(typval_T *argvars, typval_T *rettv)
5342{
5343 getpos_both(argvars, rettv, TRUE);
5344}
5345
5346/*
5347 * "getpos(string)" function
5348 */
5349 static void
5350f_getpos(typval_T *argvars, typval_T *rettv)
5351{
5352 getpos_both(argvars, rettv, FALSE);
5353}
5354
5355/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005356 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005357 */
5358 static void
5359f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5360{
5361#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005362 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005363#endif
5364}
5365
5366/*
5367 * "getreg()" function
5368 */
5369 static void
5370f_getreg(typval_T *argvars, typval_T *rettv)
5371{
5372 char_u *strregname;
5373 int regname;
5374 int arg2 = FALSE;
5375 int return_list = FALSE;
5376 int error = FALSE;
5377
5378 if (argvars[0].v_type != VAR_UNKNOWN)
5379 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005380 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381 error = strregname == NULL;
5382 if (argvars[1].v_type != VAR_UNKNOWN)
5383 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005384 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005385 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005386 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005387 }
5388 }
5389 else
5390 strregname = get_vim_var_str(VV_REG);
5391
5392 if (error)
5393 return;
5394
5395 regname = (strregname == NULL ? '"' : *strregname);
5396 if (regname == 0)
5397 regname = '"';
5398
5399 if (return_list)
5400 {
5401 rettv->v_type = VAR_LIST;
5402 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5403 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5404 if (rettv->vval.v_list == NULL)
5405 (void)rettv_list_alloc(rettv);
5406 else
5407 ++rettv->vval.v_list->lv_refcount;
5408 }
5409 else
5410 {
5411 rettv->v_type = VAR_STRING;
5412 rettv->vval.v_string = get_reg_contents(regname,
5413 arg2 ? GREG_EXPR_SRC : 0);
5414 }
5415}
5416
5417/*
5418 * "getregtype()" function
5419 */
5420 static void
5421f_getregtype(typval_T *argvars, typval_T *rettv)
5422{
5423 char_u *strregname;
5424 int regname;
5425 char_u buf[NUMBUFLEN + 2];
5426 long reglen = 0;
5427
5428 if (argvars[0].v_type != VAR_UNKNOWN)
5429 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005430 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005431 if (strregname == NULL) /* type error; errmsg already given */
5432 {
5433 rettv->v_type = VAR_STRING;
5434 rettv->vval.v_string = NULL;
5435 return;
5436 }
5437 }
5438 else
5439 /* Default to v:register */
5440 strregname = get_vim_var_str(VV_REG);
5441
5442 regname = (strregname == NULL ? '"' : *strregname);
5443 if (regname == 0)
5444 regname = '"';
5445
5446 buf[0] = NUL;
5447 buf[1] = NUL;
5448 switch (get_reg_type(regname, &reglen))
5449 {
5450 case MLINE: buf[0] = 'V'; break;
5451 case MCHAR: buf[0] = 'v'; break;
5452 case MBLOCK:
5453 buf[0] = Ctrl_V;
5454 sprintf((char *)buf + 1, "%ld", reglen + 1);
5455 break;
5456 }
5457 rettv->v_type = VAR_STRING;
5458 rettv->vval.v_string = vim_strsave(buf);
5459}
5460
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005461/*
5462 * Returns information (variables, options, etc.) about a tab page
5463 * as a dictionary.
5464 */
5465 static dict_T *
5466get_tabpage_info(tabpage_T *tp, int tp_idx)
5467{
5468 win_T *wp;
5469 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005470 list_T *l;
5471
5472 dict = dict_alloc();
5473 if (dict == NULL)
5474 return NULL;
5475
Bram Moolenaare0be1672018-07-08 16:50:37 +02005476 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005477
5478 l = list_alloc();
5479 if (l != NULL)
5480 {
5481 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005482 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005483 list_append_number(l, (varnumber_T)wp->w_id);
5484 dict_add_list(dict, "windows", l);
5485 }
5486
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005487 /* Make a reference to tabpage variables */
5488 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005489
5490 return dict;
5491}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005492
5493/*
5494 * "gettabinfo()" function
5495 */
5496 static void
5497f_gettabinfo(typval_T *argvars, typval_T *rettv)
5498{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005499 tabpage_T *tp, *tparg = NULL;
5500 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005501 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005502
5503 if (rettv_list_alloc(rettv) != OK)
5504 return;
5505
5506 if (argvars[0].v_type != VAR_UNKNOWN)
5507 {
5508 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005509 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005510 if (tparg == NULL)
5511 return;
5512 }
5513
5514 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005515 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005516 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005517 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005518 if (tparg != NULL && tp != tparg)
5519 continue;
5520 d = get_tabpage_info(tp, tpnr);
5521 if (d != NULL)
5522 list_append_dict(rettv->vval.v_list, d);
5523 if (tparg != NULL)
5524 return;
5525 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005526}
5527
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528/*
5529 * "gettabvar()" function
5530 */
5531 static void
5532f_gettabvar(typval_T *argvars, typval_T *rettv)
5533{
5534 win_T *oldcurwin;
5535 tabpage_T *tp, *oldtabpage;
5536 dictitem_T *v;
5537 char_u *varname;
5538 int done = FALSE;
5539
5540 rettv->v_type = VAR_STRING;
5541 rettv->vval.v_string = NULL;
5542
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005543 varname = tv_get_string_chk(&argvars[1]);
5544 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005545 if (tp != NULL && varname != NULL)
5546 {
5547 /* Set tp to be our tabpage, temporarily. Also set the window to the
5548 * first window in the tabpage, otherwise the window is not valid. */
5549 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005550 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5551 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005552 {
5553 /* look up the variable */
5554 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5555 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5556 if (v != NULL)
5557 {
5558 copy_tv(&v->di_tv, rettv);
5559 done = TRUE;
5560 }
5561 }
5562
5563 /* restore previous notion of curwin */
5564 restore_win(oldcurwin, oldtabpage, TRUE);
5565 }
5566
5567 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5568 copy_tv(&argvars[2], rettv);
5569}
5570
5571/*
5572 * "gettabwinvar()" function
5573 */
5574 static void
5575f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5576{
5577 getwinvar(argvars, rettv, 1);
5578}
5579
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005580/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005581 * "gettagstack()" function
5582 */
5583 static void
5584f_gettagstack(typval_T *argvars, typval_T *rettv)
5585{
5586 win_T *wp = curwin; // default is current window
5587
5588 if (rettv_dict_alloc(rettv) != OK)
5589 return;
5590
5591 if (argvars[0].v_type != VAR_UNKNOWN)
5592 {
5593 wp = find_win_by_nr_or_id(&argvars[0]);
5594 if (wp == NULL)
5595 return;
5596 }
5597
5598 get_tagstack(wp, rettv->vval.v_dict);
5599}
5600
5601/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005602 * Returns information about a window as a dictionary.
5603 */
5604 static dict_T *
5605get_win_info(win_T *wp, short tpnr, short winnr)
5606{
5607 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005608
5609 dict = dict_alloc();
5610 if (dict == NULL)
5611 return NULL;
5612
Bram Moolenaare0be1672018-07-08 16:50:37 +02005613 dict_add_number(dict, "tabnr", tpnr);
5614 dict_add_number(dict, "winnr", winnr);
5615 dict_add_number(dict, "winid", wp->w_id);
5616 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005617 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005618 dict_add_number(dict, "topline", wp->w_topline);
5619 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005620#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005621 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005622#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005623 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005624 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005625 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005626
Bram Moolenaar69905d12017-08-13 18:14:47 +02005627#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005628 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005629#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005630#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005631 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5632 dict_add_number(dict, "loclist",
5633 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005634#endif
5635
Bram Moolenaar30567352016-08-27 21:25:44 +02005636 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005637 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005638
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005639 return dict;
5640}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005641
5642/*
5643 * "getwininfo()" function
5644 */
5645 static void
5646f_getwininfo(typval_T *argvars, typval_T *rettv)
5647{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005648 tabpage_T *tp;
5649 win_T *wp = NULL, *wparg = NULL;
5650 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005651 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005652
5653 if (rettv_list_alloc(rettv) != OK)
5654 return;
5655
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005656 if (argvars[0].v_type != VAR_UNKNOWN)
5657 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005658 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005659 if (wparg == NULL)
5660 return;
5661 }
5662
5663 /* Collect information about either all the windows across all the tab
5664 * pages or one particular window.
5665 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005666 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005667 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005668 tabnr++;
5669 winnr = 0;
5670 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005671 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005672 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005673 if (wparg != NULL && wp != wparg)
5674 continue;
5675 d = get_win_info(wp, tabnr, winnr);
5676 if (d != NULL)
5677 list_append_dict(rettv->vval.v_list, d);
5678 if (wparg != NULL)
5679 /* found information about a specific window */
5680 return;
5681 }
5682 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005683}
5684
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005686 * "win_execute()" function
5687 */
5688 static void
5689f_win_execute(typval_T *argvars, typval_T *rettv)
5690{
5691 int id = (int)tv_get_number(argvars);
5692 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005693 win_T *save_curwin;
5694 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005695
5696 if (wp != NULL)
5697 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005698 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5699 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005700 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005701 check_cursor();
5702 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005703 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005704 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005705 }
5706}
5707
5708/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005709 * "win_findbuf()" function
5710 */
5711 static void
5712f_win_findbuf(typval_T *argvars, typval_T *rettv)
5713{
5714 if (rettv_list_alloc(rettv) != FAIL)
5715 win_findbuf(argvars, rettv->vval.v_list);
5716}
5717
5718/*
5719 * "win_getid()" function
5720 */
5721 static void
5722f_win_getid(typval_T *argvars, typval_T *rettv)
5723{
5724 rettv->vval.v_number = win_getid(argvars);
5725}
5726
5727/*
5728 * "win_gotoid()" function
5729 */
5730 static void
5731f_win_gotoid(typval_T *argvars, typval_T *rettv)
5732{
5733 rettv->vval.v_number = win_gotoid(argvars);
5734}
5735
5736/*
5737 * "win_id2tabwin()" function
5738 */
5739 static void
5740f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5741{
5742 if (rettv_list_alloc(rettv) != FAIL)
5743 win_id2tabwin(argvars, rettv->vval.v_list);
5744}
5745
5746/*
5747 * "win_id2win()" function
5748 */
5749 static void
5750f_win_id2win(typval_T *argvars, typval_T *rettv)
5751{
5752 rettv->vval.v_number = win_id2win(argvars);
5753}
5754
5755/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005756 * "win_screenpos()" function
5757 */
5758 static void
5759f_win_screenpos(typval_T *argvars, typval_T *rettv)
5760{
5761 win_T *wp;
5762
5763 if (rettv_list_alloc(rettv) == FAIL)
5764 return;
5765
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005766 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005767 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5768 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5769}
5770
5771/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005772 * "getwinpos({timeout})" function
5773 */
5774 static void
5775f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5776{
5777 int x = -1;
5778 int y = -1;
5779
5780 if (rettv_list_alloc(rettv) == FAIL)
5781 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005782#if defined(FEAT_GUI) \
5783 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5784 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005785 {
5786 varnumber_T timeout = 100;
5787
5788 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005789 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005790
5791 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005792 }
5793#endif
5794 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5795 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5796}
5797
5798
5799/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005800 * "getwinposx()" function
5801 */
5802 static void
5803f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5804{
5805 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005806#if defined(FEAT_GUI) \
5807 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5808 || defined(MSWIN)
5809
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005810 {
5811 int x, y;
5812
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005813 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005814 rettv->vval.v_number = x;
5815 }
5816#endif
5817}
5818
5819/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005820 * "getwinposy()" function
5821 */
5822 static void
5823f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5824{
5825 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005826#if defined(FEAT_GUI) \
5827 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5828 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 {
5830 int x, y;
5831
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005832 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005833 rettv->vval.v_number = y;
5834 }
5835#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005836}
5837
5838/*
5839 * "getwinvar()" function
5840 */
5841 static void
5842f_getwinvar(typval_T *argvars, typval_T *rettv)
5843{
5844 getwinvar(argvars, rettv, 0);
5845}
5846
5847/*
5848 * "glob()" function
5849 */
5850 static void
5851f_glob(typval_T *argvars, typval_T *rettv)
5852{
5853 int options = WILD_SILENT|WILD_USE_NL;
5854 expand_T xpc;
5855 int error = FALSE;
5856
5857 /* When the optional second argument is non-zero, don't remove matches
5858 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5859 rettv->v_type = VAR_STRING;
5860 if (argvars[1].v_type != VAR_UNKNOWN)
5861 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005862 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005863 options |= WILD_KEEP_ALL;
5864 if (argvars[2].v_type != VAR_UNKNOWN)
5865 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005866 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005867 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005869 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005870 options |= WILD_ALLLINKS;
5871 }
5872 }
5873 if (!error)
5874 {
5875 ExpandInit(&xpc);
5876 xpc.xp_context = EXPAND_FILES;
5877 if (p_wic)
5878 options += WILD_ICASE;
5879 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005880 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005881 NULL, options, WILD_ALL);
5882 else if (rettv_list_alloc(rettv) != FAIL)
5883 {
5884 int i;
5885
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005886 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005887 NULL, options, WILD_ALL_KEEP);
5888 for (i = 0; i < xpc.xp_numfiles; i++)
5889 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5890
5891 ExpandCleanup(&xpc);
5892 }
5893 }
5894 else
5895 rettv->vval.v_string = NULL;
5896}
5897
5898/*
5899 * "globpath()" function
5900 */
5901 static void
5902f_globpath(typval_T *argvars, typval_T *rettv)
5903{
5904 int flags = 0;
5905 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005906 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005907 int error = FALSE;
5908 garray_T ga;
5909 int i;
5910
5911 /* When the optional second argument is non-zero, don't remove matches
5912 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5913 rettv->v_type = VAR_STRING;
5914 if (argvars[2].v_type != VAR_UNKNOWN)
5915 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005916 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005917 flags |= WILD_KEEP_ALL;
5918 if (argvars[3].v_type != VAR_UNKNOWN)
5919 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005920 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005921 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005922 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005923 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005924 flags |= WILD_ALLLINKS;
5925 }
5926 }
5927 if (file != NULL && !error)
5928 {
5929 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005930 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005931 if (rettv->v_type == VAR_STRING)
5932 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5933 else if (rettv_list_alloc(rettv) != FAIL)
5934 for (i = 0; i < ga.ga_len; ++i)
5935 list_append_string(rettv->vval.v_list,
5936 ((char_u **)(ga.ga_data))[i], -1);
5937 ga_clear_strings(&ga);
5938 }
5939 else
5940 rettv->vval.v_string = NULL;
5941}
5942
5943/*
5944 * "glob2regpat()" function
5945 */
5946 static void
5947f_glob2regpat(typval_T *argvars, typval_T *rettv)
5948{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005949 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005950
5951 rettv->v_type = VAR_STRING;
5952 rettv->vval.v_string = (pat == NULL)
5953 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5954}
5955
5956/* for VIM_VERSION_ defines */
5957#include "version.h"
5958
5959/*
5960 * "has()" function
5961 */
5962 static void
5963f_has(typval_T *argvars, typval_T *rettv)
5964{
5965 int i;
5966 char_u *name;
5967 int n = FALSE;
5968 static char *(has_list[]) =
5969 {
5970#ifdef AMIGA
5971 "amiga",
5972# ifdef FEAT_ARP
5973 "arp",
5974# endif
5975#endif
5976#ifdef __BEOS__
5977 "beos",
5978#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005979#if defined(BSD) && !defined(MACOS_X)
5980 "bsd",
5981#endif
5982#ifdef hpux
5983 "hpux",
5984#endif
5985#ifdef __linux__
5986 "linux",
5987#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005988#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005989 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5990 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005991# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005992 "macunix", /* Mac OS X, with the darwin feature */
5993 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005994# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005995#endif
5996#ifdef __QNX__
5997 "qnx",
5998#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005999#ifdef SUN_SYSTEM
6000 "sun",
6001#else
6002 "moon",
6003#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004#ifdef UNIX
6005 "unix",
6006#endif
6007#ifdef VMS
6008 "vms",
6009#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006010#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006011 "win32",
6012#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006013#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006014 "win32unix",
6015#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006016#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 "win64",
6018#endif
6019#ifdef EBCDIC
6020 "ebcdic",
6021#endif
6022#ifndef CASE_INSENSITIVE_FILENAME
6023 "fname_case",
6024#endif
6025#ifdef HAVE_ACL
6026 "acl",
6027#endif
6028#ifdef FEAT_ARABIC
6029 "arabic",
6030#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006032#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006033 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006034#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006035#ifdef FEAT_AUTOSERVERNAME
6036 "autoservername",
6037#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006038#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006039 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006040# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006041 "balloon_multiline",
6042# endif
6043#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006044#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006045 "balloon_eval_term",
6046#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006047#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6048 "builtin_terms",
6049# ifdef ALL_BUILTIN_TCAPS
6050 "all_builtin_terms",
6051# endif
6052#endif
6053#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006054 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006055 || defined(FEAT_GUI_MOTIF))
6056 "browsefilter",
6057#endif
6058#ifdef FEAT_BYTEOFF
6059 "byte_offset",
6060#endif
6061#ifdef FEAT_JOB_CHANNEL
6062 "channel",
6063#endif
6064#ifdef FEAT_CINDENT
6065 "cindent",
6066#endif
6067#ifdef FEAT_CLIENTSERVER
6068 "clientserver",
6069#endif
6070#ifdef FEAT_CLIPBOARD
6071 "clipboard",
6072#endif
6073#ifdef FEAT_CMDL_COMPL
6074 "cmdline_compl",
6075#endif
6076#ifdef FEAT_CMDHIST
6077 "cmdline_hist",
6078#endif
6079#ifdef FEAT_COMMENTS
6080 "comments",
6081#endif
6082#ifdef FEAT_CONCEAL
6083 "conceal",
6084#endif
6085#ifdef FEAT_CRYPT
6086 "cryptv",
6087 "crypt-blowfish",
6088 "crypt-blowfish2",
6089#endif
6090#ifdef FEAT_CSCOPE
6091 "cscope",
6092#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006093 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006094#ifdef CURSOR_SHAPE
6095 "cursorshape",
6096#endif
6097#ifdef DEBUG
6098 "debug",
6099#endif
6100#ifdef FEAT_CON_DIALOG
6101 "dialog_con",
6102#endif
6103#ifdef FEAT_GUI_DIALOG
6104 "dialog_gui",
6105#endif
6106#ifdef FEAT_DIFF
6107 "diff",
6108#endif
6109#ifdef FEAT_DIGRAPHS
6110 "digraphs",
6111#endif
6112#ifdef FEAT_DIRECTX
6113 "directx",
6114#endif
6115#ifdef FEAT_DND
6116 "dnd",
6117#endif
6118#ifdef FEAT_EMACS_TAGS
6119 "emacs_tags",
6120#endif
6121 "eval", /* always present, of course! */
6122 "ex_extra", /* graduated feature */
6123#ifdef FEAT_SEARCH_EXTRA
6124 "extra_search",
6125#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006126#ifdef FEAT_SEARCHPATH
6127 "file_in_path",
6128#endif
6129#ifdef FEAT_FILTERPIPE
6130 "filterpipe",
6131#endif
6132#ifdef FEAT_FIND_ID
6133 "find_in_path",
6134#endif
6135#ifdef FEAT_FLOAT
6136 "float",
6137#endif
6138#ifdef FEAT_FOLDING
6139 "folding",
6140#endif
6141#ifdef FEAT_FOOTER
6142 "footer",
6143#endif
6144#if !defined(USE_SYSTEM) && defined(UNIX)
6145 "fork",
6146#endif
6147#ifdef FEAT_GETTEXT
6148 "gettext",
6149#endif
6150#ifdef FEAT_GUI
6151 "gui",
6152#endif
6153#ifdef FEAT_GUI_ATHENA
6154# ifdef FEAT_GUI_NEXTAW
6155 "gui_neXtaw",
6156# else
6157 "gui_athena",
6158# endif
6159#endif
6160#ifdef FEAT_GUI_GTK
6161 "gui_gtk",
6162# ifdef USE_GTK3
6163 "gui_gtk3",
6164# else
6165 "gui_gtk2",
6166# endif
6167#endif
6168#ifdef FEAT_GUI_GNOME
6169 "gui_gnome",
6170#endif
6171#ifdef FEAT_GUI_MAC
6172 "gui_mac",
6173#endif
6174#ifdef FEAT_GUI_MOTIF
6175 "gui_motif",
6176#endif
6177#ifdef FEAT_GUI_PHOTON
6178 "gui_photon",
6179#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006180#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181 "gui_win32",
6182#endif
6183#ifdef FEAT_HANGULIN
6184 "hangul_input",
6185#endif
6186#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6187 "iconv",
6188#endif
6189#ifdef FEAT_INS_EXPAND
6190 "insert_expand",
6191#endif
6192#ifdef FEAT_JOB_CHANNEL
6193 "job",
6194#endif
6195#ifdef FEAT_JUMPLIST
6196 "jumplist",
6197#endif
6198#ifdef FEAT_KEYMAP
6199 "keymap",
6200#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006201 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202#ifdef FEAT_LANGMAP
6203 "langmap",
6204#endif
6205#ifdef FEAT_LIBCALL
6206 "libcall",
6207#endif
6208#ifdef FEAT_LINEBREAK
6209 "linebreak",
6210#endif
6211#ifdef FEAT_LISP
6212 "lispindent",
6213#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006214 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215#ifdef FEAT_LOCALMAP
6216 "localmap",
6217#endif
6218#ifdef FEAT_LUA
6219# ifndef DYNAMIC_LUA
6220 "lua",
6221# endif
6222#endif
6223#ifdef FEAT_MENU
6224 "menu",
6225#endif
6226#ifdef FEAT_SESSION
6227 "mksession",
6228#endif
6229#ifdef FEAT_MODIFY_FNAME
6230 "modify_fname",
6231#endif
6232#ifdef FEAT_MOUSE
6233 "mouse",
6234#endif
6235#ifdef FEAT_MOUSESHAPE
6236 "mouseshape",
6237#endif
6238#if defined(UNIX) || defined(VMS)
6239# ifdef FEAT_MOUSE_DEC
6240 "mouse_dec",
6241# endif
6242# ifdef FEAT_MOUSE_GPM
6243 "mouse_gpm",
6244# endif
6245# ifdef FEAT_MOUSE_JSB
6246 "mouse_jsbterm",
6247# endif
6248# ifdef FEAT_MOUSE_NET
6249 "mouse_netterm",
6250# endif
6251# ifdef FEAT_MOUSE_PTERM
6252 "mouse_pterm",
6253# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006254# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006255 "mouse_sgr",
6256# endif
6257# ifdef FEAT_SYSMOUSE
6258 "mouse_sysmouse",
6259# endif
6260# ifdef FEAT_MOUSE_URXVT
6261 "mouse_urxvt",
6262# endif
6263# ifdef FEAT_MOUSE_XTERM
6264 "mouse_xterm",
6265# endif
6266#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006267 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268#ifdef FEAT_MBYTE_IME
6269 "multi_byte_ime",
6270#endif
6271#ifdef FEAT_MULTI_LANG
6272 "multi_lang",
6273#endif
6274#ifdef FEAT_MZSCHEME
6275#ifndef DYNAMIC_MZSCHEME
6276 "mzscheme",
6277#endif
6278#endif
6279#ifdef FEAT_NUM64
6280 "num64",
6281#endif
6282#ifdef FEAT_OLE
6283 "ole",
6284#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006285#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006287#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288#ifdef FEAT_PATH_EXTRA
6289 "path_extra",
6290#endif
6291#ifdef FEAT_PERL
6292#ifndef DYNAMIC_PERL
6293 "perl",
6294#endif
6295#endif
6296#ifdef FEAT_PERSISTENT_UNDO
6297 "persistent_undo",
6298#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006299#if defined(FEAT_PYTHON)
6300 "python_compiled",
6301# if defined(DYNAMIC_PYTHON)
6302 "python_dynamic",
6303# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006304 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006305 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006306# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006308#if defined(FEAT_PYTHON3)
6309 "python3_compiled",
6310# if defined(DYNAMIC_PYTHON3)
6311 "python3_dynamic",
6312# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006314 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006315# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006316#endif
6317#ifdef FEAT_POSTSCRIPT
6318 "postscript",
6319#endif
6320#ifdef FEAT_PRINTER
6321 "printer",
6322#endif
6323#ifdef FEAT_PROFILE
6324 "profile",
6325#endif
6326#ifdef FEAT_RELTIME
6327 "reltime",
6328#endif
6329#ifdef FEAT_QUICKFIX
6330 "quickfix",
6331#endif
6332#ifdef FEAT_RIGHTLEFT
6333 "rightleft",
6334#endif
6335#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6336 "ruby",
6337#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339#ifdef FEAT_CMDL_INFO
6340 "showcmd",
6341 "cmdline_info",
6342#endif
6343#ifdef FEAT_SIGNS
6344 "signs",
6345#endif
6346#ifdef FEAT_SMARTINDENT
6347 "smartindent",
6348#endif
6349#ifdef STARTUPTIME
6350 "startuptime",
6351#endif
6352#ifdef FEAT_STL_OPT
6353 "statusline",
6354#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355#ifdef FEAT_NETBEANS_INTG
6356 "netbeans_intg",
6357#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006358#ifdef FEAT_SOUND
6359 "sound",
6360#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361#ifdef FEAT_SPELL
6362 "spell",
6363#endif
6364#ifdef FEAT_SYN_HL
6365 "syntax",
6366#endif
6367#if defined(USE_SYSTEM) || !defined(UNIX)
6368 "system",
6369#endif
6370#ifdef FEAT_TAG_BINS
6371 "tag_binary",
6372#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373#ifdef FEAT_TCL
6374# ifndef DYNAMIC_TCL
6375 "tcl",
6376# endif
6377#endif
6378#ifdef FEAT_TERMGUICOLORS
6379 "termguicolors",
6380#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006381#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006382 "terminal",
6383#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006384#ifdef TERMINFO
6385 "terminfo",
6386#endif
6387#ifdef FEAT_TERMRESPONSE
6388 "termresponse",
6389#endif
6390#ifdef FEAT_TEXTOBJ
6391 "textobjects",
6392#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006393#ifdef FEAT_TEXT_PROP
6394 "textprop",
6395#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396#ifdef HAVE_TGETENT
6397 "tgetent",
6398#endif
6399#ifdef FEAT_TIMERS
6400 "timers",
6401#endif
6402#ifdef FEAT_TITLE
6403 "title",
6404#endif
6405#ifdef FEAT_TOOLBAR
6406 "toolbar",
6407#endif
6408#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6409 "unnamedplus",
6410#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006411 "user-commands", /* was accidentally included in 5.4 */
6412 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006413#ifdef FEAT_VARTABS
6414 "vartabs",
6415#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006416 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417#ifdef FEAT_VIMINFO
6418 "viminfo",
6419#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006420 "vimscript-1",
6421 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006422 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006423 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006425 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006427#ifdef FEAT_VTP
6428 "vtp",
6429#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430#ifdef FEAT_WILDIGN
6431 "wildignore",
6432#endif
6433#ifdef FEAT_WILDMENU
6434 "wildmenu",
6435#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006437#ifdef FEAT_WAK
6438 "winaltkeys",
6439#endif
6440#ifdef FEAT_WRITEBACKUP
6441 "writebackup",
6442#endif
6443#ifdef FEAT_XIM
6444 "xim",
6445#endif
6446#ifdef FEAT_XFONTSET
6447 "xfontset",
6448#endif
6449#ifdef FEAT_XPM_W32
6450 "xpm",
6451 "xpm_w32", /* for backward compatibility */
6452#else
6453# if defined(HAVE_XPM)
6454 "xpm",
6455# endif
6456#endif
6457#ifdef USE_XSMP
6458 "xsmp",
6459#endif
6460#ifdef USE_XSMP_INTERACT
6461 "xsmp_interact",
6462#endif
6463#ifdef FEAT_XCLIPBOARD
6464 "xterm_clipboard",
6465#endif
6466#ifdef FEAT_XTERM_SAVE
6467 "xterm_save",
6468#endif
6469#if defined(UNIX) && defined(FEAT_X11)
6470 "X11",
6471#endif
6472 NULL
6473 };
6474
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006475 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 for (i = 0; has_list[i] != NULL; ++i)
6477 if (STRICMP(name, has_list[i]) == 0)
6478 {
6479 n = TRUE;
6480 break;
6481 }
6482
6483 if (n == FALSE)
6484 {
6485 if (STRNICMP(name, "patch", 5) == 0)
6486 {
6487 if (name[5] == '-'
6488 && STRLEN(name) >= 11
6489 && vim_isdigit(name[6])
6490 && vim_isdigit(name[8])
6491 && vim_isdigit(name[10]))
6492 {
6493 int major = atoi((char *)name + 6);
6494 int minor = atoi((char *)name + 8);
6495
6496 /* Expect "patch-9.9.01234". */
6497 n = (major < VIM_VERSION_MAJOR
6498 || (major == VIM_VERSION_MAJOR
6499 && (minor < VIM_VERSION_MINOR
6500 || (minor == VIM_VERSION_MINOR
6501 && has_patch(atoi((char *)name + 10))))));
6502 }
6503 else
6504 n = has_patch(atoi((char *)name + 5));
6505 }
6506 else if (STRICMP(name, "vim_starting") == 0)
6507 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006508 else if (STRICMP(name, "ttyin") == 0)
6509 n = mch_input_isatty();
6510 else if (STRICMP(name, "ttyout") == 0)
6511 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006512 else if (STRICMP(name, "multi_byte_encoding") == 0)
6513 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006514#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515 else if (STRICMP(name, "balloon_multiline") == 0)
6516 n = multiline_balloon_available();
6517#endif
6518#ifdef DYNAMIC_TCL
6519 else if (STRICMP(name, "tcl") == 0)
6520 n = tcl_enabled(FALSE);
6521#endif
6522#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6523 else if (STRICMP(name, "iconv") == 0)
6524 n = iconv_enabled(FALSE);
6525#endif
6526#ifdef DYNAMIC_LUA
6527 else if (STRICMP(name, "lua") == 0)
6528 n = lua_enabled(FALSE);
6529#endif
6530#ifdef DYNAMIC_MZSCHEME
6531 else if (STRICMP(name, "mzscheme") == 0)
6532 n = mzscheme_enabled(FALSE);
6533#endif
6534#ifdef DYNAMIC_RUBY
6535 else if (STRICMP(name, "ruby") == 0)
6536 n = ruby_enabled(FALSE);
6537#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538#ifdef DYNAMIC_PYTHON
6539 else if (STRICMP(name, "python") == 0)
6540 n = python_enabled(FALSE);
6541#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006542#ifdef DYNAMIC_PYTHON3
6543 else if (STRICMP(name, "python3") == 0)
6544 n = python3_enabled(FALSE);
6545#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006546#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6547 else if (STRICMP(name, "pythonx") == 0)
6548 {
6549# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6550 if (p_pyx == 0)
6551 n = python3_enabled(FALSE) || python_enabled(FALSE);
6552 else if (p_pyx == 3)
6553 n = python3_enabled(FALSE);
6554 else if (p_pyx == 2)
6555 n = python_enabled(FALSE);
6556# elif defined(DYNAMIC_PYTHON)
6557 n = python_enabled(FALSE);
6558# elif defined(DYNAMIC_PYTHON3)
6559 n = python3_enabled(FALSE);
6560# endif
6561 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562#endif
6563#ifdef DYNAMIC_PERL
6564 else if (STRICMP(name, "perl") == 0)
6565 n = perl_enabled(FALSE);
6566#endif
6567#ifdef FEAT_GUI
6568 else if (STRICMP(name, "gui_running") == 0)
6569 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570# ifdef FEAT_BROWSE
6571 else if (STRICMP(name, "browse") == 0)
6572 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6573# endif
6574#endif
6575#ifdef FEAT_SYN_HL
6576 else if (STRICMP(name, "syntax_items") == 0)
6577 n = syntax_present(curwin);
6578#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006579#ifdef FEAT_VTP
6580 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006581 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006582#endif
6583#ifdef FEAT_NETBEANS_INTG
6584 else if (STRICMP(name, "netbeans_enabled") == 0)
6585 n = netbeans_active();
6586#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006587#ifdef FEAT_MOUSE_GPM
6588 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6589 n = gpm_enabled();
6590#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006591#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006592 else if (STRICMP(name, "terminal") == 0)
6593 n = terminal_enabled();
6594#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006595#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006596 else if (STRICMP(name, "conpty") == 0)
6597 n = use_conpty();
6598#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599 }
6600
6601 rettv->vval.v_number = n;
6602}
6603
6604/*
6605 * "has_key()" function
6606 */
6607 static void
6608f_has_key(typval_T *argvars, typval_T *rettv)
6609{
6610 if (argvars[0].v_type != VAR_DICT)
6611 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006612 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006613 return;
6614 }
6615 if (argvars[0].vval.v_dict == NULL)
6616 return;
6617
6618 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006619 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620}
6621
6622/*
6623 * "haslocaldir()" function
6624 */
6625 static void
6626f_haslocaldir(typval_T *argvars, typval_T *rettv)
6627{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006628 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006629 win_T *wp = NULL;
6630
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006631 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6632
6633 // Check for window-local and tab-local directories
6634 if (wp != NULL && wp->w_localdir != NULL)
6635 rettv->vval.v_number = 1;
6636 else if (tp != NULL && tp->tp_localdir != NULL)
6637 rettv->vval.v_number = 2;
6638 else
6639 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640}
6641
6642/*
6643 * "hasmapto()" function
6644 */
6645 static void
6646f_hasmapto(typval_T *argvars, typval_T *rettv)
6647{
6648 char_u *name;
6649 char_u *mode;
6650 char_u buf[NUMBUFLEN];
6651 int abbr = FALSE;
6652
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006653 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006654 if (argvars[1].v_type == VAR_UNKNOWN)
6655 mode = (char_u *)"nvo";
6656 else
6657 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006658 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006659 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006660 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006661 }
6662
6663 if (map_to_exists(name, mode, abbr))
6664 rettv->vval.v_number = TRUE;
6665 else
6666 rettv->vval.v_number = FALSE;
6667}
6668
6669/*
6670 * "histadd()" function
6671 */
6672 static void
6673f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6674{
6675#ifdef FEAT_CMDHIST
6676 int histype;
6677 char_u *str;
6678 char_u buf[NUMBUFLEN];
6679#endif
6680
6681 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006682 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 return;
6684#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006685 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 histype = str != NULL ? get_histtype(str) : -1;
6687 if (histype >= 0)
6688 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006689 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 if (*str != NUL)
6691 {
6692 init_history();
6693 add_to_history(histype, str, FALSE, NUL);
6694 rettv->vval.v_number = TRUE;
6695 return;
6696 }
6697 }
6698#endif
6699}
6700
6701/*
6702 * "histdel()" function
6703 */
6704 static void
6705f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6706{
6707#ifdef FEAT_CMDHIST
6708 int n;
6709 char_u buf[NUMBUFLEN];
6710 char_u *str;
6711
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006712 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006713 if (str == NULL)
6714 n = 0;
6715 else if (argvars[1].v_type == VAR_UNKNOWN)
6716 /* only one argument: clear entire history */
6717 n = clr_history(get_histtype(str));
6718 else if (argvars[1].v_type == VAR_NUMBER)
6719 /* index given: remove that entry */
6720 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006721 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722 else
6723 /* string given: remove all matching entries */
6724 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006725 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 rettv->vval.v_number = n;
6727#endif
6728}
6729
6730/*
6731 * "histget()" function
6732 */
6733 static void
6734f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6735{
6736#ifdef FEAT_CMDHIST
6737 int type;
6738 int idx;
6739 char_u *str;
6740
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006741 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742 if (str == NULL)
6743 rettv->vval.v_string = NULL;
6744 else
6745 {
6746 type = get_histtype(str);
6747 if (argvars[1].v_type == VAR_UNKNOWN)
6748 idx = get_history_idx(type);
6749 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006750 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006751 /* -1 on type error */
6752 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6753 }
6754#else
6755 rettv->vval.v_string = NULL;
6756#endif
6757 rettv->v_type = VAR_STRING;
6758}
6759
6760/*
6761 * "histnr()" function
6762 */
6763 static void
6764f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6765{
6766 int i;
6767
6768#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006769 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770
6771 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6772 if (i >= HIST_CMD && i < HIST_COUNT)
6773 i = get_history_idx(i);
6774 else
6775#endif
6776 i = -1;
6777 rettv->vval.v_number = i;
6778}
6779
6780/*
6781 * "highlightID(name)" function
6782 */
6783 static void
6784f_hlID(typval_T *argvars, typval_T *rettv)
6785{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006786 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006787}
6788
6789/*
6790 * "highlight_exists()" function
6791 */
6792 static void
6793f_hlexists(typval_T *argvars, typval_T *rettv)
6794{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006795 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796}
6797
6798/*
6799 * "hostname()" function
6800 */
6801 static void
6802f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6803{
6804 char_u hostname[256];
6805
6806 mch_get_host_name(hostname, 256);
6807 rettv->v_type = VAR_STRING;
6808 rettv->vval.v_string = vim_strsave(hostname);
6809}
6810
6811/*
6812 * iconv() function
6813 */
6814 static void
6815f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6816{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817 char_u buf1[NUMBUFLEN];
6818 char_u buf2[NUMBUFLEN];
6819 char_u *from, *to, *str;
6820 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821
6822 rettv->v_type = VAR_STRING;
6823 rettv->vval.v_string = NULL;
6824
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006825 str = tv_get_string(&argvars[0]);
6826 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6827 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828 vimconv.vc_type = CONV_NONE;
6829 convert_setup(&vimconv, from, to);
6830
6831 /* If the encodings are equal, no conversion needed. */
6832 if (vimconv.vc_type == CONV_NONE)
6833 rettv->vval.v_string = vim_strsave(str);
6834 else
6835 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6836
6837 convert_setup(&vimconv, NULL, NULL);
6838 vim_free(from);
6839 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840}
6841
6842/*
6843 * "indent()" function
6844 */
6845 static void
6846f_indent(typval_T *argvars, typval_T *rettv)
6847{
6848 linenr_T lnum;
6849
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006850 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6852 rettv->vval.v_number = get_indent_lnum(lnum);
6853 else
6854 rettv->vval.v_number = -1;
6855}
6856
6857/*
6858 * "index()" function
6859 */
6860 static void
6861f_index(typval_T *argvars, typval_T *rettv)
6862{
6863 list_T *l;
6864 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006865 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 long idx = 0;
6867 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006868 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869
6870 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006871 if (argvars[0].v_type == VAR_BLOB)
6872 {
6873 typval_T tv;
6874 int start = 0;
6875
6876 if (argvars[2].v_type != VAR_UNKNOWN)
6877 {
6878 start = tv_get_number_chk(&argvars[2], &error);
6879 if (error)
6880 return;
6881 }
6882 b = argvars[0].vval.v_blob;
6883 if (b == NULL)
6884 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006885 if (start < 0)
6886 {
6887 start = blob_len(b) + start;
6888 if (start < 0)
6889 start = 0;
6890 }
6891
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006892 for (idx = start; idx < blob_len(b); ++idx)
6893 {
6894 tv.v_type = VAR_NUMBER;
6895 tv.vval.v_number = blob_get(b, idx);
6896 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6897 {
6898 rettv->vval.v_number = idx;
6899 return;
6900 }
6901 }
6902 return;
6903 }
6904 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006905 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006906 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006907 return;
6908 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006909
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006910 l = argvars[0].vval.v_list;
6911 if (l != NULL)
6912 {
6913 item = l->lv_first;
6914 if (argvars[2].v_type != VAR_UNKNOWN)
6915 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 /* Start at specified item. Use the cached index that list_find()
6917 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006918 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 idx = l->lv_idx;
6920 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006921 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922 if (error)
6923 item = NULL;
6924 }
6925
6926 for ( ; item != NULL; item = item->li_next, ++idx)
6927 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6928 {
6929 rettv->vval.v_number = idx;
6930 break;
6931 }
6932 }
6933}
6934
6935static int inputsecret_flag = 0;
6936
6937/*
6938 * "input()" function
6939 * Also handles inputsecret() when inputsecret is set.
6940 */
6941 static void
6942f_input(typval_T *argvars, typval_T *rettv)
6943{
6944 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6945}
6946
6947/*
6948 * "inputdialog()" function
6949 */
6950 static void
6951f_inputdialog(typval_T *argvars, typval_T *rettv)
6952{
6953#if defined(FEAT_GUI_TEXTDIALOG)
6954 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6955 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6956 {
6957 char_u *message;
6958 char_u buf[NUMBUFLEN];
6959 char_u *defstr = (char_u *)"";
6960
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006961 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006962 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006963 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006964 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6965 else
6966 IObuff[0] = NUL;
6967 if (message != NULL && defstr != NULL
6968 && do_dialog(VIM_QUESTION, NULL, message,
6969 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6970 rettv->vval.v_string = vim_strsave(IObuff);
6971 else
6972 {
6973 if (message != NULL && defstr != NULL
6974 && argvars[1].v_type != VAR_UNKNOWN
6975 && argvars[2].v_type != VAR_UNKNOWN)
6976 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006977 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006978 else
6979 rettv->vval.v_string = NULL;
6980 }
6981 rettv->v_type = VAR_STRING;
6982 }
6983 else
6984#endif
6985 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6986}
6987
6988/*
6989 * "inputlist()" function
6990 */
6991 static void
6992f_inputlist(typval_T *argvars, typval_T *rettv)
6993{
6994 listitem_T *li;
6995 int selected;
6996 int mouse_used;
6997
6998#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006999 /* While starting up, there is no place to enter text. When running tests
7000 * with --not-a-term we assume feedkeys() will be used. */
7001 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007002 return;
7003#endif
7004 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7005 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007006 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007007 return;
7008 }
7009
7010 msg_start();
7011 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7012 lines_left = Rows; /* avoid more prompt */
7013 msg_scroll = TRUE;
7014 msg_clr_eos();
7015
7016 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7017 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007018 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007019 msg_putchar('\n');
7020 }
7021
7022 /* Ask for choice. */
7023 selected = prompt_for_number(&mouse_used);
7024 if (mouse_used)
7025 selected -= lines_left;
7026
7027 rettv->vval.v_number = selected;
7028}
7029
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007030static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7031
7032/*
7033 * "inputrestore()" function
7034 */
7035 static void
7036f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7037{
7038 if (ga_userinput.ga_len > 0)
7039 {
7040 --ga_userinput.ga_len;
7041 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7042 + ga_userinput.ga_len);
7043 /* default return is zero == OK */
7044 }
7045 else if (p_verbose > 1)
7046 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007047 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048 rettv->vval.v_number = 1; /* Failed */
7049 }
7050}
7051
7052/*
7053 * "inputsave()" function
7054 */
7055 static void
7056f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7057{
7058 /* Add an entry to the stack of typeahead storage. */
7059 if (ga_grow(&ga_userinput, 1) == OK)
7060 {
7061 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7062 + ga_userinput.ga_len);
7063 ++ga_userinput.ga_len;
7064 /* default return is zero == OK */
7065 }
7066 else
7067 rettv->vval.v_number = 1; /* Failed */
7068}
7069
7070/*
7071 * "inputsecret()" function
7072 */
7073 static void
7074f_inputsecret(typval_T *argvars, typval_T *rettv)
7075{
7076 ++cmdline_star;
7077 ++inputsecret_flag;
7078 f_input(argvars, rettv);
7079 --cmdline_star;
7080 --inputsecret_flag;
7081}
7082
7083/*
7084 * "insert()" function
7085 */
7086 static void
7087f_insert(typval_T *argvars, typval_T *rettv)
7088{
7089 long before = 0;
7090 listitem_T *item;
7091 list_T *l;
7092 int error = FALSE;
7093
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007094 if (argvars[0].v_type == VAR_BLOB)
7095 {
7096 int val, len;
7097 char_u *p;
7098
7099 len = blob_len(argvars[0].vval.v_blob);
7100 if (argvars[2].v_type != VAR_UNKNOWN)
7101 {
7102 before = (long)tv_get_number_chk(&argvars[2], &error);
7103 if (error)
7104 return; // type error; errmsg already given
7105 if (before < 0 || before > len)
7106 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007107 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007108 return;
7109 }
7110 }
7111 val = tv_get_number_chk(&argvars[1], &error);
7112 if (error)
7113 return;
7114 if (val < 0 || val > 255)
7115 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007116 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007117 return;
7118 }
7119
7120 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7121 return;
7122 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7123 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7124 *(p + before) = val;
7125 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7126
7127 copy_tv(&argvars[0], rettv);
7128 }
7129 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007130 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007131 else if ((l = argvars[0].vval.v_list) != NULL
7132 && !var_check_lock(l->lv_lock,
7133 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007134 {
7135 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007136 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007137 if (error)
7138 return; /* type error; errmsg already given */
7139
7140 if (before == l->lv_len)
7141 item = NULL;
7142 else
7143 {
7144 item = list_find(l, before);
7145 if (item == NULL)
7146 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007147 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 l = NULL;
7149 }
7150 }
7151 if (l != NULL)
7152 {
7153 list_insert_tv(l, &argvars[1], item);
7154 copy_tv(&argvars[0], rettv);
7155 }
7156 }
7157}
7158
7159/*
7160 * "invert(expr)" function
7161 */
7162 static void
7163f_invert(typval_T *argvars, typval_T *rettv)
7164{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007165 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166}
7167
7168/*
7169 * "isdirectory()" function
7170 */
7171 static void
7172f_isdirectory(typval_T *argvars, typval_T *rettv)
7173{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007174 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175}
7176
7177/*
7178 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7179 * or it refers to a List or Dictionary that is locked.
7180 */
7181 static int
7182tv_islocked(typval_T *tv)
7183{
7184 return (tv->v_lock & VAR_LOCKED)
7185 || (tv->v_type == VAR_LIST
7186 && tv->vval.v_list != NULL
7187 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7188 || (tv->v_type == VAR_DICT
7189 && tv->vval.v_dict != NULL
7190 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7191}
7192
7193/*
7194 * "islocked()" function
7195 */
7196 static void
7197f_islocked(typval_T *argvars, typval_T *rettv)
7198{
7199 lval_T lv;
7200 char_u *end;
7201 dictitem_T *di;
7202
7203 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007204 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007205 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 if (end != NULL && lv.ll_name != NULL)
7207 {
7208 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007209 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 else
7211 {
7212 if (lv.ll_tv == NULL)
7213 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007214 di = find_var(lv.ll_name, NULL, TRUE);
7215 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007216 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007217 /* Consider a variable locked when:
7218 * 1. the variable itself is locked
7219 * 2. the value of the variable is locked.
7220 * 3. the List or Dict value is locked.
7221 */
7222 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7223 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007224 }
7225 }
7226 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007227 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007229 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 else if (lv.ll_list != NULL)
7231 /* List item. */
7232 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7233 else
7234 /* Dictionary item. */
7235 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7236 }
7237 }
7238
7239 clear_lval(&lv);
7240}
7241
7242#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7243/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007244 * "isinf()" function
7245 */
7246 static void
7247f_isinf(typval_T *argvars, typval_T *rettv)
7248{
7249 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7250 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7251}
7252
7253/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 * "isnan()" function
7255 */
7256 static void
7257f_isnan(typval_T *argvars, typval_T *rettv)
7258{
7259 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7260 && isnan(argvars[0].vval.v_float);
7261}
7262#endif
7263
7264/*
7265 * "items(dict)" function
7266 */
7267 static void
7268f_items(typval_T *argvars, typval_T *rettv)
7269{
7270 dict_list(argvars, rettv, 2);
7271}
7272
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007273/*
7274 * "join()" function
7275 */
7276 static void
7277f_join(typval_T *argvars, typval_T *rettv)
7278{
7279 garray_T ga;
7280 char_u *sep;
7281
7282 if (argvars[0].v_type != VAR_LIST)
7283 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007284 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 return;
7286 }
7287 if (argvars[0].vval.v_list == NULL)
7288 return;
7289 if (argvars[1].v_type == VAR_UNKNOWN)
7290 sep = (char_u *)" ";
7291 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007292 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007293
7294 rettv->v_type = VAR_STRING;
7295
7296 if (sep != NULL)
7297 {
7298 ga_init2(&ga, (int)sizeof(char), 80);
7299 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7300 ga_append(&ga, NUL);
7301 rettv->vval.v_string = (char_u *)ga.ga_data;
7302 }
7303 else
7304 rettv->vval.v_string = NULL;
7305}
7306
7307/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007308 * "keys()" function
7309 */
7310 static void
7311f_keys(typval_T *argvars, typval_T *rettv)
7312{
7313 dict_list(argvars, rettv, 0);
7314}
7315
7316/*
7317 * "last_buffer_nr()" function.
7318 */
7319 static void
7320f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7321{
7322 int n = 0;
7323 buf_T *buf;
7324
Bram Moolenaar29323592016-07-24 22:04:11 +02007325 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007326 if (n < buf->b_fnum)
7327 n = buf->b_fnum;
7328
7329 rettv->vval.v_number = n;
7330}
7331
7332/*
7333 * "len()" function
7334 */
7335 static void
7336f_len(typval_T *argvars, typval_T *rettv)
7337{
7338 switch (argvars[0].v_type)
7339 {
7340 case VAR_STRING:
7341 case VAR_NUMBER:
7342 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007343 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007345 case VAR_BLOB:
7346 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7347 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348 case VAR_LIST:
7349 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7350 break;
7351 case VAR_DICT:
7352 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7353 break;
7354 case VAR_UNKNOWN:
7355 case VAR_SPECIAL:
7356 case VAR_FLOAT:
7357 case VAR_FUNC:
7358 case VAR_PARTIAL:
7359 case VAR_JOB:
7360 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007361 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362 break;
7363 }
7364}
7365
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007366 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007367libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368{
7369#ifdef FEAT_LIBCALL
7370 char_u *string_in;
7371 char_u **string_result;
7372 int nr_result;
7373#endif
7374
7375 rettv->v_type = type;
7376 if (type != VAR_NUMBER)
7377 rettv->vval.v_string = NULL;
7378
7379 if (check_restricted() || check_secure())
7380 return;
7381
7382#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007383 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7385 {
7386 string_in = NULL;
7387 if (argvars[2].v_type == VAR_STRING)
7388 string_in = argvars[2].vval.v_string;
7389 if (type == VAR_NUMBER)
7390 string_result = NULL;
7391 else
7392 string_result = &rettv->vval.v_string;
7393 if (mch_libcall(argvars[0].vval.v_string,
7394 argvars[1].vval.v_string,
7395 string_in,
7396 argvars[2].vval.v_number,
7397 string_result,
7398 &nr_result) == OK
7399 && type == VAR_NUMBER)
7400 rettv->vval.v_number = nr_result;
7401 }
7402#endif
7403}
7404
7405/*
7406 * "libcall()" function
7407 */
7408 static void
7409f_libcall(typval_T *argvars, typval_T *rettv)
7410{
7411 libcall_common(argvars, rettv, VAR_STRING);
7412}
7413
7414/*
7415 * "libcallnr()" function
7416 */
7417 static void
7418f_libcallnr(typval_T *argvars, typval_T *rettv)
7419{
7420 libcall_common(argvars, rettv, VAR_NUMBER);
7421}
7422
7423/*
7424 * "line(string)" function
7425 */
7426 static void
7427f_line(typval_T *argvars, typval_T *rettv)
7428{
7429 linenr_T lnum = 0;
7430 pos_T *fp;
7431 int fnum;
7432
7433 fp = var2fpos(&argvars[0], TRUE, &fnum);
7434 if (fp != NULL)
7435 lnum = fp->lnum;
7436 rettv->vval.v_number = lnum;
7437}
7438
7439/*
7440 * "line2byte(lnum)" function
7441 */
7442 static void
7443f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7444{
7445#ifndef FEAT_BYTEOFF
7446 rettv->vval.v_number = -1;
7447#else
7448 linenr_T lnum;
7449
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007450 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007451 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7452 rettv->vval.v_number = -1;
7453 else
7454 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7455 if (rettv->vval.v_number >= 0)
7456 ++rettv->vval.v_number;
7457#endif
7458}
7459
7460/*
7461 * "lispindent(lnum)" function
7462 */
7463 static void
7464f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7465{
7466#ifdef FEAT_LISP
7467 pos_T pos;
7468 linenr_T lnum;
7469
7470 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007471 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007472 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7473 {
7474 curwin->w_cursor.lnum = lnum;
7475 rettv->vval.v_number = get_lisp_indent();
7476 curwin->w_cursor = pos;
7477 }
7478 else
7479#endif
7480 rettv->vval.v_number = -1;
7481}
7482
7483/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007484 * "list2str()" function
7485 */
7486 static void
7487f_list2str(typval_T *argvars, typval_T *rettv)
7488{
7489 list_T *l;
7490 listitem_T *li;
7491 garray_T ga;
7492 int utf8 = FALSE;
7493
7494 rettv->v_type = VAR_STRING;
7495 rettv->vval.v_string = NULL;
7496 if (argvars[0].v_type != VAR_LIST)
7497 {
7498 emsg(_(e_invarg));
7499 return;
7500 }
7501
7502 l = argvars[0].vval.v_list;
7503 if (l == NULL)
7504 return; // empty list results in empty string
7505
7506 if (argvars[1].v_type != VAR_UNKNOWN)
7507 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7508
7509 ga_init2(&ga, 1, 80);
7510 if (has_mbyte || utf8)
7511 {
7512 char_u buf[MB_MAXBYTES + 1];
7513 int (*char2bytes)(int, char_u *);
7514
7515 if (utf8 || enc_utf8)
7516 char2bytes = utf_char2bytes;
7517 else
7518 char2bytes = mb_char2bytes;
7519
7520 for (li = l->lv_first; li != NULL; li = li->li_next)
7521 {
7522 buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
7523 ga_concat(&ga, buf);
7524 }
7525 ga_append(&ga, NUL);
7526 }
7527 else if (ga_grow(&ga, list_len(l) + 1) == OK)
7528 {
7529 for (li = l->lv_first; li != NULL; li = li->li_next)
7530 ga_append(&ga, tv_get_number(&li->li_tv));
7531 ga_append(&ga, NUL);
7532 }
7533
7534 rettv->v_type = VAR_STRING;
7535 rettv->vval.v_string = ga.ga_data;
7536}
7537
7538/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007539 * "localtime()" function
7540 */
7541 static void
7542f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7543{
7544 rettv->vval.v_number = (varnumber_T)time(NULL);
7545}
7546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007547 static void
7548get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7549{
7550 char_u *keys;
7551 char_u *which;
7552 char_u buf[NUMBUFLEN];
7553 char_u *keys_buf = NULL;
7554 char_u *rhs;
7555 int mode;
7556 int abbr = FALSE;
7557 int get_dict = FALSE;
7558 mapblock_T *mp;
7559 int buffer_local;
7560
7561 /* return empty string for failure */
7562 rettv->v_type = VAR_STRING;
7563 rettv->vval.v_string = NULL;
7564
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007565 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007566 if (*keys == NUL)
7567 return;
7568
7569 if (argvars[1].v_type != VAR_UNKNOWN)
7570 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007571 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572 if (argvars[2].v_type != VAR_UNKNOWN)
7573 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007574 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 }
7578 }
7579 else
7580 which = (char_u *)"";
7581 if (which == NULL)
7582 return;
7583
7584 mode = get_map_mode(&which, 0);
7585
7586 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7587 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7588 vim_free(keys_buf);
7589
7590 if (!get_dict)
7591 {
7592 /* Return a string. */
7593 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007594 {
7595 if (*rhs == NUL)
7596 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7597 else
7598 rettv->vval.v_string = str2special_save(rhs, FALSE);
7599 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600
7601 }
7602 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7603 {
7604 /* Return a dictionary. */
7605 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7606 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7607 dict_T *dict = rettv->vval.v_dict;
7608
Bram Moolenaare0be1672018-07-08 16:50:37 +02007609 dict_add_string(dict, "lhs", lhs);
7610 dict_add_string(dict, "rhs", mp->m_orig_str);
7611 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7612 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7613 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007614 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7615 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007616 dict_add_number(dict, "buffer", (long)buffer_local);
7617 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7618 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619
7620 vim_free(lhs);
7621 vim_free(mapmode);
7622 }
7623}
7624
7625#ifdef FEAT_FLOAT
7626/*
7627 * "log()" function
7628 */
7629 static void
7630f_log(typval_T *argvars, typval_T *rettv)
7631{
7632 float_T f = 0.0;
7633
7634 rettv->v_type = VAR_FLOAT;
7635 if (get_float_arg(argvars, &f) == OK)
7636 rettv->vval.v_float = log(f);
7637 else
7638 rettv->vval.v_float = 0.0;
7639}
7640
7641/*
7642 * "log10()" function
7643 */
7644 static void
7645f_log10(typval_T *argvars, typval_T *rettv)
7646{
7647 float_T f = 0.0;
7648
7649 rettv->v_type = VAR_FLOAT;
7650 if (get_float_arg(argvars, &f) == OK)
7651 rettv->vval.v_float = log10(f);
7652 else
7653 rettv->vval.v_float = 0.0;
7654}
7655#endif
7656
7657#ifdef FEAT_LUA
7658/*
7659 * "luaeval()" function
7660 */
7661 static void
7662f_luaeval(typval_T *argvars, typval_T *rettv)
7663{
7664 char_u *str;
7665 char_u buf[NUMBUFLEN];
7666
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007667 if (check_restricted() || check_secure())
7668 return;
7669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007670 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007671 do_luaeval(str, argvars + 1, rettv);
7672}
7673#endif
7674
7675/*
7676 * "map()" function
7677 */
7678 static void
7679f_map(typval_T *argvars, typval_T *rettv)
7680{
7681 filter_map(argvars, rettv, TRUE);
7682}
7683
7684/*
7685 * "maparg()" function
7686 */
7687 static void
7688f_maparg(typval_T *argvars, typval_T *rettv)
7689{
7690 get_maparg(argvars, rettv, TRUE);
7691}
7692
7693/*
7694 * "mapcheck()" function
7695 */
7696 static void
7697f_mapcheck(typval_T *argvars, typval_T *rettv)
7698{
7699 get_maparg(argvars, rettv, FALSE);
7700}
7701
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007702typedef enum
7703{
7704 MATCH_END, /* matchend() */
7705 MATCH_MATCH, /* match() */
7706 MATCH_STR, /* matchstr() */
7707 MATCH_LIST, /* matchlist() */
7708 MATCH_POS /* matchstrpos() */
7709} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007710
7711 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007712find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007713{
7714 char_u *str = NULL;
7715 long len = 0;
7716 char_u *expr = NULL;
7717 char_u *pat;
7718 regmatch_T regmatch;
7719 char_u patbuf[NUMBUFLEN];
7720 char_u strbuf[NUMBUFLEN];
7721 char_u *save_cpo;
7722 long start = 0;
7723 long nth = 1;
7724 colnr_T startcol = 0;
7725 int match = 0;
7726 list_T *l = NULL;
7727 listitem_T *li = NULL;
7728 long idx = 0;
7729 char_u *tofree = NULL;
7730
7731 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7732 save_cpo = p_cpo;
7733 p_cpo = (char_u *)"";
7734
7735 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007736 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007737 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007738 /* type MATCH_LIST: return empty list when there are no matches.
7739 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007740 if (rettv_list_alloc(rettv) == FAIL)
7741 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007742 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 && (list_append_string(rettv->vval.v_list,
7744 (char_u *)"", 0) == FAIL
7745 || list_append_number(rettv->vval.v_list,
7746 (varnumber_T)-1) == FAIL
7747 || list_append_number(rettv->vval.v_list,
7748 (varnumber_T)-1) == FAIL
7749 || list_append_number(rettv->vval.v_list,
7750 (varnumber_T)-1) == FAIL))
7751 {
7752 list_free(rettv->vval.v_list);
7753 rettv->vval.v_list = NULL;
7754 goto theend;
7755 }
7756 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007757 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758 {
7759 rettv->v_type = VAR_STRING;
7760 rettv->vval.v_string = NULL;
7761 }
7762
7763 if (argvars[0].v_type == VAR_LIST)
7764 {
7765 if ((l = argvars[0].vval.v_list) == NULL)
7766 goto theend;
7767 li = l->lv_first;
7768 }
7769 else
7770 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007771 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007772 len = (long)STRLEN(str);
7773 }
7774
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007775 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 if (pat == NULL)
7777 goto theend;
7778
7779 if (argvars[2].v_type != VAR_UNKNOWN)
7780 {
7781 int error = FALSE;
7782
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007783 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007784 if (error)
7785 goto theend;
7786 if (l != NULL)
7787 {
7788 li = list_find(l, start);
7789 if (li == NULL)
7790 goto theend;
7791 idx = l->lv_idx; /* use the cached index */
7792 }
7793 else
7794 {
7795 if (start < 0)
7796 start = 0;
7797 if (start > len)
7798 goto theend;
7799 /* When "count" argument is there ignore matches before "start",
7800 * otherwise skip part of the string. Differs when pattern is "^"
7801 * or "\<". */
7802 if (argvars[3].v_type != VAR_UNKNOWN)
7803 startcol = start;
7804 else
7805 {
7806 str += start;
7807 len -= start;
7808 }
7809 }
7810
7811 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007812 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813 if (error)
7814 goto theend;
7815 }
7816
7817 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7818 if (regmatch.regprog != NULL)
7819 {
7820 regmatch.rm_ic = p_ic;
7821
7822 for (;;)
7823 {
7824 if (l != NULL)
7825 {
7826 if (li == NULL)
7827 {
7828 match = FALSE;
7829 break;
7830 }
7831 vim_free(tofree);
7832 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7833 if (str == NULL)
7834 break;
7835 }
7836
7837 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7838
7839 if (match && --nth <= 0)
7840 break;
7841 if (l == NULL && !match)
7842 break;
7843
7844 /* Advance to just after the match. */
7845 if (l != NULL)
7846 {
7847 li = li->li_next;
7848 ++idx;
7849 }
7850 else
7851 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852 startcol = (colnr_T)(regmatch.startp[0]
7853 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 if (startcol > (colnr_T)len
7855 || str + startcol <= regmatch.startp[0])
7856 {
7857 match = FALSE;
7858 break;
7859 }
7860 }
7861 }
7862
7863 if (match)
7864 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007865 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 {
7867 listitem_T *li1 = rettv->vval.v_list->lv_first;
7868 listitem_T *li2 = li1->li_next;
7869 listitem_T *li3 = li2->li_next;
7870 listitem_T *li4 = li3->li_next;
7871
7872 vim_free(li1->li_tv.vval.v_string);
7873 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7874 (int)(regmatch.endp[0] - regmatch.startp[0]));
7875 li3->li_tv.vval.v_number =
7876 (varnumber_T)(regmatch.startp[0] - expr);
7877 li4->li_tv.vval.v_number =
7878 (varnumber_T)(regmatch.endp[0] - expr);
7879 if (l != NULL)
7880 li2->li_tv.vval.v_number = (varnumber_T)idx;
7881 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007882 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007883 {
7884 int i;
7885
7886 /* return list with matched string and submatches */
7887 for (i = 0; i < NSUBEXP; ++i)
7888 {
7889 if (regmatch.endp[i] == NULL)
7890 {
7891 if (list_append_string(rettv->vval.v_list,
7892 (char_u *)"", 0) == FAIL)
7893 break;
7894 }
7895 else if (list_append_string(rettv->vval.v_list,
7896 regmatch.startp[i],
7897 (int)(regmatch.endp[i] - regmatch.startp[i]))
7898 == FAIL)
7899 break;
7900 }
7901 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007902 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903 {
7904 /* return matched string */
7905 if (l != NULL)
7906 copy_tv(&li->li_tv, rettv);
7907 else
7908 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7909 (int)(regmatch.endp[0] - regmatch.startp[0]));
7910 }
7911 else if (l != NULL)
7912 rettv->vval.v_number = idx;
7913 else
7914 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007915 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007916 rettv->vval.v_number =
7917 (varnumber_T)(regmatch.startp[0] - str);
7918 else
7919 rettv->vval.v_number =
7920 (varnumber_T)(regmatch.endp[0] - str);
7921 rettv->vval.v_number += (varnumber_T)(str - expr);
7922 }
7923 }
7924 vim_regfree(regmatch.regprog);
7925 }
7926
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007927theend:
7928 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929 /* matchstrpos() without a list: drop the second item. */
7930 listitem_remove(rettv->vval.v_list,
7931 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007932 vim_free(tofree);
7933 p_cpo = save_cpo;
7934}
7935
7936/*
7937 * "match()" function
7938 */
7939 static void
7940f_match(typval_T *argvars, typval_T *rettv)
7941{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007942 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007943}
7944
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007945/*
7946 * "matchend()" function
7947 */
7948 static void
7949f_matchend(typval_T *argvars, typval_T *rettv)
7950{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007951 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952}
7953
7954/*
7955 * "matchlist()" function
7956 */
7957 static void
7958f_matchlist(typval_T *argvars, typval_T *rettv)
7959{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007960 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007961}
7962
7963/*
7964 * "matchstr()" function
7965 */
7966 static void
7967f_matchstr(typval_T *argvars, typval_T *rettv)
7968{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007969 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007970}
7971
7972/*
7973 * "matchstrpos()" function
7974 */
7975 static void
7976f_matchstrpos(typval_T *argvars, typval_T *rettv)
7977{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007978 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979}
7980
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007981 static void
7982max_min(typval_T *argvars, typval_T *rettv, int domax)
7983{
7984 varnumber_T n = 0;
7985 varnumber_T i;
7986 int error = FALSE;
7987
7988 if (argvars[0].v_type == VAR_LIST)
7989 {
7990 list_T *l;
7991 listitem_T *li;
7992
7993 l = argvars[0].vval.v_list;
7994 if (l != NULL)
7995 {
7996 li = l->lv_first;
7997 if (li != NULL)
7998 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007999 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008000 for (;;)
8001 {
8002 li = li->li_next;
8003 if (li == NULL)
8004 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008005 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006 if (domax ? i > n : i < n)
8007 n = i;
8008 }
8009 }
8010 }
8011 }
8012 else if (argvars[0].v_type == VAR_DICT)
8013 {
8014 dict_T *d;
8015 int first = TRUE;
8016 hashitem_T *hi;
8017 int todo;
8018
8019 d = argvars[0].vval.v_dict;
8020 if (d != NULL)
8021 {
8022 todo = (int)d->dv_hashtab.ht_used;
8023 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8024 {
8025 if (!HASHITEM_EMPTY(hi))
8026 {
8027 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008028 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 if (first)
8030 {
8031 n = i;
8032 first = FALSE;
8033 }
8034 else if (domax ? i > n : i < n)
8035 n = i;
8036 }
8037 }
8038 }
8039 }
8040 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008041 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 rettv->vval.v_number = error ? 0 : n;
8043}
8044
8045/*
8046 * "max()" function
8047 */
8048 static void
8049f_max(typval_T *argvars, typval_T *rettv)
8050{
8051 max_min(argvars, rettv, TRUE);
8052}
8053
8054/*
8055 * "min()" function
8056 */
8057 static void
8058f_min(typval_T *argvars, typval_T *rettv)
8059{
8060 max_min(argvars, rettv, FALSE);
8061}
8062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063/*
8064 * Create the directory in which "dir" is located, and higher levels when
8065 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008066 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008067 */
8068 static int
8069mkdir_recurse(char_u *dir, int prot)
8070{
8071 char_u *p;
8072 char_u *updir;
8073 int r = FAIL;
8074
8075 /* Get end of directory name in "dir".
8076 * We're done when it's "/" or "c:/". */
8077 p = gettail_sep(dir);
8078 if (p <= get_past_head(dir))
8079 return OK;
8080
8081 /* If the directory exists we're done. Otherwise: create it.*/
8082 updir = vim_strnsave(dir, (int)(p - dir));
8083 if (updir == NULL)
8084 return FAIL;
8085 if (mch_isdir(updir))
8086 r = OK;
8087 else if (mkdir_recurse(updir, prot) == OK)
8088 r = vim_mkdir_emsg(updir, prot);
8089 vim_free(updir);
8090 return r;
8091}
8092
8093#ifdef vim_mkdir
8094/*
8095 * "mkdir()" function
8096 */
8097 static void
8098f_mkdir(typval_T *argvars, typval_T *rettv)
8099{
8100 char_u *dir;
8101 char_u buf[NUMBUFLEN];
8102 int prot = 0755;
8103
8104 rettv->vval.v_number = FAIL;
8105 if (check_restricted() || check_secure())
8106 return;
8107
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008108 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008109 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008110 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008112 if (*gettail(dir) == NUL)
8113 /* remove trailing slashes */
8114 *gettail_sep(dir) = NUL;
8115
8116 if (argvars[1].v_type != VAR_UNKNOWN)
8117 {
8118 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008120 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008121 if (prot == -1)
8122 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008124 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008125 {
8126 if (mch_isdir(dir))
8127 {
8128 /* With the "p" flag it's OK if the dir already exists. */
8129 rettv->vval.v_number = OK;
8130 return;
8131 }
8132 mkdir_recurse(dir, prot);
8133 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008134 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008135 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136}
8137#endif
8138
8139/*
8140 * "mode()" function
8141 */
8142 static void
8143f_mode(typval_T *argvars, typval_T *rettv)
8144{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008145 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146
Bram Moolenaar612cc382018-07-29 15:34:26 +02008147 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148
8149 if (time_for_testing == 93784)
8150 {
8151 /* Testing the two-character code. */
8152 buf[0] = 'x';
8153 buf[1] = '!';
8154 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008155#ifdef FEAT_TERMINAL
8156 else if (term_use_loop())
8157 buf[0] = 't';
8158#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 else if (VIsual_active)
8160 {
8161 if (VIsual_select)
8162 buf[0] = VIsual_mode + 's' - 'v';
8163 else
8164 buf[0] = VIsual_mode;
8165 }
8166 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8167 || State == CONFIRM)
8168 {
8169 buf[0] = 'r';
8170 if (State == ASKMORE)
8171 buf[1] = 'm';
8172 else if (State == CONFIRM)
8173 buf[1] = '?';
8174 }
8175 else if (State == EXTERNCMD)
8176 buf[0] = '!';
8177 else if (State & INSERT)
8178 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 if (State & VREPLACE_FLAG)
8180 {
8181 buf[0] = 'R';
8182 buf[1] = 'v';
8183 }
8184 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008185 {
8186 if (State & REPLACE_FLAG)
8187 buf[0] = 'R';
8188 else
8189 buf[0] = 'i';
8190#ifdef FEAT_INS_EXPAND
8191 if (ins_compl_active())
8192 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008193 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008194 buf[1] = 'x';
8195#endif
8196 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008197 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008198 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008199 {
8200 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008201 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008203 else if (exmode_active == EXMODE_NORMAL)
8204 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205 }
8206 else
8207 {
8208 buf[0] = 'n';
8209 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008210 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008212 // to be able to detect force-linewise/blockwise/characterwise operations
8213 buf[2] = motion_force;
8214 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008215 else if (restart_edit == 'I' || restart_edit == 'R'
8216 || restart_edit == 'V')
8217 {
8218 buf[1] = 'i';
8219 buf[2] = restart_edit;
8220 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008221 }
8222
8223 /* Clear out the minor mode when the argument is not a non-zero number or
8224 * non-empty string. */
8225 if (!non_zero_arg(&argvars[0]))
8226 buf[1] = NUL;
8227
8228 rettv->vval.v_string = vim_strsave(buf);
8229 rettv->v_type = VAR_STRING;
8230}
8231
8232#if defined(FEAT_MZSCHEME) || defined(PROTO)
8233/*
8234 * "mzeval()" function
8235 */
8236 static void
8237f_mzeval(typval_T *argvars, typval_T *rettv)
8238{
8239 char_u *str;
8240 char_u buf[NUMBUFLEN];
8241
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008242 if (check_restricted() || check_secure())
8243 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008244 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245 do_mzeval(str, rettv);
8246}
8247
8248 void
8249mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8250{
8251 typval_T argvars[3];
8252
8253 argvars[0].v_type = VAR_STRING;
8254 argvars[0].vval.v_string = name;
8255 copy_tv(args, &argvars[1]);
8256 argvars[2].v_type = VAR_UNKNOWN;
8257 f_call(argvars, rettv);
8258 clear_tv(&argvars[1]);
8259}
8260#endif
8261
8262/*
8263 * "nextnonblank()" function
8264 */
8265 static void
8266f_nextnonblank(typval_T *argvars, typval_T *rettv)
8267{
8268 linenr_T lnum;
8269
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008270 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008271 {
8272 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8273 {
8274 lnum = 0;
8275 break;
8276 }
8277 if (*skipwhite(ml_get(lnum)) != NUL)
8278 break;
8279 }
8280 rettv->vval.v_number = lnum;
8281}
8282
8283/*
8284 * "nr2char()" function
8285 */
8286 static void
8287f_nr2char(typval_T *argvars, typval_T *rettv)
8288{
8289 char_u buf[NUMBUFLEN];
8290
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008291 if (has_mbyte)
8292 {
8293 int utf8 = 0;
8294
8295 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008296 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008297 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008298 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008299 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008300 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008301 }
8302 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008304 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 buf[1] = NUL;
8306 }
8307 rettv->v_type = VAR_STRING;
8308 rettv->vval.v_string = vim_strsave(buf);
8309}
8310
8311/*
8312 * "or(expr, expr)" function
8313 */
8314 static void
8315f_or(typval_T *argvars, typval_T *rettv)
8316{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008317 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8318 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319}
8320
8321/*
8322 * "pathshorten()" function
8323 */
8324 static void
8325f_pathshorten(typval_T *argvars, typval_T *rettv)
8326{
8327 char_u *p;
8328
8329 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008330 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331 if (p == NULL)
8332 rettv->vval.v_string = NULL;
8333 else
8334 {
8335 p = vim_strsave(p);
8336 rettv->vval.v_string = p;
8337 if (p != NULL)
8338 shorten_dir(p);
8339 }
8340}
8341
8342#ifdef FEAT_PERL
8343/*
8344 * "perleval()" function
8345 */
8346 static void
8347f_perleval(typval_T *argvars, typval_T *rettv)
8348{
8349 char_u *str;
8350 char_u buf[NUMBUFLEN];
8351
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008352 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 do_perleval(str, rettv);
8354}
8355#endif
8356
8357#ifdef FEAT_FLOAT
8358/*
8359 * "pow()" function
8360 */
8361 static void
8362f_pow(typval_T *argvars, typval_T *rettv)
8363{
8364 float_T fx = 0.0, fy = 0.0;
8365
8366 rettv->v_type = VAR_FLOAT;
8367 if (get_float_arg(argvars, &fx) == OK
8368 && get_float_arg(&argvars[1], &fy) == OK)
8369 rettv->vval.v_float = pow(fx, fy);
8370 else
8371 rettv->vval.v_float = 0.0;
8372}
8373#endif
8374
8375/*
8376 * "prevnonblank()" function
8377 */
8378 static void
8379f_prevnonblank(typval_T *argvars, typval_T *rettv)
8380{
8381 linenr_T lnum;
8382
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008383 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8385 lnum = 0;
8386 else
8387 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8388 --lnum;
8389 rettv->vval.v_number = lnum;
8390}
8391
8392/* This dummy va_list is here because:
8393 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8394 * - locally in the function results in a "used before set" warning
8395 * - using va_start() to initialize it gives "function with fixed args" error */
8396static va_list ap;
8397
8398/*
8399 * "printf()" function
8400 */
8401 static void
8402f_printf(typval_T *argvars, typval_T *rettv)
8403{
8404 char_u buf[NUMBUFLEN];
8405 int len;
8406 char_u *s;
8407 int saved_did_emsg = did_emsg;
8408 char *fmt;
8409
8410 rettv->v_type = VAR_STRING;
8411 rettv->vval.v_string = NULL;
8412
8413 /* Get the required length, allocate the buffer and do it for real. */
8414 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008415 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008416 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008417 if (!did_emsg)
8418 {
8419 s = alloc(len + 1);
8420 if (s != NULL)
8421 {
8422 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008423 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8424 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008425 }
8426 }
8427 did_emsg |= saved_did_emsg;
8428}
8429
8430/*
8431 * "pumvisible()" function
8432 */
8433 static void
8434f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8435{
8436#ifdef FEAT_INS_EXPAND
8437 if (pum_visible())
8438 rettv->vval.v_number = 1;
8439#endif
8440}
8441
8442#ifdef FEAT_PYTHON3
8443/*
8444 * "py3eval()" function
8445 */
8446 static void
8447f_py3eval(typval_T *argvars, typval_T *rettv)
8448{
8449 char_u *str;
8450 char_u buf[NUMBUFLEN];
8451
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008452 if (check_restricted() || check_secure())
8453 return;
8454
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008455 if (p_pyx == 0)
8456 p_pyx = 3;
8457
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008458 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 do_py3eval(str, rettv);
8460}
8461#endif
8462
8463#ifdef FEAT_PYTHON
8464/*
8465 * "pyeval()" function
8466 */
8467 static void
8468f_pyeval(typval_T *argvars, typval_T *rettv)
8469{
8470 char_u *str;
8471 char_u buf[NUMBUFLEN];
8472
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008473 if (check_restricted() || check_secure())
8474 return;
8475
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008476 if (p_pyx == 0)
8477 p_pyx = 2;
8478
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008479 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480 do_pyeval(str, rettv);
8481}
8482#endif
8483
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008484#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8485/*
8486 * "pyxeval()" function
8487 */
8488 static void
8489f_pyxeval(typval_T *argvars, typval_T *rettv)
8490{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008491 if (check_restricted() || check_secure())
8492 return;
8493
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008494# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8495 init_pyxversion();
8496 if (p_pyx == 2)
8497 f_pyeval(argvars, rettv);
8498 else
8499 f_py3eval(argvars, rettv);
8500# elif defined(FEAT_PYTHON)
8501 f_pyeval(argvars, rettv);
8502# elif defined(FEAT_PYTHON3)
8503 f_py3eval(argvars, rettv);
8504# endif
8505}
8506#endif
8507
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008508/*
8509 * "range()" function
8510 */
8511 static void
8512f_range(typval_T *argvars, typval_T *rettv)
8513{
8514 varnumber_T start;
8515 varnumber_T end;
8516 varnumber_T stride = 1;
8517 varnumber_T i;
8518 int error = FALSE;
8519
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008520 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008521 if (argvars[1].v_type == VAR_UNKNOWN)
8522 {
8523 end = start - 1;
8524 start = 0;
8525 }
8526 else
8527 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008528 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008529 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008530 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008531 }
8532
8533 if (error)
8534 return; /* type error; errmsg already given */
8535 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008536 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008537 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008538 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008539 else
8540 {
8541 if (rettv_list_alloc(rettv) == OK)
8542 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8543 if (list_append_number(rettv->vval.v_list,
8544 (varnumber_T)i) == FAIL)
8545 break;
8546 }
8547}
8548
8549/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008550 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008551 */
8552 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008553readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008554{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008555 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008556 typval_T save_val;
8557 typval_T rettv;
8558 typval_T argv[2];
8559 int retval = 0;
8560 int error = FALSE;
8561
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008562 if (expr->v_type == VAR_UNKNOWN)
8563 return 1;
8564
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008565 prepare_vimvar(VV_VAL, &save_val);
8566 set_vim_var_string(VV_VAL, name, -1);
8567 argv[0].v_type = VAR_STRING;
8568 argv[0].vval.v_string = name;
8569
8570 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8571 goto theend;
8572
8573 retval = tv_get_number_chk(&rettv, &error);
8574 if (error)
8575 retval = -1;
8576 clear_tv(&rettv);
8577
8578theend:
8579 set_vim_var_string(VV_VAL, NULL, 0);
8580 restore_vimvar(VV_VAL, &save_val);
8581 return retval;
8582}
8583
8584/*
8585 * "readdir()" function
8586 */
8587 static void
8588f_readdir(typval_T *argvars, typval_T *rettv)
8589{
8590 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008591 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008592 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008593 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008594 garray_T ga;
8595 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008596
8597 if (rettv_list_alloc(rettv) == FAIL)
8598 return;
8599 path = tv_get_string(&argvars[0]);
8600 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008601
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008602 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8603 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008604 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008605 for (i = 0; i < ga.ga_len; i++)
8606 {
8607 p = ((char_u **)ga.ga_data)[i];
8608 list_append_string(rettv->vval.v_list, p, -1);
8609 }
8610 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008611 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008612}
8613
8614/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008615 * "readfile()" function
8616 */
8617 static void
8618f_readfile(typval_T *argvars, typval_T *rettv)
8619{
8620 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008621 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008622 int failed = FALSE;
8623 char_u *fname;
8624 FILE *fd;
8625 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8626 int io_size = sizeof(buf);
8627 int readlen; /* size of last fread() */
8628 char_u *prev = NULL; /* previously read bytes, if any */
8629 long prevlen = 0; /* length of data in prev */
8630 long prevsize = 0; /* size of prev buffer */
8631 long maxline = MAXLNUM;
8632 long cnt = 0;
8633 char_u *p; /* position in buf */
8634 char_u *start; /* start of current line */
8635
8636 if (argvars[1].v_type != VAR_UNKNOWN)
8637 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008638 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008639 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008640 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8641 blob = TRUE;
8642
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008643 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008644 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008645 }
8646
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008647 if (blob)
8648 {
8649 if (rettv_blob_alloc(rettv) == FAIL)
8650 return;
8651 }
8652 else
8653 {
8654 if (rettv_list_alloc(rettv) == FAIL)
8655 return;
8656 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008657
8658 /* Always open the file in binary mode, library functions have a mind of
8659 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008660 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008661 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8662 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008663 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008664 return;
8665 }
8666
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008667 if (blob)
8668 {
8669 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8670 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008671 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008672 blob_free(rettv->vval.v_blob);
8673 }
8674 fclose(fd);
8675 return;
8676 }
8677
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008678 while (cnt < maxline || maxline < 0)
8679 {
8680 readlen = (int)fread(buf, 1, io_size, fd);
8681
8682 /* This for loop processes what was read, but is also entered at end
8683 * of file so that either:
8684 * - an incomplete line gets written
8685 * - a "binary" file gets an empty line at the end if it ends in a
8686 * newline. */
8687 for (p = buf, start = buf;
8688 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8689 ++p)
8690 {
8691 if (*p == '\n' || readlen <= 0)
8692 {
8693 listitem_T *li;
8694 char_u *s = NULL;
8695 long_u len = p - start;
8696
8697 /* Finished a line. Remove CRs before NL. */
8698 if (readlen > 0 && !binary)
8699 {
8700 while (len > 0 && start[len - 1] == '\r')
8701 --len;
8702 /* removal may cross back to the "prev" string */
8703 if (len == 0)
8704 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8705 --prevlen;
8706 }
8707 if (prevlen == 0)
8708 s = vim_strnsave(start, (int)len);
8709 else
8710 {
8711 /* Change "prev" buffer to be the right size. This way
8712 * the bytes are only copied once, and very long lines are
8713 * allocated only once. */
8714 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8715 {
8716 mch_memmove(s + prevlen, start, len);
8717 s[prevlen + len] = NUL;
8718 prev = NULL; /* the list will own the string */
8719 prevlen = prevsize = 0;
8720 }
8721 }
8722 if (s == NULL)
8723 {
8724 do_outofmem_msg((long_u) prevlen + len + 1);
8725 failed = TRUE;
8726 break;
8727 }
8728
8729 if ((li = listitem_alloc()) == NULL)
8730 {
8731 vim_free(s);
8732 failed = TRUE;
8733 break;
8734 }
8735 li->li_tv.v_type = VAR_STRING;
8736 li->li_tv.v_lock = 0;
8737 li->li_tv.vval.v_string = s;
8738 list_append(rettv->vval.v_list, li);
8739
8740 start = p + 1; /* step over newline */
8741 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8742 break;
8743 }
8744 else if (*p == NUL)
8745 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8747 * when finding the BF and check the previous two bytes. */
8748 else if (*p == 0xbf && enc_utf8 && !binary)
8749 {
8750 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8751 * + 1, these may be in the "prev" string. */
8752 char_u back1 = p >= buf + 1 ? p[-1]
8753 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8754 char_u back2 = p >= buf + 2 ? p[-2]
8755 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8756 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8757
8758 if (back2 == 0xef && back1 == 0xbb)
8759 {
8760 char_u *dest = p - 2;
8761
8762 /* Usually a BOM is at the beginning of a file, and so at
8763 * the beginning of a line; then we can just step over it.
8764 */
8765 if (start == dest)
8766 start = p + 1;
8767 else
8768 {
8769 /* have to shuffle buf to close gap */
8770 int adjust_prevlen = 0;
8771
8772 if (dest < buf)
8773 {
8774 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8775 dest = buf;
8776 }
8777 if (readlen > p - buf + 1)
8778 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8779 readlen -= 3 - adjust_prevlen;
8780 prevlen -= adjust_prevlen;
8781 p = dest - 1;
8782 }
8783 }
8784 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 } /* for */
8786
8787 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8788 break;
8789 if (start < p)
8790 {
8791 /* There's part of a line in buf, store it in "prev". */
8792 if (p - start + prevlen >= prevsize)
8793 {
8794 /* need bigger "prev" buffer */
8795 char_u *newprev;
8796
8797 /* A common use case is ordinary text files and "prev" gets a
8798 * fragment of a line, so the first allocation is made
8799 * small, to avoid repeatedly 'allocing' large and
8800 * 'reallocing' small. */
8801 if (prevsize == 0)
8802 prevsize = (long)(p - start);
8803 else
8804 {
8805 long grow50pc = (prevsize * 3) / 2;
8806 long growmin = (long)((p - start) * 2 + prevlen);
8807 prevsize = grow50pc > growmin ? grow50pc : growmin;
8808 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008809 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008810 if (newprev == NULL)
8811 {
8812 do_outofmem_msg((long_u)prevsize);
8813 failed = TRUE;
8814 break;
8815 }
8816 prev = newprev;
8817 }
8818 /* Add the line part to end of "prev". */
8819 mch_memmove(prev + prevlen, start, p - start);
8820 prevlen += (long)(p - start);
8821 }
8822 } /* while */
8823
8824 /*
8825 * For a negative line count use only the lines at the end of the file,
8826 * free the rest.
8827 */
8828 if (!failed && maxline < 0)
8829 while (cnt > -maxline)
8830 {
8831 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8832 --cnt;
8833 }
8834
8835 if (failed)
8836 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008837 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008838 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008839 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008840 }
8841
8842 vim_free(prev);
8843 fclose(fd);
8844}
8845
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008846 static void
8847return_register(int regname, typval_T *rettv)
8848{
8849 char_u buf[2] = {0, 0};
8850
8851 buf[0] = (char_u)regname;
8852 rettv->v_type = VAR_STRING;
8853 rettv->vval.v_string = vim_strsave(buf);
8854}
8855
8856/*
8857 * "reg_executing()" function
8858 */
8859 static void
8860f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8861{
8862 return_register(reg_executing, rettv);
8863}
8864
8865/*
8866 * "reg_recording()" function
8867 */
8868 static void
8869f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8870{
8871 return_register(reg_recording, rettv);
8872}
8873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008875/*
8876 * Convert a List to proftime_T.
8877 * Return FAIL when there is something wrong.
8878 */
8879 static int
8880list2proftime(typval_T *arg, proftime_T *tm)
8881{
8882 long n1, n2;
8883 int error = FALSE;
8884
8885 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8886 || arg->vval.v_list->lv_len != 2)
8887 return FAIL;
8888 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8889 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008890# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008891 tm->HighPart = n1;
8892 tm->LowPart = n2;
8893# else
8894 tm->tv_sec = n1;
8895 tm->tv_usec = n2;
8896# endif
8897 return error ? FAIL : OK;
8898}
8899#endif /* FEAT_RELTIME */
8900
8901/*
8902 * "reltime()" function
8903 */
8904 static void
8905f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8906{
8907#ifdef FEAT_RELTIME
8908 proftime_T res;
8909 proftime_T start;
8910
8911 if (argvars[0].v_type == VAR_UNKNOWN)
8912 {
8913 /* No arguments: get current time. */
8914 profile_start(&res);
8915 }
8916 else if (argvars[1].v_type == VAR_UNKNOWN)
8917 {
8918 if (list2proftime(&argvars[0], &res) == FAIL)
8919 return;
8920 profile_end(&res);
8921 }
8922 else
8923 {
8924 /* Two arguments: compute the difference. */
8925 if (list2proftime(&argvars[0], &start) == FAIL
8926 || list2proftime(&argvars[1], &res) == FAIL)
8927 return;
8928 profile_sub(&res, &start);
8929 }
8930
8931 if (rettv_list_alloc(rettv) == OK)
8932 {
8933 long n1, n2;
8934
Bram Moolenaar4f974752019-02-17 17:44:42 +01008935# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008936 n1 = res.HighPart;
8937 n2 = res.LowPart;
8938# else
8939 n1 = res.tv_sec;
8940 n2 = res.tv_usec;
8941# endif
8942 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8943 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8944 }
8945#endif
8946}
8947
8948#ifdef FEAT_FLOAT
8949/*
8950 * "reltimefloat()" function
8951 */
8952 static void
8953f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8954{
8955# ifdef FEAT_RELTIME
8956 proftime_T tm;
8957# endif
8958
8959 rettv->v_type = VAR_FLOAT;
8960 rettv->vval.v_float = 0;
8961# ifdef FEAT_RELTIME
8962 if (list2proftime(&argvars[0], &tm) == OK)
8963 rettv->vval.v_float = profile_float(&tm);
8964# endif
8965}
8966#endif
8967
8968/*
8969 * "reltimestr()" function
8970 */
8971 static void
8972f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8973{
8974#ifdef FEAT_RELTIME
8975 proftime_T tm;
8976#endif
8977
8978 rettv->v_type = VAR_STRING;
8979 rettv->vval.v_string = NULL;
8980#ifdef FEAT_RELTIME
8981 if (list2proftime(&argvars[0], &tm) == OK)
8982 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8983#endif
8984}
8985
8986#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008987 static void
8988make_connection(void)
8989{
8990 if (X_DISPLAY == NULL
8991# ifdef FEAT_GUI
8992 && !gui.in_use
8993# endif
8994 )
8995 {
8996 x_force_connect = TRUE;
8997 setup_term_clip();
8998 x_force_connect = FALSE;
8999 }
9000}
9001
9002 static int
9003check_connection(void)
9004{
9005 make_connection();
9006 if (X_DISPLAY == NULL)
9007 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009008 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009009 return FAIL;
9010 }
9011 return OK;
9012}
9013#endif
9014
9015#ifdef FEAT_CLIENTSERVER
9016 static void
9017remote_common(typval_T *argvars, typval_T *rettv, int expr)
9018{
9019 char_u *server_name;
9020 char_u *keys;
9021 char_u *r = NULL;
9022 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009023 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009024# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009025 HWND w;
9026# else
9027 Window w;
9028# endif
9029
9030 if (check_restricted() || check_secure())
9031 return;
9032
9033# ifdef FEAT_X11
9034 if (check_connection() == FAIL)
9035 return;
9036# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009037 if (argvars[2].v_type != VAR_UNKNOWN
9038 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009039 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009040
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009041 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009042 if (server_name == NULL)
9043 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009044 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009045# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009046 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009047# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009048 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9049 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009050# endif
9051 {
9052 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009053 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009054 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009055 vim_free(r);
9056 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009057 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009058 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009059 return;
9060 }
9061
9062 rettv->vval.v_string = r;
9063
9064 if (argvars[2].v_type != VAR_UNKNOWN)
9065 {
9066 dictitem_T v;
9067 char_u str[30];
9068 char_u *idvar;
9069
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009070 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009071 if (idvar != NULL && *idvar != NUL)
9072 {
9073 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9074 v.di_tv.v_type = VAR_STRING;
9075 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009076 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009077 vim_free(v.di_tv.vval.v_string);
9078 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009079 }
9080}
9081#endif
9082
9083/*
9084 * "remote_expr()" function
9085 */
9086 static void
9087f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9088{
9089 rettv->v_type = VAR_STRING;
9090 rettv->vval.v_string = NULL;
9091#ifdef FEAT_CLIENTSERVER
9092 remote_common(argvars, rettv, TRUE);
9093#endif
9094}
9095
9096/*
9097 * "remote_foreground()" function
9098 */
9099 static void
9100f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9101{
9102#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009103# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009104 /* On Win32 it's done in this application. */
9105 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009106 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009107
9108 if (server_name != NULL)
9109 serverForeground(server_name);
9110 }
9111# else
9112 /* Send a foreground() expression to the server. */
9113 argvars[1].v_type = VAR_STRING;
9114 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9115 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009116 rettv->v_type = VAR_STRING;
9117 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009118 remote_common(argvars, rettv, TRUE);
9119 vim_free(argvars[1].vval.v_string);
9120# endif
9121#endif
9122}
9123
9124 static void
9125f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9126{
9127#ifdef FEAT_CLIENTSERVER
9128 dictitem_T v;
9129 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009130# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009131 long_u n = 0;
9132# endif
9133 char_u *serverid;
9134
9135 if (check_restricted() || check_secure())
9136 {
9137 rettv->vval.v_number = -1;
9138 return;
9139 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009140 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009141 if (serverid == NULL)
9142 {
9143 rettv->vval.v_number = -1;
9144 return; /* type error; errmsg already given */
9145 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009146# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009147 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9148 if (n == 0)
9149 rettv->vval.v_number = -1;
9150 else
9151 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009152 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009153 rettv->vval.v_number = (s != NULL);
9154 }
9155# else
9156 if (check_connection() == FAIL)
9157 return;
9158
9159 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9160 serverStrToWin(serverid), &s);
9161# endif
9162
9163 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9164 {
9165 char_u *retvar;
9166
9167 v.di_tv.v_type = VAR_STRING;
9168 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009169 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009170 if (retvar != NULL)
9171 set_var(retvar, &v.di_tv, FALSE);
9172 vim_free(v.di_tv.vval.v_string);
9173 }
9174#else
9175 rettv->vval.v_number = -1;
9176#endif
9177}
9178
9179 static void
9180f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9181{
9182 char_u *r = NULL;
9183
9184#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009185 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009186
9187 if (serverid != NULL && !check_restricted() && !check_secure())
9188 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009189 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009190# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009191 /* The server's HWND is encoded in the 'id' parameter */
9192 long_u n = 0;
9193# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009194
9195 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009196 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009197
Bram Moolenaar4f974752019-02-17 17:44:42 +01009198# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009199 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9200 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009201 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009202 if (r == NULL)
9203# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009204 if (check_connection() == FAIL
9205 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9206 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009207# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009208 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009209 }
9210#endif
9211 rettv->v_type = VAR_STRING;
9212 rettv->vval.v_string = r;
9213}
9214
9215/*
9216 * "remote_send()" function
9217 */
9218 static void
9219f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9220{
9221 rettv->v_type = VAR_STRING;
9222 rettv->vval.v_string = NULL;
9223#ifdef FEAT_CLIENTSERVER
9224 remote_common(argvars, rettv, FALSE);
9225#endif
9226}
9227
9228/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009229 * "remote_startserver()" function
9230 */
9231 static void
9232f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9233{
9234#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009235 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009236
9237 if (server == NULL)
9238 return; /* type error; errmsg already given */
9239 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009240 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009241 else
9242 {
9243# ifdef FEAT_X11
9244 if (check_connection() == OK)
9245 serverRegisterName(X_DISPLAY, server);
9246# else
9247 serverSetName(server);
9248# endif
9249 }
9250#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009251 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009252#endif
9253}
9254
9255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009256 * "remove()" function
9257 */
9258 static void
9259f_remove(typval_T *argvars, typval_T *rettv)
9260{
9261 list_T *l;
9262 listitem_T *item, *item2;
9263 listitem_T *li;
9264 long idx;
9265 long end;
9266 char_u *key;
9267 dict_T *d;
9268 dictitem_T *di;
9269 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009270 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009271
9272 if (argvars[0].v_type == VAR_DICT)
9273 {
9274 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009275 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009276 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009277 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009278 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009279 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009280 if (key != NULL)
9281 {
9282 di = dict_find(d, key, -1);
9283 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009284 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009285 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9286 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9287 {
9288 *rettv = di->di_tv;
9289 init_tv(&di->di_tv);
9290 dictitem_remove(d, di);
9291 }
9292 }
9293 }
9294 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009295 else if (argvars[0].v_type == VAR_BLOB)
9296 {
9297 idx = (long)tv_get_number_chk(&argvars[1], &error);
9298 if (!error)
9299 {
9300 blob_T *b = argvars[0].vval.v_blob;
9301 int len = blob_len(b);
9302 char_u *p;
9303
9304 if (idx < 0)
9305 // count from the end
9306 idx = len + idx;
9307 if (idx < 0 || idx >= len)
9308 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009309 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009310 return;
9311 }
9312 if (argvars[2].v_type == VAR_UNKNOWN)
9313 {
9314 // Remove one item, return its value.
9315 p = (char_u *)b->bv_ga.ga_data;
9316 rettv->vval.v_number = (varnumber_T) *(p + idx);
9317 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9318 --b->bv_ga.ga_len;
9319 }
9320 else
9321 {
9322 blob_T *blob;
9323
9324 // Remove range of items, return list with values.
9325 end = (long)tv_get_number_chk(&argvars[2], &error);
9326 if (error)
9327 return;
9328 if (end < 0)
9329 // count from the end
9330 end = len + end;
9331 if (end >= len || idx > end)
9332 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009333 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009334 return;
9335 }
9336 blob = blob_alloc();
9337 if (blob == NULL)
9338 return;
9339 blob->bv_ga.ga_len = end - idx + 1;
9340 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9341 {
9342 vim_free(blob);
9343 return;
9344 }
9345 p = (char_u *)b->bv_ga.ga_data;
9346 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9347 (size_t)(end - idx + 1));
9348 ++blob->bv_refcount;
9349 rettv->v_type = VAR_BLOB;
9350 rettv->vval.v_blob = blob;
9351
9352 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9353 b->bv_ga.ga_len -= end - idx + 1;
9354 }
9355 }
9356 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009357 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009358 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009359 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009360 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009361 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009362 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009363 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009364 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009365 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009366 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009367 else
9368 {
9369 if (argvars[2].v_type == VAR_UNKNOWN)
9370 {
9371 /* Remove one item, return its value. */
9372 vimlist_remove(l, item, item);
9373 *rettv = item->li_tv;
9374 vim_free(item);
9375 }
9376 else
9377 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009378 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009379 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009380 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009381 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009382 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009383 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009384 else
9385 {
9386 int cnt = 0;
9387
9388 for (li = item; li != NULL; li = li->li_next)
9389 {
9390 ++cnt;
9391 if (li == item2)
9392 break;
9393 }
9394 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009395 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009396 else
9397 {
9398 vimlist_remove(l, item, item2);
9399 if (rettv_list_alloc(rettv) == OK)
9400 {
9401 l = rettv->vval.v_list;
9402 l->lv_first = item;
9403 l->lv_last = item2;
9404 item->li_prev = NULL;
9405 item2->li_next = NULL;
9406 l->lv_len = cnt;
9407 }
9408 }
9409 }
9410 }
9411 }
9412 }
9413}
9414
9415/*
9416 * "rename({from}, {to})" function
9417 */
9418 static void
9419f_rename(typval_T *argvars, typval_T *rettv)
9420{
9421 char_u buf[NUMBUFLEN];
9422
9423 if (check_restricted() || check_secure())
9424 rettv->vval.v_number = -1;
9425 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009426 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9427 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009428}
9429
9430/*
9431 * "repeat()" function
9432 */
9433 static void
9434f_repeat(typval_T *argvars, typval_T *rettv)
9435{
9436 char_u *p;
9437 int n;
9438 int slen;
9439 int len;
9440 char_u *r;
9441 int i;
9442
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009443 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009444 if (argvars[0].v_type == VAR_LIST)
9445 {
9446 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9447 while (n-- > 0)
9448 if (list_extend(rettv->vval.v_list,
9449 argvars[0].vval.v_list, NULL) == FAIL)
9450 break;
9451 }
9452 else
9453 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009454 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009455 rettv->v_type = VAR_STRING;
9456 rettv->vval.v_string = NULL;
9457
9458 slen = (int)STRLEN(p);
9459 len = slen * n;
9460 if (len <= 0)
9461 return;
9462
9463 r = alloc(len + 1);
9464 if (r != NULL)
9465 {
9466 for (i = 0; i < n; i++)
9467 mch_memmove(r + i * slen, p, (size_t)slen);
9468 r[len] = NUL;
9469 }
9470
9471 rettv->vval.v_string = r;
9472 }
9473}
9474
9475/*
9476 * "resolve()" function
9477 */
9478 static void
9479f_resolve(typval_T *argvars, typval_T *rettv)
9480{
9481 char_u *p;
9482#ifdef HAVE_READLINK
9483 char_u *buf = NULL;
9484#endif
9485
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009486 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487#ifdef FEAT_SHORTCUT
9488 {
9489 char_u *v = NULL;
9490
Bram Moolenaardce1e892019-02-10 23:18:53 +01009491 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492 if (v != NULL)
9493 rettv->vval.v_string = v;
9494 else
9495 rettv->vval.v_string = vim_strsave(p);
9496 }
9497#else
9498# ifdef HAVE_READLINK
9499 {
9500 char_u *cpy;
9501 int len;
9502 char_u *remain = NULL;
9503 char_u *q;
9504 int is_relative_to_current = FALSE;
9505 int has_trailing_pathsep = FALSE;
9506 int limit = 100;
9507
9508 p = vim_strsave(p);
9509
9510 if (p[0] == '.' && (vim_ispathsep(p[1])
9511 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9512 is_relative_to_current = TRUE;
9513
9514 len = STRLEN(p);
9515 if (len > 0 && after_pathsep(p, p + len))
9516 {
9517 has_trailing_pathsep = TRUE;
9518 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9519 }
9520
9521 q = getnextcomp(p);
9522 if (*q != NUL)
9523 {
9524 /* Separate the first path component in "p", and keep the
9525 * remainder (beginning with the path separator). */
9526 remain = vim_strsave(q - 1);
9527 q[-1] = NUL;
9528 }
9529
9530 buf = alloc(MAXPATHL + 1);
9531 if (buf == NULL)
9532 goto fail;
9533
9534 for (;;)
9535 {
9536 for (;;)
9537 {
9538 len = readlink((char *)p, (char *)buf, MAXPATHL);
9539 if (len <= 0)
9540 break;
9541 buf[len] = NUL;
9542
9543 if (limit-- == 0)
9544 {
9545 vim_free(p);
9546 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009547 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009548 rettv->vval.v_string = NULL;
9549 goto fail;
9550 }
9551
9552 /* Ensure that the result will have a trailing path separator
9553 * if the argument has one. */
9554 if (remain == NULL && has_trailing_pathsep)
9555 add_pathsep(buf);
9556
9557 /* Separate the first path component in the link value and
9558 * concatenate the remainders. */
9559 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9560 if (*q != NUL)
9561 {
9562 if (remain == NULL)
9563 remain = vim_strsave(q - 1);
9564 else
9565 {
9566 cpy = concat_str(q - 1, remain);
9567 if (cpy != NULL)
9568 {
9569 vim_free(remain);
9570 remain = cpy;
9571 }
9572 }
9573 q[-1] = NUL;
9574 }
9575
9576 q = gettail(p);
9577 if (q > p && *q == NUL)
9578 {
9579 /* Ignore trailing path separator. */
9580 q[-1] = NUL;
9581 q = gettail(p);
9582 }
9583 if (q > p && !mch_isFullName(buf))
9584 {
9585 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009586 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009587 if (cpy != NULL)
9588 {
9589 STRCPY(cpy, p);
9590 STRCPY(gettail(cpy), buf);
9591 vim_free(p);
9592 p = cpy;
9593 }
9594 }
9595 else
9596 {
9597 vim_free(p);
9598 p = vim_strsave(buf);
9599 }
9600 }
9601
9602 if (remain == NULL)
9603 break;
9604
9605 /* Append the first path component of "remain" to "p". */
9606 q = getnextcomp(remain + 1);
9607 len = q - remain - (*q != NUL);
9608 cpy = vim_strnsave(p, STRLEN(p) + len);
9609 if (cpy != NULL)
9610 {
9611 STRNCAT(cpy, remain, len);
9612 vim_free(p);
9613 p = cpy;
9614 }
9615 /* Shorten "remain". */
9616 if (*q != NUL)
9617 STRMOVE(remain, q - 1);
9618 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009619 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009620 }
9621
9622 /* If the result is a relative path name, make it explicitly relative to
9623 * the current directory if and only if the argument had this form. */
9624 if (!vim_ispathsep(*p))
9625 {
9626 if (is_relative_to_current
9627 && *p != NUL
9628 && !(p[0] == '.'
9629 && (p[1] == NUL
9630 || vim_ispathsep(p[1])
9631 || (p[1] == '.'
9632 && (p[2] == NUL
9633 || vim_ispathsep(p[2]))))))
9634 {
9635 /* Prepend "./". */
9636 cpy = concat_str((char_u *)"./", p);
9637 if (cpy != NULL)
9638 {
9639 vim_free(p);
9640 p = cpy;
9641 }
9642 }
9643 else if (!is_relative_to_current)
9644 {
9645 /* Strip leading "./". */
9646 q = p;
9647 while (q[0] == '.' && vim_ispathsep(q[1]))
9648 q += 2;
9649 if (q > p)
9650 STRMOVE(p, p + 2);
9651 }
9652 }
9653
9654 /* Ensure that the result will have no trailing path separator
9655 * if the argument had none. But keep "/" or "//". */
9656 if (!has_trailing_pathsep)
9657 {
9658 q = p + STRLEN(p);
9659 if (after_pathsep(p, q))
9660 *gettail_sep(p) = NUL;
9661 }
9662
9663 rettv->vval.v_string = p;
9664 }
9665# else
9666 rettv->vval.v_string = vim_strsave(p);
9667# endif
9668#endif
9669
9670 simplify_filename(rettv->vval.v_string);
9671
9672#ifdef HAVE_READLINK
9673fail:
9674 vim_free(buf);
9675#endif
9676 rettv->v_type = VAR_STRING;
9677}
9678
9679/*
9680 * "reverse({list})" function
9681 */
9682 static void
9683f_reverse(typval_T *argvars, typval_T *rettv)
9684{
9685 list_T *l;
9686 listitem_T *li, *ni;
9687
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009688 if (argvars[0].v_type == VAR_BLOB)
9689 {
9690 blob_T *b = argvars[0].vval.v_blob;
9691 int i, len = blob_len(b);
9692
9693 for (i = 0; i < len / 2; i++)
9694 {
9695 int tmp = blob_get(b, i);
9696
9697 blob_set(b, i, blob_get(b, len - i - 1));
9698 blob_set(b, len - i - 1, tmp);
9699 }
9700 rettv_blob_set(rettv, b);
9701 return;
9702 }
9703
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009704 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009705 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009706 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009707 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009708 (char_u *)N_("reverse() argument"), TRUE))
9709 {
9710 li = l->lv_last;
9711 l->lv_first = l->lv_last = NULL;
9712 l->lv_len = 0;
9713 while (li != NULL)
9714 {
9715 ni = li->li_prev;
9716 list_append(l, li);
9717 li = ni;
9718 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009719 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009720 l->lv_idx = l->lv_len - l->lv_idx - 1;
9721 }
9722}
9723
9724#define SP_NOMOVE 0x01 /* don't move cursor */
9725#define SP_REPEAT 0x02 /* repeat to find outer pair */
9726#define SP_RETCOUNT 0x04 /* return matchcount */
9727#define SP_SETPCMARK 0x08 /* set previous context mark */
9728#define SP_START 0x10 /* accept match at start position */
9729#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9730#define SP_END 0x40 /* leave cursor at end of match */
9731#define SP_COLUMN 0x80 /* start at cursor column */
9732
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009733/*
9734 * Get flags for a search function.
9735 * Possibly sets "p_ws".
9736 * Returns BACKWARD, FORWARD or zero (for an error).
9737 */
9738 static int
9739get_search_arg(typval_T *varp, int *flagsp)
9740{
9741 int dir = FORWARD;
9742 char_u *flags;
9743 char_u nbuf[NUMBUFLEN];
9744 int mask;
9745
9746 if (varp->v_type != VAR_UNKNOWN)
9747 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009748 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009749 if (flags == NULL)
9750 return 0; /* type error; errmsg already given */
9751 while (*flags != NUL)
9752 {
9753 switch (*flags)
9754 {
9755 case 'b': dir = BACKWARD; break;
9756 case 'w': p_ws = TRUE; break;
9757 case 'W': p_ws = FALSE; break;
9758 default: mask = 0;
9759 if (flagsp != NULL)
9760 switch (*flags)
9761 {
9762 case 'c': mask = SP_START; break;
9763 case 'e': mask = SP_END; break;
9764 case 'm': mask = SP_RETCOUNT; break;
9765 case 'n': mask = SP_NOMOVE; break;
9766 case 'p': mask = SP_SUBPAT; break;
9767 case 'r': mask = SP_REPEAT; break;
9768 case 's': mask = SP_SETPCMARK; break;
9769 case 'z': mask = SP_COLUMN; break;
9770 }
9771 if (mask == 0)
9772 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009773 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009774 dir = 0;
9775 }
9776 else
9777 *flagsp |= mask;
9778 }
9779 if (dir == 0)
9780 break;
9781 ++flags;
9782 }
9783 }
9784 return dir;
9785}
9786
9787/*
9788 * Shared by search() and searchpos() functions.
9789 */
9790 static int
9791search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9792{
9793 int flags;
9794 char_u *pat;
9795 pos_T pos;
9796 pos_T save_cursor;
9797 int save_p_ws = p_ws;
9798 int dir;
9799 int retval = 0; /* default: FAIL */
9800 long lnum_stop = 0;
9801 proftime_T tm;
9802#ifdef FEAT_RELTIME
9803 long time_limit = 0;
9804#endif
9805 int options = SEARCH_KEEP;
9806 int subpatnum;
9807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009808 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9810 if (dir == 0)
9811 goto theend;
9812 flags = *flagsp;
9813 if (flags & SP_START)
9814 options |= SEARCH_START;
9815 if (flags & SP_END)
9816 options |= SEARCH_END;
9817 if (flags & SP_COLUMN)
9818 options |= SEARCH_COL;
9819
9820 /* Optional arguments: line number to stop searching and timeout. */
9821 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009823 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009824 if (lnum_stop < 0)
9825 goto theend;
9826#ifdef FEAT_RELTIME
9827 if (argvars[3].v_type != VAR_UNKNOWN)
9828 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009829 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009830 if (time_limit < 0)
9831 goto theend;
9832 }
9833#endif
9834 }
9835
9836#ifdef FEAT_RELTIME
9837 /* Set the time limit, if there is one. */
9838 profile_setlimit(time_limit, &tm);
9839#endif
9840
9841 /*
9842 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9843 * Check to make sure only those flags are set.
9844 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9845 * flags cannot be set. Check for that condition also.
9846 */
9847 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9848 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9849 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009850 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009851 goto theend;
9852 }
9853
9854 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009855 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009856 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009857 if (subpatnum != FAIL)
9858 {
9859 if (flags & SP_SUBPAT)
9860 retval = subpatnum;
9861 else
9862 retval = pos.lnum;
9863 if (flags & SP_SETPCMARK)
9864 setpcmark();
9865 curwin->w_cursor = pos;
9866 if (match_pos != NULL)
9867 {
9868 /* Store the match cursor position */
9869 match_pos->lnum = pos.lnum;
9870 match_pos->col = pos.col + 1;
9871 }
9872 /* "/$" will put the cursor after the end of the line, may need to
9873 * correct that here */
9874 check_cursor();
9875 }
9876
9877 /* If 'n' flag is used: restore cursor position. */
9878 if (flags & SP_NOMOVE)
9879 curwin->w_cursor = save_cursor;
9880 else
9881 curwin->w_set_curswant = TRUE;
9882theend:
9883 p_ws = save_p_ws;
9884
9885 return retval;
9886}
9887
9888#ifdef FEAT_FLOAT
9889
9890/*
9891 * round() is not in C90, use ceil() or floor() instead.
9892 */
9893 float_T
9894vim_round(float_T f)
9895{
9896 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9897}
9898
9899/*
9900 * "round({float})" function
9901 */
9902 static void
9903f_round(typval_T *argvars, typval_T *rettv)
9904{
9905 float_T f = 0.0;
9906
9907 rettv->v_type = VAR_FLOAT;
9908 if (get_float_arg(argvars, &f) == OK)
9909 rettv->vval.v_float = vim_round(f);
9910 else
9911 rettv->vval.v_float = 0.0;
9912}
9913#endif
9914
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009915#ifdef FEAT_RUBY
9916/*
9917 * "rubyeval()" function
9918 */
9919 static void
9920f_rubyeval(typval_T *argvars, typval_T *rettv)
9921{
9922 char_u *str;
9923 char_u buf[NUMBUFLEN];
9924
9925 str = tv_get_string_buf(&argvars[0], buf);
9926 do_rubyeval(str, rettv);
9927}
9928#endif
9929
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009930/*
9931 * "screenattr()" function
9932 */
9933 static void
9934f_screenattr(typval_T *argvars, typval_T *rettv)
9935{
9936 int row;
9937 int col;
9938 int c;
9939
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009940 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9941 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009942 if (row < 0 || row >= screen_Rows
9943 || col < 0 || col >= screen_Columns)
9944 c = -1;
9945 else
9946 c = ScreenAttrs[LineOffset[row] + col];
9947 rettv->vval.v_number = c;
9948}
9949
9950/*
9951 * "screenchar()" function
9952 */
9953 static void
9954f_screenchar(typval_T *argvars, typval_T *rettv)
9955{
9956 int row;
9957 int col;
9958 int off;
9959 int c;
9960
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009961 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9962 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009963 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009964 c = -1;
9965 else
9966 {
9967 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009968 if (enc_utf8 && ScreenLinesUC[off] != 0)
9969 c = ScreenLinesUC[off];
9970 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009971 c = ScreenLines[off];
9972 }
9973 rettv->vval.v_number = c;
9974}
9975
9976/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009977 * "screenchars()" function
9978 */
9979 static void
9980f_screenchars(typval_T *argvars, typval_T *rettv)
9981{
9982 int row;
9983 int col;
9984 int off;
9985 int c;
9986 int i;
9987
9988 if (rettv_list_alloc(rettv) == FAIL)
9989 return;
9990 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9991 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9992 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9993 return;
9994
9995 off = LineOffset[row] + col;
9996 if (enc_utf8 && ScreenLinesUC[off] != 0)
9997 c = ScreenLinesUC[off];
9998 else
9999 c = ScreenLines[off];
10000 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10001
10002 if (enc_utf8)
10003
10004 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10005 list_append_number(rettv->vval.v_list,
10006 (varnumber_T)ScreenLinesC[i][off]);
10007}
10008
10009/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010010 * "screencol()" function
10011 *
10012 * First column is 1 to be consistent with virtcol().
10013 */
10014 static void
10015f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10016{
10017 rettv->vval.v_number = screen_screencol() + 1;
10018}
10019
10020/*
10021 * "screenrow()" function
10022 */
10023 static void
10024f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10025{
10026 rettv->vval.v_number = screen_screenrow() + 1;
10027}
10028
10029/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010030 * "screenstring()" function
10031 */
10032 static void
10033f_screenstring(typval_T *argvars, typval_T *rettv)
10034{
10035 int row;
10036 int col;
10037 int off;
10038 int c;
10039 int i;
10040 char_u buf[MB_MAXBYTES + 1];
10041 int buflen = 0;
10042
10043 rettv->vval.v_string = NULL;
10044 rettv->v_type = VAR_STRING;
10045
10046 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10047 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10048 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10049 return;
10050
10051 off = LineOffset[row] + col;
10052 if (enc_utf8 && ScreenLinesUC[off] != 0)
10053 c = ScreenLinesUC[off];
10054 else
10055 c = ScreenLines[off];
10056 buflen += mb_char2bytes(c, buf);
10057
10058 if (enc_utf8)
10059 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10060 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10061
10062 buf[buflen] = NUL;
10063 rettv->vval.v_string = vim_strsave(buf);
10064}
10065
10066/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010067 * "search()" function
10068 */
10069 static void
10070f_search(typval_T *argvars, typval_T *rettv)
10071{
10072 int flags = 0;
10073
10074 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10075}
10076
10077/*
10078 * "searchdecl()" function
10079 */
10080 static void
10081f_searchdecl(typval_T *argvars, typval_T *rettv)
10082{
10083 int locally = 1;
10084 int thisblock = 0;
10085 int error = FALSE;
10086 char_u *name;
10087
10088 rettv->vval.v_number = 1; /* default: FAIL */
10089
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010090 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010091 if (argvars[1].v_type != VAR_UNKNOWN)
10092 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010093 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010094 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010095 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010096 }
10097 if (!error && name != NULL)
10098 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10099 locally, thisblock, SEARCH_KEEP) == FAIL;
10100}
10101
10102/*
10103 * Used by searchpair() and searchpairpos()
10104 */
10105 static int
10106searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10107{
10108 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010109 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010110 int save_p_ws = p_ws;
10111 int dir;
10112 int flags = 0;
10113 char_u nbuf1[NUMBUFLEN];
10114 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010115 int retval = 0; /* default: FAIL */
10116 long lnum_stop = 0;
10117 long time_limit = 0;
10118
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010119 /* Get the three pattern arguments: start, middle, end. Will result in an
10120 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010121 spat = tv_get_string_chk(&argvars[0]);
10122 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10123 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010124 if (spat == NULL || mpat == NULL || epat == NULL)
10125 goto theend; /* type error */
10126
10127 /* Handle the optional fourth argument: flags */
10128 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10129 if (dir == 0)
10130 goto theend;
10131
10132 /* Don't accept SP_END or SP_SUBPAT.
10133 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10134 */
10135 if ((flags & (SP_END | SP_SUBPAT)) != 0
10136 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10137 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010138 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010139 goto theend;
10140 }
10141
10142 /* Using 'r' implies 'W', otherwise it doesn't work. */
10143 if (flags & SP_REPEAT)
10144 p_ws = FALSE;
10145
10146 /* Optional fifth argument: skip expression */
10147 if (argvars[3].v_type == VAR_UNKNOWN
10148 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010149 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010150 else
10151 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010152 skip = &argvars[4];
10153 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10154 && skip->v_type != VAR_STRING)
10155 {
10156 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010157 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010158 goto theend;
10159 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010160 if (argvars[5].v_type != VAR_UNKNOWN)
10161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010162 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010163 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010164 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010165 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010166 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010167 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010168#ifdef FEAT_RELTIME
10169 if (argvars[6].v_type != VAR_UNKNOWN)
10170 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010171 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010172 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010173 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010174 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010175 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010176 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010177 }
10178#endif
10179 }
10180 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010181
10182 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10183 match_pos, lnum_stop, time_limit);
10184
10185theend:
10186 p_ws = save_p_ws;
10187
10188 return retval;
10189}
10190
10191/*
10192 * "searchpair()" function
10193 */
10194 static void
10195f_searchpair(typval_T *argvars, typval_T *rettv)
10196{
10197 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10198}
10199
10200/*
10201 * "searchpairpos()" function
10202 */
10203 static void
10204f_searchpairpos(typval_T *argvars, typval_T *rettv)
10205{
10206 pos_T match_pos;
10207 int lnum = 0;
10208 int col = 0;
10209
10210 if (rettv_list_alloc(rettv) == FAIL)
10211 return;
10212
10213 if (searchpair_cmn(argvars, &match_pos) > 0)
10214 {
10215 lnum = match_pos.lnum;
10216 col = match_pos.col;
10217 }
10218
10219 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10220 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10221}
10222
10223/*
10224 * Search for a start/middle/end thing.
10225 * Used by searchpair(), see its documentation for the details.
10226 * Returns 0 or -1 for no match,
10227 */
10228 long
10229do_searchpair(
10230 char_u *spat, /* start pattern */
10231 char_u *mpat, /* middle pattern */
10232 char_u *epat, /* end pattern */
10233 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010234 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010235 int flags, /* SP_SETPCMARK and other SP_ values */
10236 pos_T *match_pos,
10237 linenr_T lnum_stop, /* stop at this line if not zero */
10238 long time_limit UNUSED) /* stop after this many msec */
10239{
10240 char_u *save_cpo;
10241 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10242 long retval = 0;
10243 pos_T pos;
10244 pos_T firstpos;
10245 pos_T foundpos;
10246 pos_T save_cursor;
10247 pos_T save_pos;
10248 int n;
10249 int r;
10250 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010251 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010252 int err;
10253 int options = SEARCH_KEEP;
10254 proftime_T tm;
10255
10256 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10257 save_cpo = p_cpo;
10258 p_cpo = empty_option;
10259
10260#ifdef FEAT_RELTIME
10261 /* Set the time limit, if there is one. */
10262 profile_setlimit(time_limit, &tm);
10263#endif
10264
10265 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10266 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +020010267 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
10268 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010269 if (pat2 == NULL || pat3 == NULL)
10270 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010271 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010272 if (*mpat == NUL)
10273 STRCPY(pat3, pat2);
10274 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010275 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010276 spat, epat, mpat);
10277 if (flags & SP_START)
10278 options |= SEARCH_START;
10279
Bram Moolenaar48570482017-10-30 21:48:41 +010010280 if (skip != NULL)
10281 {
10282 /* Empty string means to not use the skip expression. */
10283 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10284 use_skip = skip->vval.v_string != NULL
10285 && *skip->vval.v_string != NUL;
10286 }
10287
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010288 save_cursor = curwin->w_cursor;
10289 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010290 CLEAR_POS(&firstpos);
10291 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010292 pat = pat3;
10293 for (;;)
10294 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010295 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010296 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010297 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010298 /* didn't find it or found the first match again: FAIL */
10299 break;
10300
10301 if (firstpos.lnum == 0)
10302 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010303 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304 {
10305 /* Found the same position again. Can happen with a pattern that
10306 * has "\zs" at the end and searching backwards. Advance one
10307 * character and try again. */
10308 if (dir == BACKWARD)
10309 decl(&pos);
10310 else
10311 incl(&pos);
10312 }
10313 foundpos = pos;
10314
10315 /* clear the start flag to avoid getting stuck here */
10316 options &= ~SEARCH_START;
10317
10318 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010319 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010320 {
10321 save_pos = curwin->w_cursor;
10322 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010323 err = FALSE;
10324 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010325 curwin->w_cursor = save_pos;
10326 if (err)
10327 {
10328 /* Evaluating {skip} caused an error, break here. */
10329 curwin->w_cursor = save_cursor;
10330 retval = -1;
10331 break;
10332 }
10333 if (r)
10334 continue;
10335 }
10336
10337 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10338 {
10339 /* Found end when searching backwards or start when searching
10340 * forward: nested pair. */
10341 ++nest;
10342 pat = pat2; /* nested, don't search for middle */
10343 }
10344 else
10345 {
10346 /* Found end when searching forward or start when searching
10347 * backward: end of (nested) pair; or found middle in outer pair. */
10348 if (--nest == 1)
10349 pat = pat3; /* outer level, search for middle */
10350 }
10351
10352 if (nest == 0)
10353 {
10354 /* Found the match: return matchcount or line number. */
10355 if (flags & SP_RETCOUNT)
10356 ++retval;
10357 else
10358 retval = pos.lnum;
10359 if (flags & SP_SETPCMARK)
10360 setpcmark();
10361 curwin->w_cursor = pos;
10362 if (!(flags & SP_REPEAT))
10363 break;
10364 nest = 1; /* search for next unmatched */
10365 }
10366 }
10367
10368 if (match_pos != NULL)
10369 {
10370 /* Store the match cursor position */
10371 match_pos->lnum = curwin->w_cursor.lnum;
10372 match_pos->col = curwin->w_cursor.col + 1;
10373 }
10374
10375 /* If 'n' flag is used or search failed: restore cursor position. */
10376 if ((flags & SP_NOMOVE) || retval == 0)
10377 curwin->w_cursor = save_cursor;
10378
10379theend:
10380 vim_free(pat2);
10381 vim_free(pat3);
10382 if (p_cpo == empty_option)
10383 p_cpo = save_cpo;
10384 else
10385 /* Darn, evaluating the {skip} expression changed the value. */
10386 free_string_option(save_cpo);
10387
10388 return retval;
10389}
10390
10391/*
10392 * "searchpos()" function
10393 */
10394 static void
10395f_searchpos(typval_T *argvars, typval_T *rettv)
10396{
10397 pos_T match_pos;
10398 int lnum = 0;
10399 int col = 0;
10400 int n;
10401 int flags = 0;
10402
10403 if (rettv_list_alloc(rettv) == FAIL)
10404 return;
10405
10406 n = search_cmn(argvars, &match_pos, &flags);
10407 if (n > 0)
10408 {
10409 lnum = match_pos.lnum;
10410 col = match_pos.col;
10411 }
10412
10413 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10414 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10415 if (flags & SP_SUBPAT)
10416 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10417}
10418
10419 static void
10420f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10421{
10422#ifdef FEAT_CLIENTSERVER
10423 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010424 char_u *server = tv_get_string_chk(&argvars[0]);
10425 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010426
10427 rettv->vval.v_number = -1;
10428 if (server == NULL || reply == NULL)
10429 return;
10430 if (check_restricted() || check_secure())
10431 return;
10432# ifdef FEAT_X11
10433 if (check_connection() == FAIL)
10434 return;
10435# endif
10436
10437 if (serverSendReply(server, reply) < 0)
10438 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010439 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010440 return;
10441 }
10442 rettv->vval.v_number = 0;
10443#else
10444 rettv->vval.v_number = -1;
10445#endif
10446}
10447
10448 static void
10449f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10450{
10451 char_u *r = NULL;
10452
10453#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010454# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010455 r = serverGetVimNames();
10456# else
10457 make_connection();
10458 if (X_DISPLAY != NULL)
10459 r = serverGetVimNames(X_DISPLAY);
10460# endif
10461#endif
10462 rettv->v_type = VAR_STRING;
10463 rettv->vval.v_string = r;
10464}
10465
10466/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010467 * "setbufline()" function
10468 */
10469 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010470f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010471{
10472 linenr_T lnum;
10473 buf_T *buf;
10474
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010475 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010476 if (buf == NULL)
10477 rettv->vval.v_number = 1; /* FAIL */
10478 else
10479 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010480 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010481 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010482 }
10483}
10484
10485/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010486 * "setbufvar()" function
10487 */
10488 static void
10489f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10490{
10491 buf_T *buf;
10492 char_u *varname, *bufvarname;
10493 typval_T *varp;
10494 char_u nbuf[NUMBUFLEN];
10495
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010496 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010497 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010498 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10499 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010500 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010501 varp = &argvars[2];
10502
10503 if (buf != NULL && varname != NULL && varp != NULL)
10504 {
10505 if (*varname == '&')
10506 {
10507 long numval;
10508 char_u *strval;
10509 int error = FALSE;
10510 aco_save_T aco;
10511
10512 /* set curbuf to be our buf, temporarily */
10513 aucmd_prepbuf(&aco, buf);
10514
10515 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010516 numval = (long)tv_get_number_chk(varp, &error);
10517 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010518 if (!error && strval != NULL)
10519 set_option_value(varname, numval, strval, OPT_LOCAL);
10520
10521 /* reset notion of buffer */
10522 aucmd_restbuf(&aco);
10523 }
10524 else
10525 {
10526 buf_T *save_curbuf = curbuf;
10527
Bram Moolenaar964b3742019-05-24 18:54:09 +020010528 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010529 if (bufvarname != NULL)
10530 {
10531 curbuf = buf;
10532 STRCPY(bufvarname, "b:");
10533 STRCPY(bufvarname + 2, varname);
10534 set_var(bufvarname, varp, TRUE);
10535 vim_free(bufvarname);
10536 curbuf = save_curbuf;
10537 }
10538 }
10539 }
10540}
10541
10542 static void
10543f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10544{
10545 dict_T *d;
10546 dictitem_T *di;
10547 char_u *csearch;
10548
10549 if (argvars[0].v_type != VAR_DICT)
10550 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010551 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010552 return;
10553 }
10554
10555 if ((d = argvars[0].vval.v_dict) != NULL)
10556 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010557 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010558 if (csearch != NULL)
10559 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010560 if (enc_utf8)
10561 {
10562 int pcc[MAX_MCO];
10563 int c = utfc_ptr2char(csearch, pcc);
10564
10565 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10566 }
10567 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010568 set_last_csearch(PTR2CHAR(csearch),
10569 csearch, MB_PTR2LEN(csearch));
10570 }
10571
10572 di = dict_find(d, (char_u *)"forward", -1);
10573 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010574 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010575 ? FORWARD : BACKWARD);
10576
10577 di = dict_find(d, (char_u *)"until", -1);
10578 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010579 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010580 }
10581}
10582
10583/*
10584 * "setcmdpos()" function
10585 */
10586 static void
10587f_setcmdpos(typval_T *argvars, typval_T *rettv)
10588{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010589 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590
10591 if (pos >= 0)
10592 rettv->vval.v_number = set_cmdline_pos(pos);
10593}
10594
10595/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010596 * "setenv()" function
10597 */
10598 static void
10599f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10600{
10601 char_u namebuf[NUMBUFLEN];
10602 char_u valbuf[NUMBUFLEN];
10603 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10604
10605 if (argvars[1].v_type == VAR_SPECIAL
10606 && argvars[1].vval.v_number == VVAL_NULL)
10607 vim_unsetenv(name);
10608 else
10609 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10610}
10611
10612/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010613 * "setfperm({fname}, {mode})" function
10614 */
10615 static void
10616f_setfperm(typval_T *argvars, typval_T *rettv)
10617{
10618 char_u *fname;
10619 char_u modebuf[NUMBUFLEN];
10620 char_u *mode_str;
10621 int i;
10622 int mask;
10623 int mode = 0;
10624
10625 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010626 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010627 if (fname == NULL)
10628 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010629 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010630 if (mode_str == NULL)
10631 return;
10632 if (STRLEN(mode_str) != 9)
10633 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010634 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010635 return;
10636 }
10637
10638 mask = 1;
10639 for (i = 8; i >= 0; --i)
10640 {
10641 if (mode_str[i] != '-')
10642 mode |= mask;
10643 mask = mask << 1;
10644 }
10645 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10646}
10647
10648/*
10649 * "setline()" function
10650 */
10651 static void
10652f_setline(typval_T *argvars, typval_T *rettv)
10653{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010654 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010655
Bram Moolenaarca851592018-06-06 21:04:07 +020010656 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010657}
10658
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010659/*
10660 * Used by "setqflist()" and "setloclist()" functions
10661 */
10662 static void
10663set_qf_ll_list(
10664 win_T *wp UNUSED,
10665 typval_T *list_arg UNUSED,
10666 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010667 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668 typval_T *rettv)
10669{
10670#ifdef FEAT_QUICKFIX
10671 static char *e_invact = N_("E927: Invalid action: '%s'");
10672 char_u *act;
10673 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010674 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675#endif
10676
10677 rettv->vval.v_number = -1;
10678
10679#ifdef FEAT_QUICKFIX
10680 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010681 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010682 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010683 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010684 else
10685 {
10686 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010687 dict_T *d = NULL;
10688 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010689
10690 if (action_arg->v_type == VAR_STRING)
10691 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010692 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010693 if (act == NULL)
10694 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010695 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10696 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010697 action = *act;
10698 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010699 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010700 }
10701 else if (action_arg->v_type == VAR_UNKNOWN)
10702 action = ' ';
10703 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010704 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010705
Bram Moolenaard823fa92016-08-12 16:29:27 +020010706 if (action_arg->v_type != VAR_UNKNOWN
10707 && what_arg->v_type != VAR_UNKNOWN)
10708 {
10709 if (what_arg->v_type == VAR_DICT)
10710 d = what_arg->vval.v_dict;
10711 else
10712 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010713 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010714 valid_dict = FALSE;
10715 }
10716 }
10717
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010718 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010719 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010720 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10721 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010722 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010723 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 }
10725#endif
10726}
10727
10728/*
10729 * "setloclist()" function
10730 */
10731 static void
10732f_setloclist(typval_T *argvars, typval_T *rettv)
10733{
10734 win_T *win;
10735
10736 rettv->vval.v_number = -1;
10737
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010738 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010739 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010740 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010741}
10742
10743/*
10744 * "setmatches()" function
10745 */
10746 static void
10747f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10748{
10749#ifdef FEAT_SEARCH_EXTRA
10750 list_T *l;
10751 listitem_T *li;
10752 dict_T *d;
10753 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010010754 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010755
10756 rettv->vval.v_number = -1;
10757 if (argvars[0].v_type != VAR_LIST)
10758 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010759 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010760 return;
10761 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010010762 if (win == NULL)
10763 return;
10764
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010765 if ((l = argvars[0].vval.v_list) != NULL)
10766 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010767 /* To some extent make sure that we are dealing with a list from
10768 * "getmatches()". */
10769 li = l->lv_first;
10770 while (li != NULL)
10771 {
10772 if (li->li_tv.v_type != VAR_DICT
10773 || (d = li->li_tv.vval.v_dict) == NULL)
10774 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010775 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010776 return;
10777 }
10778 if (!(dict_find(d, (char_u *)"group", -1) != NULL
10779 && (dict_find(d, (char_u *)"pattern", -1) != NULL
10780 || dict_find(d, (char_u *)"pos1", -1) != NULL)
10781 && dict_find(d, (char_u *)"priority", -1) != NULL
10782 && dict_find(d, (char_u *)"id", -1) != NULL))
10783 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010784 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010785 return;
10786 }
10787 li = li->li_next;
10788 }
10789
Bram Moolenaaraff74912019-03-30 18:11:49 +010010790 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010791 li = l->lv_first;
10792 while (li != NULL)
10793 {
10794 int i = 0;
Bram Moolenaar54315892019-04-26 22:33:49 +020010795 char buf[30]; // use 30 to avoid compiler warning
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010796 dictitem_T *di;
10797 char_u *group;
10798 int priority;
10799 int id;
10800 char_u *conceal;
10801
10802 d = li->li_tv.vval.v_dict;
10803 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
10804 {
10805 if (s == NULL)
10806 {
10807 s = list_alloc();
10808 if (s == NULL)
10809 return;
10810 }
10811
10812 /* match from matchaddpos() */
10813 for (i = 1; i < 9; i++)
10814 {
10815 sprintf((char *)buf, (char *)"pos%d", i);
10816 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
10817 {
10818 if (di->di_tv.v_type != VAR_LIST)
10819 return;
10820
10821 list_append_tv(s, &di->di_tv);
10822 s->lv_refcount++;
10823 }
10824 else
10825 break;
10826 }
10827 }
10828
Bram Moolenaar8f667172018-12-14 15:38:31 +010010829 group = dict_get_string(d, (char_u *)"group", TRUE);
10830 priority = (int)dict_get_number(d, (char_u *)"priority");
10831 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010832 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010010833 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834 : NULL;
10835 if (i == 0)
10836 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010010837 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010010838 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010839 priority, id, NULL, conceal);
10840 }
10841 else
10842 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010010843 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010844 list_unref(s);
10845 s = NULL;
10846 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020010847 vim_free(group);
10848 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010849
10850 li = li->li_next;
10851 }
10852 rettv->vval.v_number = 0;
10853 }
10854#endif
10855}
10856
10857/*
10858 * "setpos()" function
10859 */
10860 static void
10861f_setpos(typval_T *argvars, typval_T *rettv)
10862{
10863 pos_T pos;
10864 int fnum;
10865 char_u *name;
10866 colnr_T curswant = -1;
10867
10868 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010869 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010870 if (name != NULL)
10871 {
10872 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10873 {
10874 if (--pos.col < 0)
10875 pos.col = 0;
10876 if (name[0] == '.' && name[1] == NUL)
10877 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010878 /* set cursor; "fnum" is ignored */
10879 curwin->w_cursor = pos;
10880 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010881 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010882 curwin->w_curswant = curswant - 1;
10883 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010884 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010885 check_cursor();
10886 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010887 }
10888 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10889 {
10890 /* set mark */
10891 if (setmark_pos(name[1], &pos, fnum) == OK)
10892 rettv->vval.v_number = 0;
10893 }
10894 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010895 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010896 }
10897 }
10898}
10899
10900/*
10901 * "setqflist()" function
10902 */
10903 static void
10904f_setqflist(typval_T *argvars, typval_T *rettv)
10905{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010906 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010907}
10908
10909/*
10910 * "setreg()" function
10911 */
10912 static void
10913f_setreg(typval_T *argvars, typval_T *rettv)
10914{
10915 int regname;
10916 char_u *strregname;
10917 char_u *stropt;
10918 char_u *strval;
10919 int append;
10920 char_u yank_type;
10921 long block_len;
10922
10923 block_len = -1;
10924 yank_type = MAUTO;
10925 append = FALSE;
10926
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010927 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928 rettv->vval.v_number = 1; /* FAIL is default */
10929
10930 if (strregname == NULL)
10931 return; /* type error; errmsg already given */
10932 regname = *strregname;
10933 if (regname == 0 || regname == '@')
10934 regname = '"';
10935
10936 if (argvars[2].v_type != VAR_UNKNOWN)
10937 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010938 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010939 if (stropt == NULL)
10940 return; /* type error */
10941 for (; *stropt != NUL; ++stropt)
10942 switch (*stropt)
10943 {
10944 case 'a': case 'A': /* append */
10945 append = TRUE;
10946 break;
10947 case 'v': case 'c': /* character-wise selection */
10948 yank_type = MCHAR;
10949 break;
10950 case 'V': case 'l': /* line-wise selection */
10951 yank_type = MLINE;
10952 break;
10953 case 'b': case Ctrl_V: /* block-wise selection */
10954 yank_type = MBLOCK;
10955 if (VIM_ISDIGIT(stropt[1]))
10956 {
10957 ++stropt;
10958 block_len = getdigits(&stropt) - 1;
10959 --stropt;
10960 }
10961 break;
10962 }
10963 }
10964
10965 if (argvars[1].v_type == VAR_LIST)
10966 {
10967 char_u **lstval;
10968 char_u **allocval;
10969 char_u buf[NUMBUFLEN];
10970 char_u **curval;
10971 char_u **curallocval;
10972 list_T *ll = argvars[1].vval.v_list;
10973 listitem_T *li;
10974 int len;
10975
10976 /* If the list is NULL handle like an empty list. */
10977 len = ll == NULL ? 0 : ll->lv_len;
10978
10979 /* First half: use for pointers to result lines; second half: use for
10980 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010981 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010982 if (lstval == NULL)
10983 return;
10984 curval = lstval;
10985 allocval = lstval + len + 2;
10986 curallocval = allocval;
10987
10988 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10989 li = li->li_next)
10990 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010991 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010992 if (strval == NULL)
10993 goto free_lstval;
10994 if (strval == buf)
10995 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010996 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997 * overwrite the string. */
10998 strval = vim_strsave(buf);
10999 if (strval == NULL)
11000 goto free_lstval;
11001 *curallocval++ = strval;
11002 }
11003 *curval++ = strval;
11004 }
11005 *curval++ = NULL;
11006
11007 write_reg_contents_lst(regname, lstval, -1,
11008 append, yank_type, block_len);
11009free_lstval:
11010 while (curallocval > allocval)
11011 vim_free(*--curallocval);
11012 vim_free(lstval);
11013 }
11014 else
11015 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011016 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011017 if (strval == NULL)
11018 return;
11019 write_reg_contents_ex(regname, strval, -1,
11020 append, yank_type, block_len);
11021 }
11022 rettv->vval.v_number = 0;
11023}
11024
11025/*
11026 * "settabvar()" function
11027 */
11028 static void
11029f_settabvar(typval_T *argvars, typval_T *rettv)
11030{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011031 tabpage_T *save_curtab;
11032 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011033 char_u *varname, *tabvarname;
11034 typval_T *varp;
11035
11036 rettv->vval.v_number = 0;
11037
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011038 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011039 return;
11040
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011041 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11042 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011043 varp = &argvars[2];
11044
Bram Moolenaar4033c552017-09-16 20:54:51 +020011045 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011046 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011047 save_curtab = curtab;
11048 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011049
Bram Moolenaar964b3742019-05-24 18:54:09 +020011050 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011051 if (tabvarname != NULL)
11052 {
11053 STRCPY(tabvarname, "t:");
11054 STRCPY(tabvarname + 2, varname);
11055 set_var(tabvarname, varp, TRUE);
11056 vim_free(tabvarname);
11057 }
11058
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 /* Restore current tabpage */
11060 if (valid_tabpage(save_curtab))
11061 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011062 }
11063}
11064
11065/*
11066 * "settabwinvar()" function
11067 */
11068 static void
11069f_settabwinvar(typval_T *argvars, typval_T *rettv)
11070{
11071 setwinvar(argvars, rettv, 1);
11072}
11073
11074/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011075 * "settagstack()" function
11076 */
11077 static void
11078f_settagstack(typval_T *argvars, typval_T *rettv)
11079{
11080 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11081 win_T *wp;
11082 dict_T *d;
11083 int action = 'r';
11084
11085 rettv->vval.v_number = -1;
11086
11087 // first argument: window number or id
11088 wp = find_win_by_nr_or_id(&argvars[0]);
11089 if (wp == NULL)
11090 return;
11091
11092 // second argument: dict with items to set in the tag stack
11093 if (argvars[1].v_type != VAR_DICT)
11094 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011095 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011096 return;
11097 }
11098 d = argvars[1].vval.v_dict;
11099 if (d == NULL)
11100 return;
11101
11102 // third argument: action - 'a' for append and 'r' for replace.
11103 // default is to replace the stack.
11104 if (argvars[2].v_type == VAR_UNKNOWN)
11105 action = 'r';
11106 else if (argvars[2].v_type == VAR_STRING)
11107 {
11108 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011109 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011110 if (actstr == NULL)
11111 return;
11112 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11113 action = *actstr;
11114 else
11115 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011116 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011117 return;
11118 }
11119 }
11120 else
11121 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011122 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011123 return;
11124 }
11125
11126 if (set_tagstack(wp, d, action) == OK)
11127 rettv->vval.v_number = 0;
11128}
11129
11130/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011131 * "setwinvar()" function
11132 */
11133 static void
11134f_setwinvar(typval_T *argvars, typval_T *rettv)
11135{
11136 setwinvar(argvars, rettv, 0);
11137}
11138
11139#ifdef FEAT_CRYPT
11140/*
11141 * "sha256({string})" function
11142 */
11143 static void
11144f_sha256(typval_T *argvars, typval_T *rettv)
11145{
11146 char_u *p;
11147
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011148 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011149 rettv->vval.v_string = vim_strsave(
11150 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11151 rettv->v_type = VAR_STRING;
11152}
11153#endif /* FEAT_CRYPT */
11154
11155/*
11156 * "shellescape({string})" function
11157 */
11158 static void
11159f_shellescape(typval_T *argvars, typval_T *rettv)
11160{
Bram Moolenaar20615522017-06-05 18:46:26 +020011161 int do_special = non_zero_arg(&argvars[1]);
11162
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011163 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011164 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011165 rettv->v_type = VAR_STRING;
11166}
11167
11168/*
11169 * shiftwidth() function
11170 */
11171 static void
11172f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11173{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011174 rettv->vval.v_number = 0;
11175
11176 if (argvars[0].v_type != VAR_UNKNOWN)
11177 {
11178 long col;
11179
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011180 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011181 if (col < 0)
11182 return; // type error; errmsg already given
11183#ifdef FEAT_VARTABS
11184 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11185 return;
11186#endif
11187 }
11188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011189 rettv->vval.v_number = get_sw_value(curbuf);
11190}
11191
11192/*
11193 * "simplify()" function
11194 */
11195 static void
11196f_simplify(typval_T *argvars, typval_T *rettv)
11197{
11198 char_u *p;
11199
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011200 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011201 rettv->vval.v_string = vim_strsave(p);
11202 simplify_filename(rettv->vval.v_string); /* simplify in place */
11203 rettv->v_type = VAR_STRING;
11204}
11205
11206#ifdef FEAT_FLOAT
11207/*
11208 * "sin()" function
11209 */
11210 static void
11211f_sin(typval_T *argvars, typval_T *rettv)
11212{
11213 float_T f = 0.0;
11214
11215 rettv->v_type = VAR_FLOAT;
11216 if (get_float_arg(argvars, &f) == OK)
11217 rettv->vval.v_float = sin(f);
11218 else
11219 rettv->vval.v_float = 0.0;
11220}
11221
11222/*
11223 * "sinh()" function
11224 */
11225 static void
11226f_sinh(typval_T *argvars, typval_T *rettv)
11227{
11228 float_T f = 0.0;
11229
11230 rettv->v_type = VAR_FLOAT;
11231 if (get_float_arg(argvars, &f) == OK)
11232 rettv->vval.v_float = sinh(f);
11233 else
11234 rettv->vval.v_float = 0.0;
11235}
11236#endif
11237
Bram Moolenaareae1b912019-05-09 15:12:55 +020011238static int item_compare(const void *s1, const void *s2);
11239static int item_compare2(const void *s1, const void *s2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240
11241/* struct used in the array that's given to qsort() */
11242typedef struct
11243{
11244 listitem_T *item;
11245 int idx;
11246} sortItem_T;
11247
11248/* struct storing information about current sort */
11249typedef struct
11250{
11251 int item_compare_ic;
11252 int item_compare_numeric;
11253 int item_compare_numbers;
11254#ifdef FEAT_FLOAT
11255 int item_compare_float;
11256#endif
11257 char_u *item_compare_func;
11258 partial_T *item_compare_partial;
11259 dict_T *item_compare_selfdict;
11260 int item_compare_func_err;
11261 int item_compare_keep_zero;
11262} sortinfo_T;
11263static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011264#define ITEM_COMPARE_FAIL 999
11265
11266/*
11267 * Compare functions for f_sort() and f_uniq() below.
11268 */
11269 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011270item_compare(const void *s1, const void *s2)
11271{
11272 sortItem_T *si1, *si2;
11273 typval_T *tv1, *tv2;
11274 char_u *p1, *p2;
11275 char_u *tofree1 = NULL, *tofree2 = NULL;
11276 int res;
11277 char_u numbuf1[NUMBUFLEN];
11278 char_u numbuf2[NUMBUFLEN];
11279
11280 si1 = (sortItem_T *)s1;
11281 si2 = (sortItem_T *)s2;
11282 tv1 = &si1->item->li_tv;
11283 tv2 = &si2->item->li_tv;
11284
11285 if (sortinfo->item_compare_numbers)
11286 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011287 varnumber_T v1 = tv_get_number(tv1);
11288 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011289
11290 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11291 }
11292
11293#ifdef FEAT_FLOAT
11294 if (sortinfo->item_compare_float)
11295 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011296 float_T v1 = tv_get_float(tv1);
11297 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011298
11299 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
11300 }
11301#endif
11302
11303 /* tv2string() puts quotes around a string and allocates memory. Don't do
11304 * that for string variables. Use a single quote when comparing with a
11305 * non-string to do what the docs promise. */
11306 if (tv1->v_type == VAR_STRING)
11307 {
11308 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11309 p1 = (char_u *)"'";
11310 else
11311 p1 = tv1->vval.v_string;
11312 }
11313 else
11314 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
11315 if (tv2->v_type == VAR_STRING)
11316 {
11317 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
11318 p2 = (char_u *)"'";
11319 else
11320 p2 = tv2->vval.v_string;
11321 }
11322 else
11323 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
11324 if (p1 == NULL)
11325 p1 = (char_u *)"";
11326 if (p2 == NULL)
11327 p2 = (char_u *)"";
11328 if (!sortinfo->item_compare_numeric)
11329 {
11330 if (sortinfo->item_compare_ic)
11331 res = STRICMP(p1, p2);
11332 else
11333 res = STRCMP(p1, p2);
11334 }
11335 else
11336 {
11337 double n1, n2;
11338 n1 = strtod((char *)p1, (char **)&p1);
11339 n2 = strtod((char *)p2, (char **)&p2);
11340 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
11341 }
11342
11343 /* When the result would be zero, compare the item indexes. Makes the
11344 * sort stable. */
11345 if (res == 0 && !sortinfo->item_compare_keep_zero)
11346 res = si1->idx > si2->idx ? 1 : -1;
11347
11348 vim_free(tofree1);
11349 vim_free(tofree2);
11350 return res;
11351}
11352
11353 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011354item_compare2(const void *s1, const void *s2)
11355{
11356 sortItem_T *si1, *si2;
11357 int res;
11358 typval_T rettv;
11359 typval_T argv[3];
11360 int dummy;
11361 char_u *func_name;
11362 partial_T *partial = sortinfo->item_compare_partial;
11363
11364 /* shortcut after failure in previous call; compare all items equal */
11365 if (sortinfo->item_compare_func_err)
11366 return 0;
11367
11368 si1 = (sortItem_T *)s1;
11369 si2 = (sortItem_T *)s2;
11370
11371 if (partial == NULL)
11372 func_name = sortinfo->item_compare_func;
11373 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011374 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011375
11376 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
11377 * in the copy without changing the original list items. */
11378 copy_tv(&si1->item->li_tv, &argv[0]);
11379 copy_tv(&si2->item->li_tv, &argv[1]);
11380
11381 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
Bram Moolenaar6ed88192019-05-11 18:37:44 +020011382 res = call_func(func_name, -1, &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011383 partial, sortinfo->item_compare_selfdict);
11384 clear_tv(&argv[0]);
11385 clear_tv(&argv[1]);
11386
11387 if (res == FAIL)
11388 res = ITEM_COMPARE_FAIL;
11389 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011390 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011391 if (sortinfo->item_compare_func_err)
11392 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
11393 clear_tv(&rettv);
11394
11395 /* When the result would be zero, compare the pointers themselves. Makes
11396 * the sort stable. */
11397 if (res == 0 && !sortinfo->item_compare_keep_zero)
11398 res = si1->idx > si2->idx ? 1 : -1;
11399
11400 return res;
11401}
11402
11403/*
11404 * "sort({list})" function
11405 */
11406 static void
11407do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
11408{
11409 list_T *l;
11410 listitem_T *li;
11411 sortItem_T *ptrs;
11412 sortinfo_T *old_sortinfo;
11413 sortinfo_T info;
11414 long len;
11415 long i;
11416
11417 /* Pointer to current info struct used in compare function. Save and
11418 * restore the current one for nested calls. */
11419 old_sortinfo = sortinfo;
11420 sortinfo = &info;
11421
11422 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011423 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011424 else
11425 {
11426 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010011427 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011428 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
11429 TRUE))
11430 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011431 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011432
11433 len = list_len(l);
11434 if (len <= 1)
11435 goto theend; /* short list sorts pretty quickly */
11436
11437 info.item_compare_ic = FALSE;
11438 info.item_compare_numeric = FALSE;
11439 info.item_compare_numbers = FALSE;
11440#ifdef FEAT_FLOAT
11441 info.item_compare_float = FALSE;
11442#endif
11443 info.item_compare_func = NULL;
11444 info.item_compare_partial = NULL;
11445 info.item_compare_selfdict = NULL;
11446 if (argvars[1].v_type != VAR_UNKNOWN)
11447 {
11448 /* optional second argument: {func} */
11449 if (argvars[1].v_type == VAR_FUNC)
11450 info.item_compare_func = argvars[1].vval.v_string;
11451 else if (argvars[1].v_type == VAR_PARTIAL)
11452 info.item_compare_partial = argvars[1].vval.v_partial;
11453 else
11454 {
11455 int error = FALSE;
11456
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011457 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011458 if (error)
11459 goto theend; /* type error; errmsg already given */
11460 if (i == 1)
11461 info.item_compare_ic = TRUE;
11462 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011463 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011464 else if (i != 0)
11465 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011466 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011467 goto theend;
11468 }
11469 if (info.item_compare_func != NULL)
11470 {
11471 if (*info.item_compare_func == NUL)
11472 {
11473 /* empty string means default sort */
11474 info.item_compare_func = NULL;
11475 }
11476 else if (STRCMP(info.item_compare_func, "n") == 0)
11477 {
11478 info.item_compare_func = NULL;
11479 info.item_compare_numeric = TRUE;
11480 }
11481 else if (STRCMP(info.item_compare_func, "N") == 0)
11482 {
11483 info.item_compare_func = NULL;
11484 info.item_compare_numbers = TRUE;
11485 }
11486#ifdef FEAT_FLOAT
11487 else if (STRCMP(info.item_compare_func, "f") == 0)
11488 {
11489 info.item_compare_func = NULL;
11490 info.item_compare_float = TRUE;
11491 }
11492#endif
11493 else if (STRCMP(info.item_compare_func, "i") == 0)
11494 {
11495 info.item_compare_func = NULL;
11496 info.item_compare_ic = TRUE;
11497 }
11498 }
11499 }
11500
11501 if (argvars[2].v_type != VAR_UNKNOWN)
11502 {
11503 /* optional third argument: {dict} */
11504 if (argvars[2].v_type != VAR_DICT)
11505 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011506 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011507 goto theend;
11508 }
11509 info.item_compare_selfdict = argvars[2].vval.v_dict;
11510 }
11511 }
11512
11513 /* Make an array with each entry pointing to an item in the List. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020011514 ptrs = ALLOC_MULT(sortItem_T, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011515 if (ptrs == NULL)
11516 goto theend;
11517
11518 i = 0;
11519 if (sort)
11520 {
11521 /* sort(): ptrs will be the list to sort */
11522 for (li = l->lv_first; li != NULL; li = li->li_next)
11523 {
11524 ptrs[i].item = li;
11525 ptrs[i].idx = i;
11526 ++i;
11527 }
11528
11529 info.item_compare_func_err = FALSE;
11530 info.item_compare_keep_zero = FALSE;
11531 /* test the compare function */
11532 if ((info.item_compare_func != NULL
11533 || info.item_compare_partial != NULL)
11534 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
11535 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011536 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011537 else
11538 {
11539 /* Sort the array with item pointers. */
11540 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
11541 info.item_compare_func == NULL
11542 && info.item_compare_partial == NULL
11543 ? item_compare : item_compare2);
11544
11545 if (!info.item_compare_func_err)
11546 {
11547 /* Clear the List and append the items in sorted order. */
11548 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
11549 l->lv_len = 0;
11550 for (i = 0; i < len; ++i)
11551 list_append(l, ptrs[i].item);
11552 }
11553 }
11554 }
11555 else
11556 {
11557 int (*item_compare_func_ptr)(const void *, const void *);
11558
11559 /* f_uniq(): ptrs will be a stack of items to remove */
11560 info.item_compare_func_err = FALSE;
11561 info.item_compare_keep_zero = TRUE;
11562 item_compare_func_ptr = info.item_compare_func != NULL
11563 || info.item_compare_partial != NULL
11564 ? item_compare2 : item_compare;
11565
11566 for (li = l->lv_first; li != NULL && li->li_next != NULL;
11567 li = li->li_next)
11568 {
11569 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
11570 == 0)
11571 ptrs[i++].item = li;
11572 if (info.item_compare_func_err)
11573 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011574 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011575 break;
11576 }
11577 }
11578
11579 if (!info.item_compare_func_err)
11580 {
11581 while (--i >= 0)
11582 {
11583 li = ptrs[i].item->li_next;
11584 ptrs[i].item->li_next = li->li_next;
11585 if (li->li_next != NULL)
11586 li->li_next->li_prev = ptrs[i].item;
11587 else
11588 l->lv_last = ptrs[i].item;
11589 list_fix_watch(l, li);
11590 listitem_free(li);
11591 l->lv_len--;
11592 }
11593 }
11594 }
11595
11596 vim_free(ptrs);
11597 }
11598theend:
11599 sortinfo = old_sortinfo;
11600}
11601
11602/*
11603 * "sort({list})" function
11604 */
11605 static void
11606f_sort(typval_T *argvars, typval_T *rettv)
11607{
11608 do_sort_uniq(argvars, rettv, TRUE);
11609}
11610
11611/*
11612 * "uniq({list})" function
11613 */
11614 static void
11615f_uniq(typval_T *argvars, typval_T *rettv)
11616{
11617 do_sort_uniq(argvars, rettv, FALSE);
11618}
11619
11620/*
11621 * "soundfold({word})" function
11622 */
11623 static void
11624f_soundfold(typval_T *argvars, typval_T *rettv)
11625{
11626 char_u *s;
11627
11628 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011629 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011630#ifdef FEAT_SPELL
11631 rettv->vval.v_string = eval_soundfold(s);
11632#else
11633 rettv->vval.v_string = vim_strsave(s);
11634#endif
11635}
11636
11637/*
11638 * "spellbadword()" function
11639 */
11640 static void
11641f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
11642{
11643 char_u *word = (char_u *)"";
11644 hlf_T attr = HLF_COUNT;
11645 int len = 0;
11646
11647 if (rettv_list_alloc(rettv) == FAIL)
11648 return;
11649
11650#ifdef FEAT_SPELL
11651 if (argvars[0].v_type == VAR_UNKNOWN)
11652 {
11653 /* Find the start and length of the badly spelled word. */
11654 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
11655 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011656 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011657 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010011658 curwin->w_set_curswant = TRUE;
11659 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011660 }
11661 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
11662 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011663 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011664 int capcol = -1;
11665
11666 if (str != NULL)
11667 {
11668 /* Check the argument for spelling. */
11669 while (*str != NUL)
11670 {
11671 len = spell_check(curwin, str, &attr, &capcol, FALSE);
11672 if (attr != HLF_COUNT)
11673 {
11674 word = str;
11675 break;
11676 }
11677 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020011678 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011679 }
11680 }
11681 }
11682#endif
11683
11684 list_append_string(rettv->vval.v_list, word, len);
11685 list_append_string(rettv->vval.v_list, (char_u *)(
11686 attr == HLF_SPB ? "bad" :
11687 attr == HLF_SPR ? "rare" :
11688 attr == HLF_SPL ? "local" :
11689 attr == HLF_SPC ? "caps" :
11690 ""), -1);
11691}
11692
11693/*
11694 * "spellsuggest()" function
11695 */
11696 static void
11697f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
11698{
11699#ifdef FEAT_SPELL
11700 char_u *str;
11701 int typeerr = FALSE;
11702 int maxcount;
11703 garray_T ga;
11704 int i;
11705 listitem_T *li;
11706 int need_capital = FALSE;
11707#endif
11708
11709 if (rettv_list_alloc(rettv) == FAIL)
11710 return;
11711
11712#ifdef FEAT_SPELL
11713 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
11714 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011715 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011716 if (argvars[1].v_type != VAR_UNKNOWN)
11717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011718 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011719 if (maxcount <= 0)
11720 return;
11721 if (argvars[2].v_type != VAR_UNKNOWN)
11722 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011723 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011724 if (typeerr)
11725 return;
11726 }
11727 }
11728 else
11729 maxcount = 25;
11730
11731 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
11732
11733 for (i = 0; i < ga.ga_len; ++i)
11734 {
11735 str = ((char_u **)ga.ga_data)[i];
11736
11737 li = listitem_alloc();
11738 if (li == NULL)
11739 vim_free(str);
11740 else
11741 {
11742 li->li_tv.v_type = VAR_STRING;
11743 li->li_tv.v_lock = 0;
11744 li->li_tv.vval.v_string = str;
11745 list_append(rettv->vval.v_list, li);
11746 }
11747 }
11748 ga_clear(&ga);
11749 }
11750#endif
11751}
11752
11753 static void
11754f_split(typval_T *argvars, typval_T *rettv)
11755{
11756 char_u *str;
11757 char_u *end;
11758 char_u *pat = NULL;
11759 regmatch_T regmatch;
11760 char_u patbuf[NUMBUFLEN];
11761 char_u *save_cpo;
11762 int match;
11763 colnr_T col = 0;
11764 int keepempty = FALSE;
11765 int typeerr = FALSE;
11766
11767 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11768 save_cpo = p_cpo;
11769 p_cpo = (char_u *)"";
11770
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011771 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011772 if (argvars[1].v_type != VAR_UNKNOWN)
11773 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011774 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011775 if (pat == NULL)
11776 typeerr = TRUE;
11777 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011778 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011779 }
11780 if (pat == NULL || *pat == NUL)
11781 pat = (char_u *)"[\\x01- ]\\+";
11782
11783 if (rettv_list_alloc(rettv) == FAIL)
11784 return;
11785 if (typeerr)
11786 return;
11787
11788 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11789 if (regmatch.regprog != NULL)
11790 {
11791 regmatch.rm_ic = FALSE;
11792 while (*str != NUL || keepempty)
11793 {
11794 if (*str == NUL)
11795 match = FALSE; /* empty item at the end */
11796 else
11797 match = vim_regexec_nl(&regmatch, str, col);
11798 if (match)
11799 end = regmatch.startp[0];
11800 else
11801 end = str + STRLEN(str);
11802 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11803 && *str != NUL && match && end < regmatch.endp[0]))
11804 {
11805 if (list_append_string(rettv->vval.v_list, str,
11806 (int)(end - str)) == FAIL)
11807 break;
11808 }
11809 if (!match)
11810 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010011811 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011812 if (regmatch.endp[0] > str)
11813 col = 0;
11814 else
Bram Moolenaar13505972019-01-24 15:04:48 +010011815 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011816 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011817 str = regmatch.endp[0];
11818 }
11819
11820 vim_regfree(regmatch.regprog);
11821 }
11822
11823 p_cpo = save_cpo;
11824}
11825
11826#ifdef FEAT_FLOAT
11827/*
11828 * "sqrt()" function
11829 */
11830 static void
11831f_sqrt(typval_T *argvars, typval_T *rettv)
11832{
11833 float_T f = 0.0;
11834
11835 rettv->v_type = VAR_FLOAT;
11836 if (get_float_arg(argvars, &f) == OK)
11837 rettv->vval.v_float = sqrt(f);
11838 else
11839 rettv->vval.v_float = 0.0;
11840}
11841
11842/*
11843 * "str2float()" function
11844 */
11845 static void
11846f_str2float(typval_T *argvars, typval_T *rettv)
11847{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011848 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011849 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011850
Bram Moolenaar08243d22017-01-10 16:12:29 +010011851 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011852 p = skipwhite(p + 1);
11853 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011854 if (isneg)
11855 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011856 rettv->v_type = VAR_FLOAT;
11857}
11858#endif
11859
11860/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020011861 * "str2list()" function
11862 */
11863 static void
11864f_str2list(typval_T *argvars, typval_T *rettv)
11865{
11866 char_u *p;
11867 int utf8 = FALSE;
11868
11869 if (rettv_list_alloc(rettv) == FAIL)
11870 return;
11871
11872 if (argvars[1].v_type != VAR_UNKNOWN)
11873 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
11874
11875 p = tv_get_string(&argvars[0]);
11876
11877 if (has_mbyte || utf8)
11878 {
11879 int (*ptr2len)(char_u *);
11880 int (*ptr2char)(char_u *);
11881
11882 if (utf8 || enc_utf8)
11883 {
11884 ptr2len = utf_ptr2len;
11885 ptr2char = utf_ptr2char;
11886 }
11887 else
11888 {
11889 ptr2len = mb_ptr2len;
11890 ptr2char = mb_ptr2char;
11891 }
11892
11893 for ( ; *p != NUL; p += (*ptr2len)(p))
11894 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
11895 }
11896 else
11897 for ( ; *p != NUL; ++p)
11898 list_append_number(rettv->vval.v_list, *p);
11899}
11900
11901/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011902 * "str2nr()" function
11903 */
11904 static void
11905f_str2nr(typval_T *argvars, typval_T *rettv)
11906{
11907 int base = 10;
11908 char_u *p;
11909 varnumber_T n;
11910 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011911 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011912
11913 if (argvars[1].v_type != VAR_UNKNOWN)
11914 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011915 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011916 if (base != 2 && base != 8 && base != 10 && base != 16)
11917 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011918 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011919 return;
11920 }
11921 }
11922
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011923 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011924 isneg = (*p == '-');
11925 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011926 p = skipwhite(p + 1);
11927 switch (base)
11928 {
11929 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11930 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11931 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11932 default: what = 0;
11933 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020011934 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
11935 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010011936 if (isneg)
11937 rettv->vval.v_number = -n;
11938 else
11939 rettv->vval.v_number = n;
11940
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011941}
11942
11943#ifdef HAVE_STRFTIME
11944/*
11945 * "strftime({format}[, {time}])" function
11946 */
11947 static void
11948f_strftime(typval_T *argvars, typval_T *rettv)
11949{
11950 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020011951 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011952 struct tm *curtime;
11953 time_t seconds;
11954 char_u *p;
11955
11956 rettv->v_type = VAR_STRING;
11957
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011958 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011959 if (argvars[1].v_type == VAR_UNKNOWN)
11960 seconds = time(NULL);
11961 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011962 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020011963 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011964 /* MSVC returns NULL for an invalid value of seconds. */
11965 if (curtime == NULL)
11966 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11967 else
11968 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011969 vimconv_T conv;
11970 char_u *enc;
11971
11972 conv.vc_type = CONV_NONE;
11973 enc = enc_locale();
11974 convert_setup(&conv, p_enc, enc);
11975 if (conv.vc_type != CONV_NONE)
11976 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011977 if (p != NULL)
11978 (void)strftime((char *)result_buf, sizeof(result_buf),
11979 (char *)p, curtime);
11980 else
11981 result_buf[0] = NUL;
11982
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011983 if (conv.vc_type != CONV_NONE)
11984 vim_free(p);
11985 convert_setup(&conv, enc, p_enc);
11986 if (conv.vc_type != CONV_NONE)
11987 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11988 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011989 rettv->vval.v_string = vim_strsave(result_buf);
11990
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011991 /* Release conversion descriptors */
11992 convert_setup(&conv, NULL, NULL);
11993 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011994 }
11995}
11996#endif
11997
11998/*
11999 * "strgetchar()" function
12000 */
12001 static void
12002f_strgetchar(typval_T *argvars, typval_T *rettv)
12003{
12004 char_u *str;
12005 int len;
12006 int error = FALSE;
12007 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012008 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012009
12010 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012011 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012012 if (str == NULL)
12013 return;
12014 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012015 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012016 if (error)
12017 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012018
Bram Moolenaar13505972019-01-24 15:04:48 +010012019 while (charidx >= 0 && byteidx < len)
12020 {
12021 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012022 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012023 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12024 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012025 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012026 --charidx;
12027 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012028 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012029}
12030
12031/*
12032 * "stridx()" function
12033 */
12034 static void
12035f_stridx(typval_T *argvars, typval_T *rettv)
12036{
12037 char_u buf[NUMBUFLEN];
12038 char_u *needle;
12039 char_u *haystack;
12040 char_u *save_haystack;
12041 char_u *pos;
12042 int start_idx;
12043
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012044 needle = tv_get_string_chk(&argvars[1]);
12045 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012046 rettv->vval.v_number = -1;
12047 if (needle == NULL || haystack == NULL)
12048 return; /* type error; errmsg already given */
12049
12050 if (argvars[2].v_type != VAR_UNKNOWN)
12051 {
12052 int error = FALSE;
12053
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012054 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012055 if (error || start_idx >= (int)STRLEN(haystack))
12056 return;
12057 if (start_idx >= 0)
12058 haystack += start_idx;
12059 }
12060
12061 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12062 if (pos != NULL)
12063 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12064}
12065
12066/*
12067 * "string()" function
12068 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012069 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012070f_string(typval_T *argvars, typval_T *rettv)
12071{
12072 char_u *tofree;
12073 char_u numbuf[NUMBUFLEN];
12074
12075 rettv->v_type = VAR_STRING;
12076 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12077 get_copyID());
12078 /* Make a copy if we have a value but it's not in allocated memory. */
12079 if (rettv->vval.v_string != NULL && tofree == NULL)
12080 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12081}
12082
12083/*
12084 * "strlen()" function
12085 */
12086 static void
12087f_strlen(typval_T *argvars, typval_T *rettv)
12088{
12089 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012090 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012091}
12092
12093/*
12094 * "strchars()" function
12095 */
12096 static void
12097f_strchars(typval_T *argvars, typval_T *rettv)
12098{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012099 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012100 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012101 varnumber_T len = 0;
12102 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012103
12104 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012105 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012106 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012107 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012108 else
12109 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012110 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12111 while (*s != NUL)
12112 {
12113 func_mb_ptr2char_adv(&s);
12114 ++len;
12115 }
12116 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012117 }
12118}
12119
12120/*
12121 * "strdisplaywidth()" function
12122 */
12123 static void
12124f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12125{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012126 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012127 int col = 0;
12128
12129 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012130 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012131
12132 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12133}
12134
12135/*
12136 * "strwidth()" function
12137 */
12138 static void
12139f_strwidth(typval_T *argvars, typval_T *rettv)
12140{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012141 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012142
Bram Moolenaar13505972019-01-24 15:04:48 +010012143 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012144}
12145
12146/*
12147 * "strcharpart()" function
12148 */
12149 static void
12150f_strcharpart(typval_T *argvars, typval_T *rettv)
12151{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012152 char_u *p;
12153 int nchar;
12154 int nbyte = 0;
12155 int charlen;
12156 int len = 0;
12157 int slen;
12158 int error = FALSE;
12159
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012160 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012161 slen = (int)STRLEN(p);
12162
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012163 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012164 if (!error)
12165 {
12166 if (nchar > 0)
12167 while (nchar > 0 && nbyte < slen)
12168 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012169 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012170 --nchar;
12171 }
12172 else
12173 nbyte = nchar;
12174 if (argvars[2].v_type != VAR_UNKNOWN)
12175 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012176 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012177 while (charlen > 0 && nbyte + len < slen)
12178 {
12179 int off = nbyte + len;
12180
12181 if (off < 0)
12182 len += 1;
12183 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012184 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012185 --charlen;
12186 }
12187 }
12188 else
12189 len = slen - nbyte; /* default: all bytes that are available. */
12190 }
12191
12192 /*
12193 * Only return the overlap between the specified part and the actual
12194 * string.
12195 */
12196 if (nbyte < 0)
12197 {
12198 len += nbyte;
12199 nbyte = 0;
12200 }
12201 else if (nbyte > slen)
12202 nbyte = slen;
12203 if (len < 0)
12204 len = 0;
12205 else if (nbyte + len > slen)
12206 len = slen - nbyte;
12207
12208 rettv->v_type = VAR_STRING;
12209 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012210}
12211
12212/*
12213 * "strpart()" function
12214 */
12215 static void
12216f_strpart(typval_T *argvars, typval_T *rettv)
12217{
12218 char_u *p;
12219 int n;
12220 int len;
12221 int slen;
12222 int error = FALSE;
12223
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012224 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012225 slen = (int)STRLEN(p);
12226
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012227 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012228 if (error)
12229 len = 0;
12230 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012231 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012232 else
12233 len = slen - n; /* default len: all bytes that are available. */
12234
12235 /*
12236 * Only return the overlap between the specified part and the actual
12237 * string.
12238 */
12239 if (n < 0)
12240 {
12241 len += n;
12242 n = 0;
12243 }
12244 else if (n > slen)
12245 n = slen;
12246 if (len < 0)
12247 len = 0;
12248 else if (n + len > slen)
12249 len = slen - n;
12250
12251 rettv->v_type = VAR_STRING;
12252 rettv->vval.v_string = vim_strnsave(p + n, len);
12253}
12254
12255/*
12256 * "strridx()" function
12257 */
12258 static void
12259f_strridx(typval_T *argvars, typval_T *rettv)
12260{
12261 char_u buf[NUMBUFLEN];
12262 char_u *needle;
12263 char_u *haystack;
12264 char_u *rest;
12265 char_u *lastmatch = NULL;
12266 int haystack_len, end_idx;
12267
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012268 needle = tv_get_string_chk(&argvars[1]);
12269 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012270
12271 rettv->vval.v_number = -1;
12272 if (needle == NULL || haystack == NULL)
12273 return; /* type error; errmsg already given */
12274
12275 haystack_len = (int)STRLEN(haystack);
12276 if (argvars[2].v_type != VAR_UNKNOWN)
12277 {
12278 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012279 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012280 if (end_idx < 0)
12281 return; /* can never find a match */
12282 }
12283 else
12284 end_idx = haystack_len;
12285
12286 if (*needle == NUL)
12287 {
12288 /* Empty string matches past the end. */
12289 lastmatch = haystack + end_idx;
12290 }
12291 else
12292 {
12293 for (rest = haystack; *rest != '\0'; ++rest)
12294 {
12295 rest = (char_u *)strstr((char *)rest, (char *)needle);
12296 if (rest == NULL || rest > haystack + end_idx)
12297 break;
12298 lastmatch = rest;
12299 }
12300 }
12301
12302 if (lastmatch == NULL)
12303 rettv->vval.v_number = -1;
12304 else
12305 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
12306}
12307
12308/*
12309 * "strtrans()" function
12310 */
12311 static void
12312f_strtrans(typval_T *argvars, typval_T *rettv)
12313{
12314 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012315 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012316}
12317
12318/*
12319 * "submatch()" function
12320 */
12321 static void
12322f_submatch(typval_T *argvars, typval_T *rettv)
12323{
12324 int error = FALSE;
12325 int no;
12326 int retList = 0;
12327
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012328 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012329 if (error)
12330 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012331 if (no < 0 || no >= NSUBEXP)
12332 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012333 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010012334 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020012335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012337 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012338 if (error)
12339 return;
12340
12341 if (retList == 0)
12342 {
12343 rettv->v_type = VAR_STRING;
12344 rettv->vval.v_string = reg_submatch(no);
12345 }
12346 else
12347 {
12348 rettv->v_type = VAR_LIST;
12349 rettv->vval.v_list = reg_submatch_list(no);
12350 }
12351}
12352
12353/*
12354 * "substitute()" function
12355 */
12356 static void
12357f_substitute(typval_T *argvars, typval_T *rettv)
12358{
12359 char_u patbuf[NUMBUFLEN];
12360 char_u subbuf[NUMBUFLEN];
12361 char_u flagsbuf[NUMBUFLEN];
12362
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012363 char_u *str = tv_get_string_chk(&argvars[0]);
12364 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012365 char_u *sub = NULL;
12366 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012367 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012368
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012369 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
12370 expr = &argvars[2];
12371 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012372 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012373
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012374 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012375 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
12376 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012377 rettv->vval.v_string = NULL;
12378 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020012379 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012380}
12381
12382/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012383 * "swapinfo(swap_filename)" function
12384 */
12385 static void
12386f_swapinfo(typval_T *argvars, typval_T *rettv)
12387{
12388 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012389 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020012390}
12391
12392/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020012393 * "swapname(expr)" function
12394 */
12395 static void
12396f_swapname(typval_T *argvars, typval_T *rettv)
12397{
12398 buf_T *buf;
12399
12400 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010012401 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020012402 if (buf == NULL || buf->b_ml.ml_mfp == NULL
12403 || buf->b_ml.ml_mfp->mf_fname == NULL)
12404 rettv->vval.v_string = NULL;
12405 else
12406 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
12407}
12408
12409/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012410 * "synID(lnum, col, trans)" function
12411 */
12412 static void
12413f_synID(typval_T *argvars UNUSED, typval_T *rettv)
12414{
12415 int id = 0;
12416#ifdef FEAT_SYN_HL
12417 linenr_T lnum;
12418 colnr_T col;
12419 int trans;
12420 int transerr = FALSE;
12421
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012422 lnum = tv_get_lnum(argvars); /* -1 on type error */
12423 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
12424 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012425
12426 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12427 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
12428 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
12429#endif
12430
12431 rettv->vval.v_number = id;
12432}
12433
12434/*
12435 * "synIDattr(id, what [, mode])" function
12436 */
12437 static void
12438f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
12439{
12440 char_u *p = NULL;
12441#ifdef FEAT_SYN_HL
12442 int id;
12443 char_u *what;
12444 char_u *mode;
12445 char_u modebuf[NUMBUFLEN];
12446 int modec;
12447
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012448 id = (int)tv_get_number(&argvars[0]);
12449 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012450 if (argvars[2].v_type != VAR_UNKNOWN)
12451 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012452 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012453 modec = TOLOWER_ASC(mode[0]);
12454 if (modec != 't' && modec != 'c' && modec != 'g')
12455 modec = 0; /* replace invalid with current */
12456 }
12457 else
12458 {
12459#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
12460 if (USE_24BIT)
12461 modec = 'g';
12462 else
12463#endif
12464 if (t_colors > 1)
12465 modec = 'c';
12466 else
12467 modec = 't';
12468 }
12469
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012470 switch (TOLOWER_ASC(what[0]))
12471 {
12472 case 'b':
12473 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
12474 p = highlight_color(id, what, modec);
12475 else /* bold */
12476 p = highlight_has_attr(id, HL_BOLD, modec);
12477 break;
12478
12479 case 'f': /* fg[#] or font */
12480 p = highlight_color(id, what, modec);
12481 break;
12482
12483 case 'i':
12484 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
12485 p = highlight_has_attr(id, HL_INVERSE, modec);
12486 else /* italic */
12487 p = highlight_has_attr(id, HL_ITALIC, modec);
12488 break;
12489
12490 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020012491 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012492 break;
12493
12494 case 'r': /* reverse */
12495 p = highlight_has_attr(id, HL_INVERSE, modec);
12496 break;
12497
12498 case 's':
12499 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
12500 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020012501 /* strikeout */
12502 else if (TOLOWER_ASC(what[1]) == 't' &&
12503 TOLOWER_ASC(what[2]) == 'r')
12504 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012505 else /* standout */
12506 p = highlight_has_attr(id, HL_STANDOUT, modec);
12507 break;
12508
12509 case 'u':
12510 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
12511 /* underline */
12512 p = highlight_has_attr(id, HL_UNDERLINE, modec);
12513 else
12514 /* undercurl */
12515 p = highlight_has_attr(id, HL_UNDERCURL, modec);
12516 break;
12517 }
12518
12519 if (p != NULL)
12520 p = vim_strsave(p);
12521#endif
12522 rettv->v_type = VAR_STRING;
12523 rettv->vval.v_string = p;
12524}
12525
12526/*
12527 * "synIDtrans(id)" function
12528 */
12529 static void
12530f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
12531{
12532 int id;
12533
12534#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012535 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012536
12537 if (id > 0)
12538 id = syn_get_final_id(id);
12539 else
12540#endif
12541 id = 0;
12542
12543 rettv->vval.v_number = id;
12544}
12545
12546/*
12547 * "synconcealed(lnum, col)" function
12548 */
12549 static void
12550f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
12551{
12552#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
12553 linenr_T lnum;
12554 colnr_T col;
12555 int syntax_flags = 0;
12556 int cchar;
12557 int matchid = 0;
12558 char_u str[NUMBUFLEN];
12559#endif
12560
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012561 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012562
12563#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012564 lnum = tv_get_lnum(argvars); /* -1 on type error */
12565 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012566
12567 vim_memset(str, NUL, sizeof(str));
12568
12569 if (rettv_list_alloc(rettv) != FAIL)
12570 {
12571 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12572 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12573 && curwin->w_p_cole > 0)
12574 {
12575 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
12576 syntax_flags = get_syntax_info(&matchid);
12577
12578 /* get the conceal character */
12579 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
12580 {
12581 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020012582 if (cchar == NUL && curwin->w_p_cole == 1)
12583 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012584 if (cchar != NUL)
12585 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012586 if (has_mbyte)
12587 (*mb_char2bytes)(cchar, str);
12588 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012589 str[0] = cchar;
12590 }
12591 }
12592 }
12593
12594 list_append_number(rettv->vval.v_list,
12595 (syntax_flags & HL_CONCEAL) != 0);
12596 /* -1 to auto-determine strlen */
12597 list_append_string(rettv->vval.v_list, str, -1);
12598 list_append_number(rettv->vval.v_list, matchid);
12599 }
12600#endif
12601}
12602
12603/*
12604 * "synstack(lnum, col)" function
12605 */
12606 static void
12607f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
12608{
12609#ifdef FEAT_SYN_HL
12610 linenr_T lnum;
12611 colnr_T col;
12612 int i;
12613 int id;
12614#endif
12615
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012616 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012617
12618#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012619 lnum = tv_get_lnum(argvars); /* -1 on type error */
12620 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012621
12622 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
12623 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
12624 && rettv_list_alloc(rettv) != FAIL)
12625 {
12626 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
12627 for (i = 0; ; ++i)
12628 {
12629 id = syn_get_stack_item(i);
12630 if (id < 0)
12631 break;
12632 if (list_append_number(rettv->vval.v_list, id) == FAIL)
12633 break;
12634 }
12635 }
12636#endif
12637}
12638
12639 static void
12640get_cmd_output_as_rettv(
12641 typval_T *argvars,
12642 typval_T *rettv,
12643 int retlist)
12644{
12645 char_u *res = NULL;
12646 char_u *p;
12647 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012648 int err = FALSE;
12649 FILE *fd;
12650 list_T *list = NULL;
12651 int flags = SHELL_SILENT;
12652
12653 rettv->v_type = VAR_STRING;
12654 rettv->vval.v_string = NULL;
12655 if (check_restricted() || check_secure())
12656 goto errret;
12657
12658 if (argvars[1].v_type != VAR_UNKNOWN)
12659 {
12660 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010012661 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012662 * command.
12663 */
12664 if ((infile = vim_tempname('i', TRUE)) == NULL)
12665 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012666 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012667 goto errret;
12668 }
12669
12670 fd = mch_fopen((char *)infile, WRITEBIN);
12671 if (fd == NULL)
12672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012673 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012674 goto errret;
12675 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010012676 if (argvars[1].v_type == VAR_NUMBER)
12677 {
12678 linenr_T lnum;
12679 buf_T *buf;
12680
12681 buf = buflist_findnr(argvars[1].vval.v_number);
12682 if (buf == NULL)
12683 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012684 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010012685 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010012686 goto errret;
12687 }
12688
12689 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
12690 {
12691 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
12692 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
12693 {
12694 err = TRUE;
12695 break;
12696 }
12697 if (putc(NL, fd) == EOF)
12698 {
12699 err = TRUE;
12700 break;
12701 }
12702 }
12703 }
12704 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012705 {
12706 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
12707 err = TRUE;
12708 }
12709 else
12710 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010012711 size_t len;
12712 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012713
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012714 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012715 if (p == NULL)
12716 {
12717 fclose(fd);
12718 goto errret; /* type error; errmsg already given */
12719 }
12720 len = STRLEN(p);
12721 if (len > 0 && fwrite(p, len, 1, fd) != 1)
12722 err = TRUE;
12723 }
12724 if (fclose(fd) != 0)
12725 err = TRUE;
12726 if (err)
12727 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012728 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012729 goto errret;
12730 }
12731 }
12732
12733 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
12734 * echoes typeahead, that messes up the display. */
12735 if (!msg_silent)
12736 flags += SHELL_COOKED;
12737
12738 if (retlist)
12739 {
12740 int len;
12741 listitem_T *li;
12742 char_u *s = NULL;
12743 char_u *start;
12744 char_u *end;
12745 int i;
12746
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012747 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012748 if (res == NULL)
12749 goto errret;
12750
12751 list = list_alloc();
12752 if (list == NULL)
12753 goto errret;
12754
12755 for (i = 0; i < len; ++i)
12756 {
12757 start = res + i;
12758 while (i < len && res[i] != NL)
12759 ++i;
12760 end = res + i;
12761
Bram Moolenaar964b3742019-05-24 18:54:09 +020012762 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012763 if (s == NULL)
12764 goto errret;
12765
12766 for (p = s; start < end; ++p, ++start)
12767 *p = *start == NUL ? NL : *start;
12768 *p = NUL;
12769
12770 li = listitem_alloc();
12771 if (li == NULL)
12772 {
12773 vim_free(s);
12774 goto errret;
12775 }
12776 li->li_tv.v_type = VAR_STRING;
12777 li->li_tv.v_lock = 0;
12778 li->li_tv.vval.v_string = s;
12779 list_append(list, li);
12780 }
12781
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012782 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012783 list = NULL;
12784 }
12785 else
12786 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012787 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010012788#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012789 /* translate <CR><NL> into <NL> */
12790 if (res != NULL)
12791 {
12792 char_u *s, *d;
12793
12794 d = res;
12795 for (s = res; *s; ++s)
12796 {
12797 if (s[0] == CAR && s[1] == NL)
12798 ++s;
12799 *d++ = *s;
12800 }
12801 *d = NUL;
12802 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012803#endif
12804 rettv->vval.v_string = res;
12805 res = NULL;
12806 }
12807
12808errret:
12809 if (infile != NULL)
12810 {
12811 mch_remove(infile);
12812 vim_free(infile);
12813 }
12814 if (res != NULL)
12815 vim_free(res);
12816 if (list != NULL)
12817 list_free(list);
12818}
12819
12820/*
12821 * "system()" function
12822 */
12823 static void
12824f_system(typval_T *argvars, typval_T *rettv)
12825{
12826 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12827}
12828
12829/*
12830 * "systemlist()" function
12831 */
12832 static void
12833f_systemlist(typval_T *argvars, typval_T *rettv)
12834{
12835 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12836}
12837
12838/*
12839 * "tabpagebuflist()" function
12840 */
12841 static void
12842f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12843{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012844 tabpage_T *tp;
12845 win_T *wp = NULL;
12846
12847 if (argvars[0].v_type == VAR_UNKNOWN)
12848 wp = firstwin;
12849 else
12850 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012851 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012852 if (tp != NULL)
12853 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12854 }
12855 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12856 {
12857 for (; wp != NULL; wp = wp->w_next)
12858 if (list_append_number(rettv->vval.v_list,
12859 wp->w_buffer->b_fnum) == FAIL)
12860 break;
12861 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012862}
12863
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012864/*
12865 * "tabpagenr()" function
12866 */
12867 static void
12868f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12869{
12870 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012871 char_u *arg;
12872
12873 if (argvars[0].v_type != VAR_UNKNOWN)
12874 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012875 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012876 nr = 0;
12877 if (arg != NULL)
12878 {
12879 if (STRCMP(arg, "$") == 0)
12880 nr = tabpage_index(NULL) - 1;
12881 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012882 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012883 }
12884 }
12885 else
12886 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012887 rettv->vval.v_number = nr;
12888}
12889
12890
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012891/*
12892 * Common code for tabpagewinnr() and winnr().
12893 */
12894 static int
12895get_winnr(tabpage_T *tp, typval_T *argvar)
12896{
12897 win_T *twin;
12898 int nr = 1;
12899 win_T *wp;
12900 char_u *arg;
12901
12902 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12903 if (argvar->v_type != VAR_UNKNOWN)
12904 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012905 int invalid_arg = FALSE;
12906
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012907 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012908 if (arg == NULL)
12909 nr = 0; /* type error; errmsg already given */
12910 else if (STRCMP(arg, "$") == 0)
12911 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12912 else if (STRCMP(arg, "#") == 0)
12913 {
12914 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12915 if (twin == NULL)
12916 nr = 0;
12917 }
12918 else
12919 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012920 long count;
12921 char_u *endp;
12922
12923 // Extract the window count (if specified). e.g. winnr('3j')
12924 count = strtol((char *)arg, (char **)&endp, 10);
12925 if (count <= 0)
12926 count = 1; // if count is not specified, default to 1
12927 if (endp != NULL && *endp != '\0')
12928 {
12929 if (STRCMP(endp, "j") == 0)
12930 twin = win_vert_neighbor(tp, twin, FALSE, count);
12931 else if (STRCMP(endp, "k") == 0)
12932 twin = win_vert_neighbor(tp, twin, TRUE, count);
12933 else if (STRCMP(endp, "h") == 0)
12934 twin = win_horz_neighbor(tp, twin, TRUE, count);
12935 else if (STRCMP(endp, "l") == 0)
12936 twin = win_horz_neighbor(tp, twin, FALSE, count);
12937 else
12938 invalid_arg = TRUE;
12939 }
12940 else
12941 invalid_arg = TRUE;
12942 }
12943
12944 if (invalid_arg)
12945 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012946 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012947 nr = 0;
12948 }
12949 }
12950
12951 if (nr > 0)
12952 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12953 wp != twin; wp = wp->w_next)
12954 {
12955 if (wp == NULL)
12956 {
12957 /* didn't find it in this tabpage */
12958 nr = 0;
12959 break;
12960 }
12961 ++nr;
12962 }
12963 return nr;
12964}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012965
12966/*
12967 * "tabpagewinnr()" function
12968 */
12969 static void
12970f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12971{
12972 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012973 tabpage_T *tp;
12974
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012975 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012976 if (tp == NULL)
12977 nr = 0;
12978 else
12979 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012980 rettv->vval.v_number = nr;
12981}
12982
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012983/*
12984 * "tagfiles()" function
12985 */
12986 static void
12987f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12988{
12989 char_u *fname;
12990 tagname_T tn;
12991 int first;
12992
12993 if (rettv_list_alloc(rettv) == FAIL)
12994 return;
12995 fname = alloc(MAXPATHL);
12996 if (fname == NULL)
12997 return;
12998
12999 for (first = TRUE; ; first = FALSE)
13000 if (get_tagfname(&tn, first, fname) == FAIL
13001 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13002 break;
13003 tagname_free(&tn);
13004 vim_free(fname);
13005}
13006
13007/*
13008 * "taglist()" function
13009 */
13010 static void
13011f_taglist(typval_T *argvars, typval_T *rettv)
13012{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013013 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013014 char_u *tag_pattern;
13015
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013016 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013017
13018 rettv->vval.v_number = FALSE;
13019 if (*tag_pattern == NUL)
13020 return;
13021
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013022 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013023 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013024 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013025 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013026}
13027
13028/*
13029 * "tempname()" function
13030 */
13031 static void
13032f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13033{
13034 static int x = 'A';
13035
13036 rettv->v_type = VAR_STRING;
13037 rettv->vval.v_string = vim_tempname(x, FALSE);
13038
13039 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13040 * names. Skip 'I' and 'O', they are used for shell redirection. */
13041 do
13042 {
13043 if (x == 'Z')
13044 x = '0';
13045 else if (x == '9')
13046 x = 'A';
13047 else
13048 {
13049#ifdef EBCDIC
13050 if (x == 'I')
13051 x = 'J';
13052 else if (x == 'R')
13053 x = 'S';
13054 else
13055#endif
13056 ++x;
13057 }
13058 } while (x == 'I' || x == 'O');
13059}
13060
13061#ifdef FEAT_FLOAT
13062/*
13063 * "tan()" function
13064 */
13065 static void
13066f_tan(typval_T *argvars, typval_T *rettv)
13067{
13068 float_T f = 0.0;
13069
13070 rettv->v_type = VAR_FLOAT;
13071 if (get_float_arg(argvars, &f) == OK)
13072 rettv->vval.v_float = tan(f);
13073 else
13074 rettv->vval.v_float = 0.0;
13075}
13076
13077/*
13078 * "tanh()" function
13079 */
13080 static void
13081f_tanh(typval_T *argvars, typval_T *rettv)
13082{
13083 float_T f = 0.0;
13084
13085 rettv->v_type = VAR_FLOAT;
13086 if (get_float_arg(argvars, &f) == OK)
13087 rettv->vval.v_float = tanh(f);
13088 else
13089 rettv->vval.v_float = 0.0;
13090}
13091#endif
13092
13093/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013094 * Get a callback from "arg". It can be a Funcref or a function name.
13095 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013096 * "cb_name" is not allocated.
13097 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013098 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013099 callback_T
13100get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013101{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013102 callback_T res;
13103
13104 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013105 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
13106 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013107 res.cb_partial = arg->vval.v_partial;
13108 ++res.cb_partial->pt_refcount;
13109 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013110 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013111 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013113 res.cb_partial = NULL;
13114 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
13115 {
13116 // Note that we don't make a copy of the string.
13117 res.cb_name = arg->vval.v_string;
13118 func_ref(res.cb_name);
13119 }
13120 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
13121 {
13122 res.cb_name = (char_u *)"";
13123 }
13124 else
13125 {
13126 emsg(_("E921: Invalid callback argument"));
13127 res.cb_name = NULL;
13128 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013129 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013130 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131}
13132
13133/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013134 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013135 */
13136 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013137put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013138{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013139 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013140 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013141 tv->v_type = VAR_PARTIAL;
13142 tv->vval.v_partial = cb->cb_partial;
13143 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013144 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013145 else
13146 {
13147 tv->v_type = VAR_FUNC;
13148 tv->vval.v_string = vim_strsave(cb->cb_name);
13149 func_ref(cb->cb_name);
13150 }
13151}
13152
13153/*
13154 * Make a copy of "src" into "dest", allocating the function name if needed,
13155 * without incrementing the refcount.
13156 */
13157 void
13158set_callback(callback_T *dest, callback_T *src)
13159{
13160 if (src->cb_partial == NULL)
13161 {
13162 // just a function name, make a copy
13163 dest->cb_name = vim_strsave(src->cb_name);
13164 dest->cb_free_name = TRUE;
13165 }
13166 else
13167 {
13168 // cb_name is a pointer into cb_partial
13169 dest->cb_name = src->cb_name;
13170 dest->cb_free_name = FALSE;
13171 }
13172 dest->cb_partial = src->cb_partial;
13173}
13174
13175/*
13176 * Unref/free "callback" returned by get_callback() or set_callback().
13177 */
13178 void
13179free_callback(callback_T *callback)
13180{
13181 if (callback->cb_partial != NULL)
13182 {
13183 partial_unref(callback->cb_partial);
13184 callback->cb_partial = NULL;
13185 }
13186 else if (callback->cb_name != NULL)
13187 func_unref(callback->cb_name);
13188 if (callback->cb_free_name)
13189 {
13190 vim_free(callback->cb_name);
13191 callback->cb_free_name = FALSE;
13192 }
13193 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013194}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013195
13196#ifdef FEAT_TIMERS
13197/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013198 * "timer_info([timer])" function
13199 */
13200 static void
13201f_timer_info(typval_T *argvars, typval_T *rettv)
13202{
13203 timer_T *timer = NULL;
13204
13205 if (rettv_list_alloc(rettv) != OK)
13206 return;
13207 if (argvars[0].v_type != VAR_UNKNOWN)
13208 {
13209 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013210 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013211 else
13212 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013213 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020013214 if (timer != NULL)
13215 add_timer_info(rettv, timer);
13216 }
13217 }
13218 else
13219 add_timer_info_all(rettv);
13220}
13221
13222/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013223 * "timer_pause(timer, paused)" function
13224 */
13225 static void
13226f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
13227{
13228 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013229 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013230
13231 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013232 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013233 else
13234 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013235 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013236 if (timer != NULL)
13237 timer->tr_paused = paused;
13238 }
13239}
13240
13241/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013242 * "timer_start(time, callback [, options])" function
13243 */
13244 static void
13245f_timer_start(typval_T *argvars, typval_T *rettv)
13246{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013247 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020013248 timer_T *timer;
13249 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013250 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020013251 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013252
Bram Moolenaar75537a92016-09-05 22:45:28 +020013253 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013254 if (check_secure())
13255 return;
13256 if (argvars[2].v_type != VAR_UNKNOWN)
13257 {
13258 if (argvars[2].v_type != VAR_DICT
13259 || (dict = argvars[2].vval.v_dict) == NULL)
13260 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013261 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013262 return;
13263 }
13264 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013265 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013266 }
13267
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013268 callback = get_callback(&argvars[1]);
13269 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020013270 return;
13271
13272 timer = create_timer(msec, repeat);
13273 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013274 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013275 else
13276 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020013277 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020013278 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013279 }
13280}
13281
13282/*
13283 * "timer_stop(timer)" function
13284 */
13285 static void
13286f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
13287{
13288 timer_T *timer;
13289
13290 if (argvars[0].v_type != VAR_NUMBER)
13291 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013292 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013293 return;
13294 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013295 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013296 if (timer != NULL)
13297 stop_timer(timer);
13298}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020013299
13300/*
13301 * "timer_stopall()" function
13302 */
13303 static void
13304f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13305{
13306 stop_all_timers();
13307}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013308#endif
13309
13310/*
13311 * "tolower(string)" function
13312 */
13313 static void
13314f_tolower(typval_T *argvars, typval_T *rettv)
13315{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013316 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013317 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013318}
13319
13320/*
13321 * "toupper(string)" function
13322 */
13323 static void
13324f_toupper(typval_T *argvars, typval_T *rettv)
13325{
13326 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013327 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013328}
13329
13330/*
13331 * "tr(string, fromstr, tostr)" function
13332 */
13333 static void
13334f_tr(typval_T *argvars, typval_T *rettv)
13335{
13336 char_u *in_str;
13337 char_u *fromstr;
13338 char_u *tostr;
13339 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013340 int inlen;
13341 int fromlen;
13342 int tolen;
13343 int idx;
13344 char_u *cpstr;
13345 int cplen;
13346 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013347 char_u buf[NUMBUFLEN];
13348 char_u buf2[NUMBUFLEN];
13349 garray_T ga;
13350
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013351 in_str = tv_get_string(&argvars[0]);
13352 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
13353 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013354
13355 /* Default return value: empty string. */
13356 rettv->v_type = VAR_STRING;
13357 rettv->vval.v_string = NULL;
13358 if (fromstr == NULL || tostr == NULL)
13359 return; /* type error; errmsg already given */
13360 ga_init2(&ga, (int)sizeof(char), 80);
13361
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013362 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013363 /* not multi-byte: fromstr and tostr must be the same length */
13364 if (STRLEN(fromstr) != STRLEN(tostr))
13365 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013366error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013367 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013368 ga_clear(&ga);
13369 return;
13370 }
13371
13372 /* fromstr and tostr have to contain the same number of chars */
13373 while (*in_str != NUL)
13374 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013375 if (has_mbyte)
13376 {
13377 inlen = (*mb_ptr2len)(in_str);
13378 cpstr = in_str;
13379 cplen = inlen;
13380 idx = 0;
13381 for (p = fromstr; *p != NUL; p += fromlen)
13382 {
13383 fromlen = (*mb_ptr2len)(p);
13384 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
13385 {
13386 for (p = tostr; *p != NUL; p += tolen)
13387 {
13388 tolen = (*mb_ptr2len)(p);
13389 if (idx-- == 0)
13390 {
13391 cplen = tolen;
13392 cpstr = p;
13393 break;
13394 }
13395 }
13396 if (*p == NUL) /* tostr is shorter than fromstr */
13397 goto error;
13398 break;
13399 }
13400 ++idx;
13401 }
13402
13403 if (first && cpstr == in_str)
13404 {
13405 /* Check that fromstr and tostr have the same number of
13406 * (multi-byte) characters. Done only once when a character
13407 * of in_str doesn't appear in fromstr. */
13408 first = FALSE;
13409 for (p = tostr; *p != NUL; p += tolen)
13410 {
13411 tolen = (*mb_ptr2len)(p);
13412 --idx;
13413 }
13414 if (idx != 0)
13415 goto error;
13416 }
13417
13418 (void)ga_grow(&ga, cplen);
13419 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
13420 ga.ga_len += cplen;
13421
13422 in_str += inlen;
13423 }
13424 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013425 {
13426 /* When not using multi-byte chars we can do it faster. */
13427 p = vim_strchr(fromstr, *in_str);
13428 if (p != NULL)
13429 ga_append(&ga, tostr[p - fromstr]);
13430 else
13431 ga_append(&ga, *in_str);
13432 ++in_str;
13433 }
13434 }
13435
13436 /* add a terminating NUL */
13437 (void)ga_grow(&ga, 1);
13438 ga_append(&ga, NUL);
13439
13440 rettv->vval.v_string = ga.ga_data;
13441}
13442
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013443/*
13444 * "trim({expr})" function
13445 */
13446 static void
13447f_trim(typval_T *argvars, typval_T *rettv)
13448{
13449 char_u buf1[NUMBUFLEN];
13450 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013451 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013452 char_u *mask = NULL;
13453 char_u *tail;
13454 char_u *prev;
13455 char_u *p;
13456 int c1;
13457
13458 rettv->v_type = VAR_STRING;
13459 if (head == NULL)
13460 {
13461 rettv->vval.v_string = NULL;
13462 return;
13463 }
13464
13465 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013466 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010013467
13468 while (*head != NUL)
13469 {
13470 c1 = PTR2CHAR(head);
13471 if (mask == NULL)
13472 {
13473 if (c1 > ' ' && c1 != 0xa0)
13474 break;
13475 }
13476 else
13477 {
13478 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13479 if (c1 == PTR2CHAR(p))
13480 break;
13481 if (*p == NUL)
13482 break;
13483 }
13484 MB_PTR_ADV(head);
13485 }
13486
13487 for (tail = head + STRLEN(head); tail > head; tail = prev)
13488 {
13489 prev = tail;
13490 MB_PTR_BACK(head, prev);
13491 c1 = PTR2CHAR(prev);
13492 if (mask == NULL)
13493 {
13494 if (c1 > ' ' && c1 != 0xa0)
13495 break;
13496 }
13497 else
13498 {
13499 for (p = mask; *p != NUL; MB_PTR_ADV(p))
13500 if (c1 == PTR2CHAR(p))
13501 break;
13502 if (*p == NUL)
13503 break;
13504 }
13505 }
13506 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
13507}
13508
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013509#ifdef FEAT_FLOAT
13510/*
13511 * "trunc({float})" function
13512 */
13513 static void
13514f_trunc(typval_T *argvars, typval_T *rettv)
13515{
13516 float_T f = 0.0;
13517
13518 rettv->v_type = VAR_FLOAT;
13519 if (get_float_arg(argvars, &f) == OK)
13520 /* trunc() is not in C90, use floor() or ceil() instead. */
13521 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
13522 else
13523 rettv->vval.v_float = 0.0;
13524}
13525#endif
13526
13527/*
13528 * "type(expr)" function
13529 */
13530 static void
13531f_type(typval_T *argvars, typval_T *rettv)
13532{
13533 int n = -1;
13534
13535 switch (argvars[0].v_type)
13536 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020013537 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
13538 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013539 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020013540 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
13541 case VAR_LIST: n = VAR_TYPE_LIST; break;
13542 case VAR_DICT: n = VAR_TYPE_DICT; break;
13543 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013544 case VAR_SPECIAL:
13545 if (argvars[0].vval.v_number == VVAL_FALSE
13546 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020013547 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013548 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020013549 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013550 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020013551 case VAR_JOB: n = VAR_TYPE_JOB; break;
13552 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013553 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013554 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010013555 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013556 n = -1;
13557 break;
13558 }
13559 rettv->vval.v_number = n;
13560}
13561
13562/*
13563 * "undofile(name)" function
13564 */
13565 static void
13566f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
13567{
13568 rettv->v_type = VAR_STRING;
13569#ifdef FEAT_PERSISTENT_UNDO
13570 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013571 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013572
13573 if (*fname == NUL)
13574 {
13575 /* If there is no file name there will be no undo file. */
13576 rettv->vval.v_string = NULL;
13577 }
13578 else
13579 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020013580 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013581
13582 if (ffname != NULL)
13583 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
13584 vim_free(ffname);
13585 }
13586 }
13587#else
13588 rettv->vval.v_string = NULL;
13589#endif
13590}
13591
13592/*
13593 * "undotree()" function
13594 */
13595 static void
13596f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
13597{
13598 if (rettv_dict_alloc(rettv) == OK)
13599 {
13600 dict_T *dict = rettv->vval.v_dict;
13601 list_T *list;
13602
Bram Moolenaare0be1672018-07-08 16:50:37 +020013603 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
13604 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
13605 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
13606 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
13607 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
13608 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013609
13610 list = list_alloc();
13611 if (list != NULL)
13612 {
13613 u_eval_tree(curbuf->b_u_oldhead, list);
13614 dict_add_list(dict, "entries", list);
13615 }
13616 }
13617}
13618
13619/*
13620 * "values(dict)" function
13621 */
13622 static void
13623f_values(typval_T *argvars, typval_T *rettv)
13624{
13625 dict_list(argvars, rettv, 1);
13626}
13627
13628/*
13629 * "virtcol(string)" function
13630 */
13631 static void
13632f_virtcol(typval_T *argvars, typval_T *rettv)
13633{
13634 colnr_T vcol = 0;
13635 pos_T *fp;
13636 int fnum = curbuf->b_fnum;
13637
13638 fp = var2fpos(&argvars[0], FALSE, &fnum);
13639 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
13640 && fnum == curbuf->b_fnum)
13641 {
13642 getvvcol(curwin, fp, NULL, NULL, &vcol);
13643 ++vcol;
13644 }
13645
13646 rettv->vval.v_number = vcol;
13647}
13648
13649/*
13650 * "visualmode()" function
13651 */
13652 static void
13653f_visualmode(typval_T *argvars, typval_T *rettv)
13654{
13655 char_u str[2];
13656
13657 rettv->v_type = VAR_STRING;
13658 str[0] = curbuf->b_visual_mode_eval;
13659 str[1] = NUL;
13660 rettv->vval.v_string = vim_strsave(str);
13661
13662 /* A non-zero number or non-empty string argument: reset mode. */
13663 if (non_zero_arg(&argvars[0]))
13664 curbuf->b_visual_mode_eval = NUL;
13665}
13666
13667/*
13668 * "wildmenumode()" function
13669 */
13670 static void
13671f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13672{
13673#ifdef FEAT_WILDMENU
13674 if (wild_menu_showing)
13675 rettv->vval.v_number = 1;
13676#endif
13677}
13678
13679/*
13680 * "winbufnr(nr)" function
13681 */
13682 static void
13683f_winbufnr(typval_T *argvars, typval_T *rettv)
13684{
13685 win_T *wp;
13686
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013687 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013688 if (wp == NULL)
13689 rettv->vval.v_number = -1;
13690 else
13691 rettv->vval.v_number = wp->w_buffer->b_fnum;
13692}
13693
13694/*
13695 * "wincol()" function
13696 */
13697 static void
13698f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
13699{
13700 validate_cursor();
13701 rettv->vval.v_number = curwin->w_wcol + 1;
13702}
13703
13704/*
13705 * "winheight(nr)" function
13706 */
13707 static void
13708f_winheight(typval_T *argvars, typval_T *rettv)
13709{
13710 win_T *wp;
13711
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013712 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013713 if (wp == NULL)
13714 rettv->vval.v_number = -1;
13715 else
13716 rettv->vval.v_number = wp->w_height;
13717}
13718
13719/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013720 * "winlayout()" function
13721 */
13722 static void
13723f_winlayout(typval_T *argvars, typval_T *rettv)
13724{
13725 tabpage_T *tp;
13726
13727 if (rettv_list_alloc(rettv) != OK)
13728 return;
13729
13730 if (argvars[0].v_type == VAR_UNKNOWN)
13731 tp = curtab;
13732 else
13733 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013734 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020013735 if (tp == NULL)
13736 return;
13737 }
13738
13739 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
13740}
13741
13742/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013743 * "winline()" function
13744 */
13745 static void
13746f_winline(typval_T *argvars UNUSED, typval_T *rettv)
13747{
13748 validate_cursor();
13749 rettv->vval.v_number = curwin->w_wrow + 1;
13750}
13751
13752/*
13753 * "winnr()" function
13754 */
13755 static void
13756f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
13757{
13758 int nr = 1;
13759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013760 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013761 rettv->vval.v_number = nr;
13762}
13763
13764/*
13765 * "winrestcmd()" function
13766 */
13767 static void
13768f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13769{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013770 win_T *wp;
13771 int winnr = 1;
13772 garray_T ga;
13773 char_u buf[50];
13774
13775 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013776 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013777 {
13778 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13779 ga_concat(&ga, buf);
13780 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13781 ga_concat(&ga, buf);
13782 ++winnr;
13783 }
13784 ga_append(&ga, NUL);
13785
13786 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013787 rettv->v_type = VAR_STRING;
13788}
13789
13790/*
13791 * "winrestview()" function
13792 */
13793 static void
13794f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13795{
13796 dict_T *dict;
13797
13798 if (argvars[0].v_type != VAR_DICT
13799 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013800 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013801 else
13802 {
13803 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013804 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013805 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013806 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013807 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013808 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013809 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13810 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010013811 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013812 curwin->w_set_curswant = FALSE;
13813 }
13814
13815 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013816 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013817#ifdef FEAT_DIFF
13818 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013819 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013820#endif
13821 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013822 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013823 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013824 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013825
13826 check_cursor();
13827 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013828 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013829 changed_window_setting();
13830
13831 if (curwin->w_topline <= 0)
13832 curwin->w_topline = 1;
13833 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13834 curwin->w_topline = curbuf->b_ml.ml_line_count;
13835#ifdef FEAT_DIFF
13836 check_topfill(curwin, TRUE);
13837#endif
13838 }
13839}
13840
13841/*
13842 * "winsaveview()" function
13843 */
13844 static void
13845f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13846{
13847 dict_T *dict;
13848
13849 if (rettv_dict_alloc(rettv) == FAIL)
13850 return;
13851 dict = rettv->vval.v_dict;
13852
Bram Moolenaare0be1672018-07-08 16:50:37 +020013853 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13854 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020013855 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013856 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013857 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013858
Bram Moolenaare0be1672018-07-08 16:50:37 +020013859 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013860#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013861 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013862#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013863 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13864 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013865}
13866
13867/*
13868 * "winwidth(nr)" function
13869 */
13870 static void
13871f_winwidth(typval_T *argvars, typval_T *rettv)
13872{
13873 win_T *wp;
13874
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013875 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013876 if (wp == NULL)
13877 rettv->vval.v_number = -1;
13878 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013879 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013880}
13881
13882/*
13883 * "wordcount()" function
13884 */
13885 static void
13886f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13887{
13888 if (rettv_dict_alloc(rettv) == FAIL)
13889 return;
13890 cursor_pos_info(rettv->vval.v_dict);
13891}
13892
13893/*
13894 * "writefile()" function
13895 */
13896 static void
13897f_writefile(typval_T *argvars, typval_T *rettv)
13898{
13899 int binary = FALSE;
13900 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013901#ifdef HAVE_FSYNC
13902 int do_fsync = p_fs;
13903#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013904 char_u *fname;
13905 FILE *fd;
13906 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013907 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013908 list_T *list = NULL;
13909 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013910
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013911 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010013912 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013913 return;
13914
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013915 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013916 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013917 list = argvars[0].vval.v_list;
13918 if (list == NULL)
13919 return;
13920 for (li = list->lv_first; li != NULL; li = li->li_next)
13921 if (tv_get_string_chk(&li->li_tv) == NULL)
13922 return;
13923 }
13924 else if (argvars[0].v_type == VAR_BLOB)
13925 {
13926 blob = argvars[0].vval.v_blob;
13927 if (blob == NULL)
13928 return;
13929 }
13930 else
13931 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013932 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013933 return;
13934 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013935
13936 if (argvars[2].v_type != VAR_UNKNOWN)
13937 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013938 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013939
13940 if (arg2 == NULL)
13941 return;
13942 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013943 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013944 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013945 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013946#ifdef HAVE_FSYNC
13947 if (vim_strchr(arg2, 's') != NULL)
13948 do_fsync = TRUE;
13949 else if (vim_strchr(arg2, 'S') != NULL)
13950 do_fsync = FALSE;
13951#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013952 }
13953
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013954 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013955 if (fname == NULL)
13956 return;
13957
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013958 /* Always open the file in binary mode, library functions have a mind of
13959 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013960 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13961 append ? APPENDBIN : WRITEBIN)) == NULL)
13962 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013963 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013964 ret = -1;
13965 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013966 else if (blob)
13967 {
13968 if (write_blob(fd, blob) == FAIL)
13969 ret = -1;
13970#ifdef HAVE_FSYNC
13971 else if (do_fsync)
13972 // Ignore the error, the user wouldn't know what to do about it.
13973 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010013974 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013975#endif
13976 fclose(fd);
13977 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013978 else
13979 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013980 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013981 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013982#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013983 else if (do_fsync)
13984 /* Ignore the error, the user wouldn't know what to do about it.
13985 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010013986 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013987#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013988 fclose(fd);
13989 }
13990
13991 rettv->vval.v_number = ret;
13992}
13993
13994/*
13995 * "xor(expr, expr)" function
13996 */
13997 static void
13998f_xor(typval_T *argvars, typval_T *rettv)
13999{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014000 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
14001 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014002}
14003
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014004#endif /* FEAT_EVAL */