blob: 3875b43da5424d38b930f53d198a765c9f3b4a2f [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);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077static void f_col(typval_T *argvars, typval_T *rettv);
78#if defined(FEAT_INS_EXPAND)
79static void f_complete(typval_T *argvars, typval_T *rettv);
80static void f_complete_add(typval_T *argvars, typval_T *rettv);
81static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +010082static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083#endif
84static void f_confirm(typval_T *argvars, typval_T *rettv);
85static void f_copy(typval_T *argvars, typval_T *rettv);
86#ifdef FEAT_FLOAT
87static void f_cos(typval_T *argvars, typval_T *rettv);
88static void f_cosh(typval_T *argvars, typval_T *rettv);
89#endif
90static void f_count(typval_T *argvars, typval_T *rettv);
91static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
92static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010093#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020094static void f_debugbreak(typval_T *argvars, typval_T *rettv);
95#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_deepcopy(typval_T *argvars, typval_T *rettv);
97static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020098static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_did_filetype(typval_T *argvars, typval_T *rettv);
100static void f_diff_filler(typval_T *argvars, typval_T *rettv);
101static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
102static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200103static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_escape(typval_T *argvars, typval_T *rettv);
105static void f_eval(typval_T *argvars, typval_T *rettv);
106static void f_eventhandler(typval_T *argvars, typval_T *rettv);
107static void f_executable(typval_T *argvars, typval_T *rettv);
108static void f_execute(typval_T *argvars, typval_T *rettv);
109static void f_exepath(typval_T *argvars, typval_T *rettv);
110static void f_exists(typval_T *argvars, typval_T *rettv);
111#ifdef FEAT_FLOAT
112static void f_exp(typval_T *argvars, typval_T *rettv);
113#endif
114static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200115static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200116static void f_extend(typval_T *argvars, typval_T *rettv);
117static void f_feedkeys(typval_T *argvars, typval_T *rettv);
118static void f_filereadable(typval_T *argvars, typval_T *rettv);
119static void f_filewritable(typval_T *argvars, typval_T *rettv);
120static void f_filter(typval_T *argvars, typval_T *rettv);
121static void f_finddir(typval_T *argvars, typval_T *rettv);
122static void f_findfile(typval_T *argvars, typval_T *rettv);
123#ifdef FEAT_FLOAT
124static void f_float2nr(typval_T *argvars, typval_T *rettv);
125static void f_floor(typval_T *argvars, typval_T *rettv);
126static void f_fmod(typval_T *argvars, typval_T *rettv);
127#endif
128static void f_fnameescape(typval_T *argvars, typval_T *rettv);
129static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
130static void f_foldclosed(typval_T *argvars, typval_T *rettv);
131static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
132static void f_foldlevel(typval_T *argvars, typval_T *rettv);
133static void f_foldtext(typval_T *argvars, typval_T *rettv);
134static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
135static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200136static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_function(typval_T *argvars, typval_T *rettv);
138static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
139static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200140static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_getbufline(typval_T *argvars, typval_T *rettv);
142static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100143static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200144static void f_getchar(typval_T *argvars, typval_T *rettv);
145static void f_getcharmod(typval_T *argvars, typval_T *rettv);
146static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
147static void f_getcmdline(typval_T *argvars, typval_T *rettv);
148#if defined(FEAT_CMDL_COMPL)
149static void f_getcompletion(typval_T *argvars, typval_T *rettv);
150#endif
151static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
152static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
153static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
154static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200155static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_getfontname(typval_T *argvars, typval_T *rettv);
157static void f_getfperm(typval_T *argvars, typval_T *rettv);
158static void f_getfsize(typval_T *argvars, typval_T *rettv);
159static void f_getftime(typval_T *argvars, typval_T *rettv);
160static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100161static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200163static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200164static void f_getpid(typval_T *argvars, typval_T *rettv);
165static void f_getcurpos(typval_T *argvars, typval_T *rettv);
166static void f_getpos(typval_T *argvars, typval_T *rettv);
167static void f_getqflist(typval_T *argvars, typval_T *rettv);
168static void f_getreg(typval_T *argvars, typval_T *rettv);
169static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200170static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_gettabvar(typval_T *argvars, typval_T *rettv);
172static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100173static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200174static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100175static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200176static void f_getwinposx(typval_T *argvars, typval_T *rettv);
177static void f_getwinposy(typval_T *argvars, typval_T *rettv);
178static void f_getwinvar(typval_T *argvars, typval_T *rettv);
179static void f_glob(typval_T *argvars, typval_T *rettv);
180static void f_globpath(typval_T *argvars, typval_T *rettv);
181static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
182static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200183static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
184static void f_hasmapto(typval_T *argvars, typval_T *rettv);
185static void f_histadd(typval_T *argvars, typval_T *rettv);
186static void f_histdel(typval_T *argvars, typval_T *rettv);
187static void f_histget(typval_T *argvars, typval_T *rettv);
188static void f_histnr(typval_T *argvars, typval_T *rettv);
189static void f_hlID(typval_T *argvars, typval_T *rettv);
190static void f_hlexists(typval_T *argvars, typval_T *rettv);
191static void f_hostname(typval_T *argvars, typval_T *rettv);
192static void f_iconv(typval_T *argvars, typval_T *rettv);
193static void f_indent(typval_T *argvars, typval_T *rettv);
194static void f_index(typval_T *argvars, typval_T *rettv);
195static void f_input(typval_T *argvars, typval_T *rettv);
196static void f_inputdialog(typval_T *argvars, typval_T *rettv);
197static void f_inputlist(typval_T *argvars, typval_T *rettv);
198static void f_inputrestore(typval_T *argvars, typval_T *rettv);
199static void f_inputsave(typval_T *argvars, typval_T *rettv);
200static void f_inputsecret(typval_T *argvars, typval_T *rettv);
201static void f_insert(typval_T *argvars, typval_T *rettv);
202static void f_invert(typval_T *argvars, typval_T *rettv);
203static void f_isdirectory(typval_T *argvars, typval_T *rettv);
204static void f_islocked(typval_T *argvars, typval_T *rettv);
205#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200206static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_isnan(typval_T *argvars, typval_T *rettv);
208#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
210static void f_len(typval_T *argvars, typval_T *rettv);
211static void f_libcall(typval_T *argvars, typval_T *rettv);
212static void f_libcallnr(typval_T *argvars, typval_T *rettv);
213static void f_line(typval_T *argvars, typval_T *rettv);
214static void f_line2byte(typval_T *argvars, typval_T *rettv);
215static void f_lispindent(typval_T *argvars, typval_T *rettv);
216static void f_localtime(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_log(typval_T *argvars, typval_T *rettv);
219static void f_log10(typval_T *argvars, typval_T *rettv);
220#endif
221#ifdef FEAT_LUA
222static void f_luaeval(typval_T *argvars, typval_T *rettv);
223#endif
224static void f_map(typval_T *argvars, typval_T *rettv);
225static void f_maparg(typval_T *argvars, typval_T *rettv);
226static void f_mapcheck(typval_T *argvars, typval_T *rettv);
227static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200228static void f_matchend(typval_T *argvars, typval_T *rettv);
229static void f_matchlist(typval_T *argvars, typval_T *rettv);
230static void f_matchstr(typval_T *argvars, typval_T *rettv);
231static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
232static void f_max(typval_T *argvars, typval_T *rettv);
233static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_mode(typval_T *argvars, typval_T *rettv);
236#ifdef FEAT_MZSCHEME
237static void f_mzeval(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
240static void f_nr2char(typval_T *argvars, typval_T *rettv);
241static void f_or(typval_T *argvars, typval_T *rettv);
242static void f_pathshorten(typval_T *argvars, typval_T *rettv);
243#ifdef FEAT_PERL
244static void f_perleval(typval_T *argvars, typval_T *rettv);
245#endif
246#ifdef FEAT_FLOAT
247static void f_pow(typval_T *argvars, typval_T *rettv);
248#endif
249static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
250static void f_printf(typval_T *argvars, typval_T *rettv);
251static void f_pumvisible(typval_T *argvars, typval_T *rettv);
252#ifdef FEAT_PYTHON3
253static void f_py3eval(typval_T *argvars, typval_T *rettv);
254#endif
255#ifdef FEAT_PYTHON
256static void f_pyeval(typval_T *argvars, typval_T *rettv);
257#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100258#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
259static void f_pyxeval(typval_T *argvars, typval_T *rettv);
260#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200262static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200263static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200264static void f_reg_executing(typval_T *argvars, typval_T *rettv);
265static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200266static void f_reltime(typval_T *argvars, typval_T *rettv);
267#ifdef FEAT_FLOAT
268static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
269#endif
270static void f_reltimestr(typval_T *argvars, typval_T *rettv);
271static void f_remote_expr(typval_T *argvars, typval_T *rettv);
272static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
273static void f_remote_peek(typval_T *argvars, typval_T *rettv);
274static void f_remote_read(typval_T *argvars, typval_T *rettv);
275static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100276static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200277static void f_remove(typval_T *argvars, typval_T *rettv);
278static void f_rename(typval_T *argvars, typval_T *rettv);
279static void f_repeat(typval_T *argvars, typval_T *rettv);
280static void f_resolve(typval_T *argvars, typval_T *rettv);
281static void f_reverse(typval_T *argvars, typval_T *rettv);
282#ifdef FEAT_FLOAT
283static void f_round(typval_T *argvars, typval_T *rettv);
284#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100285#ifdef FEAT_RUBY
286static void f_rubyeval(typval_T *argvars, typval_T *rettv);
287#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288static void f_screenattr(typval_T *argvars, typval_T *rettv);
289static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100290static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200291static void f_screencol(typval_T *argvars, typval_T *rettv);
292static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100293static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200294static void f_search(typval_T *argvars, typval_T *rettv);
295static void f_searchdecl(typval_T *argvars, typval_T *rettv);
296static void f_searchpair(typval_T *argvars, typval_T *rettv);
297static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
298static void f_searchpos(typval_T *argvars, typval_T *rettv);
299static void f_server2client(typval_T *argvars, typval_T *rettv);
300static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200301static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_setbufvar(typval_T *argvars, typval_T *rettv);
303static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
304static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200305static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306static void f_setfperm(typval_T *argvars, typval_T *rettv);
307static void f_setline(typval_T *argvars, typval_T *rettv);
308static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309static void f_setpos(typval_T *argvars, typval_T *rettv);
310static void f_setqflist(typval_T *argvars, typval_T *rettv);
311static void f_setreg(typval_T *argvars, typval_T *rettv);
312static void f_settabvar(typval_T *argvars, typval_T *rettv);
313static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100314static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315static void f_setwinvar(typval_T *argvars, typval_T *rettv);
316#ifdef FEAT_CRYPT
317static void f_sha256(typval_T *argvars, typval_T *rettv);
318#endif /* FEAT_CRYPT */
319static void f_shellescape(typval_T *argvars, typval_T *rettv);
320static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
321static void f_simplify(typval_T *argvars, typval_T *rettv);
322#ifdef FEAT_FLOAT
323static void f_sin(typval_T *argvars, typval_T *rettv);
324static void f_sinh(typval_T *argvars, typval_T *rettv);
325#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326static void f_soundfold(typval_T *argvars, typval_T *rettv);
327static void f_spellbadword(typval_T *argvars, typval_T *rettv);
328static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
329static void f_split(typval_T *argvars, typval_T *rettv);
330#ifdef FEAT_FLOAT
331static void f_sqrt(typval_T *argvars, typval_T *rettv);
332static void f_str2float(typval_T *argvars, typval_T *rettv);
333#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200334static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200335static void f_str2nr(typval_T *argvars, typval_T *rettv);
336static void f_strchars(typval_T *argvars, typval_T *rettv);
337#ifdef HAVE_STRFTIME
338static void f_strftime(typval_T *argvars, typval_T *rettv);
339#endif
340static void f_strgetchar(typval_T *argvars, typval_T *rettv);
341static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342static void f_strlen(typval_T *argvars, typval_T *rettv);
343static void f_strcharpart(typval_T *argvars, typval_T *rettv);
344static void f_strpart(typval_T *argvars, typval_T *rettv);
345static void f_strridx(typval_T *argvars, typval_T *rettv);
346static void f_strtrans(typval_T *argvars, typval_T *rettv);
347static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
348static void f_strwidth(typval_T *argvars, typval_T *rettv);
349static void f_submatch(typval_T *argvars, typval_T *rettv);
350static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200351static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200352static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353static void f_synID(typval_T *argvars, typval_T *rettv);
354static void f_synIDattr(typval_T *argvars, typval_T *rettv);
355static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
356static void f_synstack(typval_T *argvars, typval_T *rettv);
357static void f_synconcealed(typval_T *argvars, typval_T *rettv);
358static void f_system(typval_T *argvars, typval_T *rettv);
359static void f_systemlist(typval_T *argvars, typval_T *rettv);
360static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
361static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
362static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
363static void f_taglist(typval_T *argvars, typval_T *rettv);
364static void f_tagfiles(typval_T *argvars, typval_T *rettv);
365static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366#ifdef FEAT_FLOAT
367static void f_tan(typval_T *argvars, typval_T *rettv);
368static void f_tanh(typval_T *argvars, typval_T *rettv);
369#endif
370#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200371static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200372static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200373static void f_timer_start(typval_T *argvars, typval_T *rettv);
374static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200375static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200376#endif
377static void f_tolower(typval_T *argvars, typval_T *rettv);
378static void f_toupper(typval_T *argvars, typval_T *rettv);
379static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100380static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381#ifdef FEAT_FLOAT
382static void f_trunc(typval_T *argvars, typval_T *rettv);
383#endif
384static void f_type(typval_T *argvars, typval_T *rettv);
385static void f_undofile(typval_T *argvars, typval_T *rettv);
386static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200387static void f_virtcol(typval_T *argvars, typval_T *rettv);
388static void f_visualmode(typval_T *argvars, typval_T *rettv);
389static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200390static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
392static void f_win_getid(typval_T *argvars, typval_T *rettv);
393static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
394static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
395static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100396static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397static void f_winbufnr(typval_T *argvars, typval_T *rettv);
398static void f_wincol(typval_T *argvars, typval_T *rettv);
399static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200400static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401static void f_winline(typval_T *argvars, typval_T *rettv);
402static void f_winnr(typval_T *argvars, typval_T *rettv);
403static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
404static void f_winrestview(typval_T *argvars, typval_T *rettv);
405static void f_winsaveview(typval_T *argvars, typval_T *rettv);
406static void f_winwidth(typval_T *argvars, typval_T *rettv);
407static void f_writefile(typval_T *argvars, typval_T *rettv);
408static void f_wordcount(typval_T *argvars, typval_T *rettv);
409static void f_xor(typval_T *argvars, typval_T *rettv);
410
411/*
412 * Array with names and number of arguments of all internal functions
413 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
414 */
415static struct fst
416{
417 char *f_name; /* function name */
418 char f_min_argc; /* minimal number of arguments */
419 char f_max_argc; /* maximal number of arguments */
420 void (*f_func)(typval_T *args, typval_T *rvar);
421 /* implementation of function */
422} functions[] =
423{
424#ifdef FEAT_FLOAT
425 {"abs", 1, 1, f_abs},
426 {"acos", 1, 1, f_acos}, /* WJMc */
427#endif
428 {"add", 2, 2, f_add},
429 {"and", 2, 2, f_and},
430 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200431 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200432 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200433 {"argidx", 0, 0, f_argidx},
434 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200435 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#ifdef FEAT_FLOAT
437 {"asin", 1, 1, f_asin}, /* WJMc */
438#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100439 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200440 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100441 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200443 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100445 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200446 {"assert_match", 2, 3, f_assert_match},
447 {"assert_notequal", 2, 3, f_assert_notequal},
448 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100449 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200450 {"assert_true", 1, 2, f_assert_true},
451#ifdef FEAT_FLOAT
452 {"atan", 1, 1, f_atan},
453 {"atan2", 2, 2, f_atan2},
454#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100455#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +0200456 {"balloon_gettext", 0, 0, f_balloon_gettext},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100457 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100458# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100459 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100460# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100461#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200462 {"browse", 4, 4, f_browse},
463 {"browsedir", 2, 2, f_browsedir},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200464 {"bufadd", 1, 1, f_bufadd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200465 {"bufexists", 1, 1, f_bufexists},
466 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
467 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
468 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
469 {"buflisted", 1, 1, f_buflisted},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200470 {"bufload", 1, 1, f_bufload},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200471 {"bufloaded", 1, 1, f_bufloaded},
472 {"bufname", 1, 1, f_bufname},
473 {"bufnr", 1, 2, f_bufnr},
474 {"bufwinid", 1, 1, f_bufwinid},
475 {"bufwinnr", 1, 1, f_bufwinnr},
476 {"byte2line", 1, 1, f_byte2line},
477 {"byteidx", 2, 2, f_byteidx},
478 {"byteidxcomp", 2, 2, f_byteidxcomp},
479 {"call", 2, 3, f_call},
480#ifdef FEAT_FLOAT
481 {"ceil", 1, 1, f_ceil},
482#endif
483#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100484 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200485 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200486 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
488 {"ch_evalraw", 2, 3, f_ch_evalraw},
489 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
490 {"ch_getjob", 1, 1, f_ch_getjob},
491 {"ch_info", 1, 1, f_ch_info},
492 {"ch_log", 1, 2, f_ch_log},
493 {"ch_logfile", 1, 2, f_ch_logfile},
494 {"ch_open", 1, 2, f_ch_open},
495 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100496 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200497 {"ch_readraw", 1, 2, f_ch_readraw},
498 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
499 {"ch_sendraw", 2, 3, f_ch_sendraw},
500 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200501 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200502#endif
503 {"changenr", 0, 0, f_changenr},
504 {"char2nr", 1, 2, f_char2nr},
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200505 {"chdir", 1, 1, f_chdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200506 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100507 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508 {"col", 1, 1, f_col},
509#if defined(FEAT_INS_EXPAND)
510 {"complete", 2, 2, f_complete},
511 {"complete_add", 1, 1, f_complete_add},
512 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100513 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200514#endif
515 {"confirm", 1, 4, f_confirm},
516 {"copy", 1, 1, f_copy},
517#ifdef FEAT_FLOAT
518 {"cos", 1, 1, f_cos},
519 {"cosh", 1, 1, f_cosh},
520#endif
521 {"count", 2, 4, f_count},
522 {"cscope_connection",0,3, f_cscope_connection},
523 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100524#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200525 {"debugbreak", 1, 1, f_debugbreak},
526#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527 {"deepcopy", 1, 2, f_deepcopy},
528 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200529 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530 {"did_filetype", 0, 0, f_did_filetype},
531 {"diff_filler", 1, 1, f_diff_filler},
532 {"diff_hlID", 2, 2, f_diff_hlID},
533 {"empty", 1, 1, f_empty},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200534 {"environ", 0, 0, f_environ},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535 {"escape", 2, 2, f_escape},
536 {"eval", 1, 1, f_eval},
537 {"eventhandler", 0, 0, f_eventhandler},
538 {"executable", 1, 1, f_executable},
539 {"execute", 1, 2, f_execute},
540 {"exepath", 1, 1, f_exepath},
541 {"exists", 1, 1, f_exists},
542#ifdef FEAT_FLOAT
543 {"exp", 1, 1, f_exp},
544#endif
545 {"expand", 1, 3, f_expand},
Bram Moolenaar80dad482019-06-09 17:22:31 +0200546 {"expandcmd", 1, 1, f_expandcmd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547 {"extend", 2, 3, f_extend},
548 {"feedkeys", 1, 2, f_feedkeys},
549 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
550 {"filereadable", 1, 1, f_filereadable},
551 {"filewritable", 1, 1, f_filewritable},
552 {"filter", 2, 2, f_filter},
553 {"finddir", 1, 3, f_finddir},
554 {"findfile", 1, 3, f_findfile},
555#ifdef FEAT_FLOAT
556 {"float2nr", 1, 1, f_float2nr},
557 {"floor", 1, 1, f_floor},
558 {"fmod", 2, 2, f_fmod},
559#endif
560 {"fnameescape", 1, 1, f_fnameescape},
561 {"fnamemodify", 2, 2, f_fnamemodify},
562 {"foldclosed", 1, 1, f_foldclosed},
563 {"foldclosedend", 1, 1, f_foldclosedend},
564 {"foldlevel", 1, 1, f_foldlevel},
565 {"foldtext", 0, 0, f_foldtext},
566 {"foldtextresult", 1, 1, f_foldtextresult},
567 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200568 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200569 {"function", 1, 3, f_function},
570 {"garbagecollect", 0, 1, f_garbagecollect},
571 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200572 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200573 {"getbufline", 2, 3, f_getbufline},
574 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100575 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200576 {"getchar", 0, 1, f_getchar},
577 {"getcharmod", 0, 0, f_getcharmod},
578 {"getcharsearch", 0, 0, f_getcharsearch},
579 {"getcmdline", 0, 0, f_getcmdline},
580 {"getcmdpos", 0, 0, f_getcmdpos},
581 {"getcmdtype", 0, 0, f_getcmdtype},
582 {"getcmdwintype", 0, 0, f_getcmdwintype},
583#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200584 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200585#endif
586 {"getcurpos", 0, 0, f_getcurpos},
587 {"getcwd", 0, 2, f_getcwd},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200588 {"getenv", 1, 1, f_getenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200589 {"getfontname", 0, 1, f_getfontname},
590 {"getfperm", 1, 1, f_getfperm},
591 {"getfsize", 1, 1, f_getfsize},
592 {"getftime", 1, 1, f_getftime},
593 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100594 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200595 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200596 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100597 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200598 {"getpid", 0, 0, f_getpid},
599 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200600 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601 {"getreg", 0, 3, f_getreg},
602 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200603 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200604 {"gettabvar", 2, 3, f_gettabvar},
605 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100606 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200607 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100608 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609 {"getwinposx", 0, 0, f_getwinposx},
610 {"getwinposy", 0, 0, f_getwinposy},
611 {"getwinvar", 2, 3, f_getwinvar},
612 {"glob", 1, 4, f_glob},
613 {"glob2regpat", 1, 1, f_glob2regpat},
614 {"globpath", 2, 5, f_globpath},
615 {"has", 1, 1, f_has},
616 {"has_key", 2, 2, f_has_key},
617 {"haslocaldir", 0, 2, f_haslocaldir},
618 {"hasmapto", 1, 3, f_hasmapto},
619 {"highlightID", 1, 1, f_hlID}, /* obsolete */
620 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
621 {"histadd", 2, 2, f_histadd},
622 {"histdel", 1, 2, f_histdel},
623 {"histget", 1, 2, f_histget},
624 {"histnr", 1, 1, f_histnr},
625 {"hlID", 1, 1, f_hlID},
626 {"hlexists", 1, 1, f_hlexists},
627 {"hostname", 0, 0, f_hostname},
628 {"iconv", 3, 3, f_iconv},
629 {"indent", 1, 1, f_indent},
630 {"index", 2, 4, f_index},
631 {"input", 1, 3, f_input},
632 {"inputdialog", 1, 3, f_inputdialog},
633 {"inputlist", 1, 1, f_inputlist},
634 {"inputrestore", 0, 0, f_inputrestore},
635 {"inputsave", 0, 0, f_inputsave},
636 {"inputsecret", 1, 2, f_inputsecret},
637 {"insert", 2, 3, f_insert},
638 {"invert", 1, 1, f_invert},
639 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200640#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
641 {"isinf", 1, 1, f_isinf},
642#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643 {"islocked", 1, 1, f_islocked},
644#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
645 {"isnan", 1, 1, f_isnan},
646#endif
647 {"items", 1, 1, f_items},
648#ifdef FEAT_JOB_CHANNEL
649 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200650 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651 {"job_setoptions", 2, 2, f_job_setoptions},
652 {"job_start", 1, 2, f_job_start},
653 {"job_status", 1, 1, f_job_status},
654 {"job_stop", 1, 2, f_job_stop},
655#endif
656 {"join", 1, 2, f_join},
657 {"js_decode", 1, 1, f_js_decode},
658 {"js_encode", 1, 1, f_js_encode},
659 {"json_decode", 1, 1, f_json_decode},
660 {"json_encode", 1, 1, f_json_encode},
661 {"keys", 1, 1, f_keys},
662 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
663 {"len", 1, 1, f_len},
664 {"libcall", 3, 3, f_libcall},
665 {"libcallnr", 3, 3, f_libcallnr},
666 {"line", 1, 1, f_line},
667 {"line2byte", 1, 1, f_line2byte},
668 {"lispindent", 1, 1, f_lispindent},
Bram Moolenaar9d401282019-04-06 13:18:12 +0200669 {"list2str", 1, 2, f_list2str},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200670 {"listener_add", 1, 2, f_listener_add},
Bram Moolenaarfe1ade02019-05-14 21:20:36 +0200671 {"listener_flush", 0, 1, f_listener_flush},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200672 {"listener_remove", 1, 1, f_listener_remove},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200673 {"localtime", 0, 0, f_localtime},
674#ifdef FEAT_FLOAT
675 {"log", 1, 1, f_log},
676 {"log10", 1, 1, f_log10},
677#endif
678#ifdef FEAT_LUA
679 {"luaeval", 1, 2, f_luaeval},
680#endif
681 {"map", 2, 2, f_map},
682 {"maparg", 1, 4, f_maparg},
683 {"mapcheck", 1, 3, f_mapcheck},
684 {"match", 2, 4, f_match},
685 {"matchadd", 2, 5, f_matchadd},
686 {"matchaddpos", 2, 5, f_matchaddpos},
687 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100688 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689 {"matchend", 2, 4, f_matchend},
690 {"matchlist", 2, 4, f_matchlist},
691 {"matchstr", 2, 4, f_matchstr},
692 {"matchstrpos", 2, 4, f_matchstrpos},
693 {"max", 1, 1, f_max},
694 {"min", 1, 1, f_min},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695 {"mkdir", 1, 3, f_mkdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200696 {"mode", 0, 1, f_mode},
697#ifdef FEAT_MZSCHEME
698 {"mzeval", 1, 1, f_mzeval},
699#endif
700 {"nextnonblank", 1, 1, f_nextnonblank},
701 {"nr2char", 1, 2, f_nr2char},
702 {"or", 2, 2, f_or},
703 {"pathshorten", 1, 1, f_pathshorten},
704#ifdef FEAT_PERL
705 {"perleval", 1, 1, f_perleval},
706#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200707#ifdef FEAT_TEXT_PROP
Bram Moolenaarcc31ad92019-05-30 19:25:06 +0200708 {"popup_atcursor", 2, 2, f_popup_atcursor},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200709 {"popup_beval", 2, 2, f_popup_beval},
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200710 {"popup_clear", 0, 0, f_popup_clear},
Bram Moolenaar9eaac892019-06-01 22:49:29 +0200711 {"popup_close", 1, 2, f_popup_close},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200712 {"popup_create", 2, 2, f_popup_create},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200713 {"popup_dialog", 2, 2, f_popup_dialog},
Bram Moolenaara730e552019-06-16 19:05:31 +0200714 {"popup_filter_menu", 2, 2, f_popup_filter_menu},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200715 {"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
Bram Moolenaar8c2a6002019-05-30 14:29:45 +0200716 {"popup_getoptions", 1, 1, f_popup_getoptions},
Bram Moolenaarccd6e342019-05-30 22:35:18 +0200717 {"popup_getpos", 1, 1, f_popup_getpos},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200718 {"popup_hide", 1, 1, f_popup_hide},
Bram Moolenaarb4f06282019-07-12 21:07:54 +0200719 {"popup_locate", 2, 2, f_popup_locate},
Bram Moolenaara730e552019-06-16 19:05:31 +0200720 {"popup_menu", 2, 2, f_popup_menu},
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200721 {"popup_move", 2, 2, f_popup_move},
Bram Moolenaar68d48f42019-06-12 22:42:41 +0200722 {"popup_notification", 2, 2, f_popup_notification},
Bram Moolenaarae943152019-06-16 22:54:14 +0200723 {"popup_setoptions", 2, 2, f_popup_setoptions},
Bram Moolenaardc2ce582019-06-16 15:32:14 +0200724 {"popup_settext", 2, 2, f_popup_settext},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200725 {"popup_show", 1, 1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200726#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#ifdef FEAT_FLOAT
728 {"pow", 2, 2, f_pow},
729#endif
730 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100731 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200732#ifdef FEAT_JOB_CHANNEL
733 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200734 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200735 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
736#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100737#ifdef FEAT_TEXT_PROP
738 {"prop_add", 3, 3, f_prop_add},
739 {"prop_clear", 1, 3, f_prop_clear},
740 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100741 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100742 {"prop_type_add", 2, 2, f_prop_type_add},
743 {"prop_type_change", 2, 2, f_prop_type_change},
744 {"prop_type_delete", 1, 2, f_prop_type_delete},
745 {"prop_type_get", 1, 2, f_prop_type_get},
746 {"prop_type_list", 0, 1, f_prop_type_list},
747#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200748 {"pumvisible", 0, 0, f_pumvisible},
749#ifdef FEAT_PYTHON3
750 {"py3eval", 1, 1, f_py3eval},
751#endif
752#ifdef FEAT_PYTHON
753 {"pyeval", 1, 1, f_pyeval},
754#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100755#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
756 {"pyxeval", 1, 1, f_pyxeval},
757#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200759 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200760 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200761 {"reg_executing", 0, 0, f_reg_executing},
762 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763 {"reltime", 0, 2, f_reltime},
764#ifdef FEAT_FLOAT
765 {"reltimefloat", 1, 1, f_reltimefloat},
766#endif
767 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100768 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200769 {"remote_foreground", 1, 1, f_remote_foreground},
770 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100771 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100773 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200774 {"remove", 2, 3, f_remove},
775 {"rename", 2, 2, f_rename},
776 {"repeat", 2, 2, f_repeat},
777 {"resolve", 1, 1, f_resolve},
778 {"reverse", 1, 1, f_reverse},
779#ifdef FEAT_FLOAT
780 {"round", 1, 1, f_round},
781#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100782#ifdef FEAT_RUBY
783 {"rubyeval", 1, 1, f_rubyeval},
784#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200785 {"screenattr", 2, 2, f_screenattr},
786 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100787 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788 {"screencol", 0, 0, f_screencol},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200789 {"screenpos", 3, 3, f_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200790 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100791 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200792 {"search", 1, 4, f_search},
793 {"searchdecl", 1, 3, f_searchdecl},
794 {"searchpair", 3, 7, f_searchpair},
795 {"searchpairpos", 3, 7, f_searchpairpos},
796 {"searchpos", 1, 4, f_searchpos},
797 {"server2client", 2, 2, f_server2client},
798 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200799 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200800 {"setbufvar", 3, 3, f_setbufvar},
801 {"setcharsearch", 1, 1, f_setcharsearch},
802 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200803 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804 {"setfperm", 2, 2, f_setfperm},
805 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200806 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100807 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200809 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810 {"setreg", 2, 3, f_setreg},
811 {"settabvar", 3, 3, f_settabvar},
812 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100813 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814 {"setwinvar", 3, 3, f_setwinvar},
815#ifdef FEAT_CRYPT
816 {"sha256", 1, 1, f_sha256},
817#endif
818 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100819 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100820#ifdef FEAT_SIGNS
821 {"sign_define", 1, 2, f_sign_define},
822 {"sign_getdefined", 0, 1, f_sign_getdefined},
823 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100824 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100825 {"sign_place", 4, 5, f_sign_place},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200826 {"sign_placelist", 1, 1, f_sign_placelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100827 {"sign_undefine", 0, 1, f_sign_undefine},
828 {"sign_unplace", 1, 2, f_sign_unplace},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200829 {"sign_unplacelist", 1, 2, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100830#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831 {"simplify", 1, 1, f_simplify},
832#ifdef FEAT_FLOAT
833 {"sin", 1, 1, f_sin},
834 {"sinh", 1, 1, f_sinh},
835#endif
836 {"sort", 1, 3, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200837#ifdef FEAT_SOUND
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200838 {"sound_clear", 0, 0, f_sound_clear},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200839 {"sound_playevent", 1, 2, f_sound_playevent},
840 {"sound_playfile", 1, 2, f_sound_playfile},
841 {"sound_stop", 1, 1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200842#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843 {"soundfold", 1, 1, f_soundfold},
844 {"spellbadword", 0, 1, f_spellbadword},
845 {"spellsuggest", 1, 3, f_spellsuggest},
846 {"split", 1, 3, f_split},
847#ifdef FEAT_FLOAT
848 {"sqrt", 1, 1, f_sqrt},
849 {"str2float", 1, 1, f_str2float},
850#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200851 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200852 {"str2nr", 1, 2, f_str2nr},
853 {"strcharpart", 2, 3, f_strcharpart},
854 {"strchars", 1, 2, f_strchars},
855 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
856#ifdef HAVE_STRFTIME
857 {"strftime", 1, 2, f_strftime},
858#endif
859 {"strgetchar", 2, 2, f_strgetchar},
860 {"stridx", 2, 3, f_stridx},
861 {"string", 1, 1, f_string},
862 {"strlen", 1, 1, f_strlen},
863 {"strpart", 2, 3, f_strpart},
864 {"strridx", 2, 3, f_strridx},
865 {"strtrans", 1, 1, f_strtrans},
866 {"strwidth", 1, 1, f_strwidth},
867 {"submatch", 1, 2, f_submatch},
868 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200869 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200870 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200871 {"synID", 3, 3, f_synID},
872 {"synIDattr", 2, 3, f_synIDattr},
873 {"synIDtrans", 1, 1, f_synIDtrans},
874 {"synconcealed", 2, 2, f_synconcealed},
875 {"synstack", 2, 2, f_synstack},
876 {"system", 1, 2, f_system},
877 {"systemlist", 1, 2, f_systemlist},
878 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
879 {"tabpagenr", 0, 1, f_tabpagenr},
880 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
881 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100882 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883#ifdef FEAT_FLOAT
884 {"tan", 1, 1, f_tan},
885 {"tanh", 1, 1, f_tanh},
886#endif
887 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200888#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100889 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
890 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100891 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200892 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200893# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
894 {"term_getansicolors", 1, 1, f_term_getansicolors},
895# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200896 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200897 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200898 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200899 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200900 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200901 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200902 {"term_getstatus", 1, 1, f_term_getstatus},
903 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200904 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200905 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200906 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200907 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200908# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
909 {"term_setansicolors", 2, 2, f_term_setansicolors},
910# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100911 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100912 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200913 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200914 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200915 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200916#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
918 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200919 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaaradc67142019-06-22 01:40:42 +0200921 {"test_garbagecollect_soon", 0, 0, f_test_garbagecollect_soon},
Bram Moolenaareda65222019-05-16 20:29:44 +0200922 {"test_getvalue", 1, 1, f_test_getvalue},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100923 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100924 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925#ifdef FEAT_JOB_CHANNEL
926 {"test_null_channel", 0, 0, f_test_null_channel},
927#endif
928 {"test_null_dict", 0, 0, f_test_null_dict},
929#ifdef FEAT_JOB_CHANNEL
930 {"test_null_job", 0, 0, f_test_null_job},
931#endif
932 {"test_null_list", 0, 0, f_test_null_list},
933 {"test_null_partial", 0, 0, f_test_null_partial},
934 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200935 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100936 {"test_override", 2, 2, f_test_override},
937 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200938#ifdef FEAT_GUI
939 {"test_scrollbar", 3, 3, f_test_scrollbar},
940#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200941#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +0200942 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200943#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200944 {"test_settime", 1, 1, f_test_settime},
945#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200946 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200947 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948 {"timer_start", 2, 3, f_timer_start},
949 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200950 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951#endif
952 {"tolower", 1, 1, f_tolower},
953 {"toupper", 1, 1, f_toupper},
954 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100955 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956#ifdef FEAT_FLOAT
957 {"trunc", 1, 1, f_trunc},
958#endif
959 {"type", 1, 1, f_type},
960 {"undofile", 1, 1, f_undofile},
961 {"undotree", 0, 0, f_undotree},
962 {"uniq", 1, 3, f_uniq},
963 {"values", 1, 1, f_values},
964 {"virtcol", 1, 1, f_virtcol},
965 {"visualmode", 0, 1, f_visualmode},
966 {"wildmenumode", 0, 0, f_wildmenumode},
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200967 {"win_execute", 2, 3, f_win_execute},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 {"win_findbuf", 1, 1, f_win_findbuf},
969 {"win_getid", 0, 2, f_win_getid},
970 {"win_gotoid", 1, 1, f_win_gotoid},
971 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
972 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100973 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200974 {"winbufnr", 1, 1, f_winbufnr},
975 {"wincol", 0, 0, f_wincol},
976 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200977 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978 {"winline", 0, 0, f_winline},
979 {"winnr", 0, 1, f_winnr},
980 {"winrestcmd", 0, 0, f_winrestcmd},
981 {"winrestview", 1, 1, f_winrestview},
982 {"winsaveview", 0, 0, f_winsaveview},
983 {"winwidth", 1, 1, f_winwidth},
984 {"wordcount", 0, 0, f_wordcount},
985 {"writefile", 2, 3, f_writefile},
986 {"xor", 2, 2, f_xor},
987};
988
989#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
990
991/*
992 * Function given to ExpandGeneric() to obtain the list of internal
993 * or user defined function names.
994 */
995 char_u *
996get_function_name(expand_T *xp, int idx)
997{
998 static int intidx = -1;
999 char_u *name;
1000
1001 if (idx == 0)
1002 intidx = -1;
1003 if (intidx < 0)
1004 {
1005 name = get_user_func_name(xp, idx);
1006 if (name != NULL)
1007 return name;
1008 }
1009 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1010 {
1011 STRCPY(IObuff, functions[intidx].f_name);
1012 STRCAT(IObuff, "(");
1013 if (functions[intidx].f_max_argc == 0)
1014 STRCAT(IObuff, ")");
1015 return IObuff;
1016 }
1017
1018 return NULL;
1019}
1020
1021/*
1022 * Function given to ExpandGeneric() to obtain the list of internal or
1023 * user defined variable or function names.
1024 */
1025 char_u *
1026get_expr_name(expand_T *xp, int idx)
1027{
1028 static int intidx = -1;
1029 char_u *name;
1030
1031 if (idx == 0)
1032 intidx = -1;
1033 if (intidx < 0)
1034 {
1035 name = get_function_name(xp, idx);
1036 if (name != NULL)
1037 return name;
1038 }
1039 return get_user_var_name(xp, ++intidx);
1040}
1041
1042#endif /* FEAT_CMDL_COMPL */
1043
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001044/*
1045 * Find internal function in table above.
1046 * Return index, or -1 if not found
1047 */
1048 int
1049find_internal_func(
1050 char_u *name) /* name of the function */
1051{
1052 int first = 0;
1053 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1054 int cmp;
1055 int x;
1056
1057 /*
1058 * Find the function name in the table. Binary search.
1059 */
1060 while (first <= last)
1061 {
1062 x = first + ((unsigned)(last - first) >> 1);
1063 cmp = STRCMP(name, functions[x].f_name);
1064 if (cmp < 0)
1065 last = x - 1;
1066 else if (cmp > 0)
1067 first = x + 1;
1068 else
1069 return x;
1070 }
1071 return -1;
1072}
1073
1074 int
1075call_internal_func(
1076 char_u *name,
1077 int argcount,
1078 typval_T *argvars,
1079 typval_T *rettv)
1080{
1081 int i;
1082
1083 i = find_internal_func(name);
1084 if (i < 0)
1085 return ERROR_UNKNOWN;
1086 if (argcount < functions[i].f_min_argc)
1087 return ERROR_TOOFEW;
1088 if (argcount > functions[i].f_max_argc)
1089 return ERROR_TOOMANY;
1090 argvars[argcount].v_type = VAR_UNKNOWN;
1091 functions[i].f_func(argvars, rettv);
1092 return ERROR_NONE;
1093}
1094
1095/*
1096 * Return TRUE for a non-zero Number and a non-empty String.
1097 */
1098 static int
1099non_zero_arg(typval_T *argvars)
1100{
1101 return ((argvars[0].v_type == VAR_NUMBER
1102 && argvars[0].vval.v_number != 0)
1103 || (argvars[0].v_type == VAR_SPECIAL
1104 && argvars[0].vval.v_number == VVAL_TRUE)
1105 || (argvars[0].v_type == VAR_STRING
1106 && argvars[0].vval.v_string != NULL
1107 && *argvars[0].vval.v_string != NUL));
1108}
1109
1110/*
1111 * Get the lnum from the first argument.
1112 * Also accepts ".", "$", etc., but that only works for the current buffer.
1113 * Returns -1 on error.
1114 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001115 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001116tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001117{
1118 typval_T rettv;
1119 linenr_T lnum;
1120
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001121 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001122 if (lnum == 0) /* no valid number, try using line() */
1123 {
1124 rettv.v_type = VAR_NUMBER;
1125 f_line(argvars, &rettv);
1126 lnum = (linenr_T)rettv.vval.v_number;
1127 clear_tv(&rettv);
1128 }
1129 return lnum;
1130}
1131
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001132/*
1133 * Get the lnum from the first argument.
1134 * Also accepts "$", then "buf" is used.
1135 * Returns 0 on error.
1136 */
1137 static linenr_T
1138tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1139{
1140 if (argvars[0].v_type == VAR_STRING
1141 && argvars[0].vval.v_string != NULL
1142 && argvars[0].vval.v_string[0] == '$'
1143 && buf != NULL)
1144 return buf->b_ml.ml_line_count;
1145 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1146}
1147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001148#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001149/*
1150 * Get the float value of "argvars[0]" into "f".
1151 * Returns FAIL when the argument is not a Number or Float.
1152 */
1153 static int
1154get_float_arg(typval_T *argvars, float_T *f)
1155{
1156 if (argvars[0].v_type == VAR_FLOAT)
1157 {
1158 *f = argvars[0].vval.v_float;
1159 return OK;
1160 }
1161 if (argvars[0].v_type == VAR_NUMBER)
1162 {
1163 *f = (float_T)argvars[0].vval.v_number;
1164 return OK;
1165 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001166 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001167 return FAIL;
1168}
1169
1170/*
1171 * "abs(expr)" function
1172 */
1173 static void
1174f_abs(typval_T *argvars, typval_T *rettv)
1175{
1176 if (argvars[0].v_type == VAR_FLOAT)
1177 {
1178 rettv->v_type = VAR_FLOAT;
1179 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1180 }
1181 else
1182 {
1183 varnumber_T n;
1184 int error = FALSE;
1185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001186 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001187 if (error)
1188 rettv->vval.v_number = -1;
1189 else if (n > 0)
1190 rettv->vval.v_number = n;
1191 else
1192 rettv->vval.v_number = -n;
1193 }
1194}
1195
1196/*
1197 * "acos()" function
1198 */
1199 static void
1200f_acos(typval_T *argvars, typval_T *rettv)
1201{
1202 float_T f = 0.0;
1203
1204 rettv->v_type = VAR_FLOAT;
1205 if (get_float_arg(argvars, &f) == OK)
1206 rettv->vval.v_float = acos(f);
1207 else
1208 rettv->vval.v_float = 0.0;
1209}
1210#endif
1211
1212/*
1213 * "add(list, item)" function
1214 */
1215 static void
1216f_add(typval_T *argvars, typval_T *rettv)
1217{
1218 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001219 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001220
1221 rettv->vval.v_number = 1; /* Default: Failed */
1222 if (argvars[0].v_type == VAR_LIST)
1223 {
1224 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001225 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001226 (char_u *)N_("add() argument"), TRUE)
1227 && list_append_tv(l, &argvars[1]) == OK)
1228 copy_tv(&argvars[0], rettv);
1229 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001230 else if (argvars[0].v_type == VAR_BLOB)
1231 {
1232 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001233 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001234 (char_u *)N_("add() argument"), TRUE))
1235 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001236 int error = FALSE;
1237 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1238
1239 if (!error)
1240 {
1241 ga_append(&b->bv_ga, (int)n);
1242 copy_tv(&argvars[0], rettv);
1243 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001244 }
1245 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001246 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001247 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001248}
1249
1250/*
1251 * "and(expr, expr)" function
1252 */
1253 static void
1254f_and(typval_T *argvars, typval_T *rettv)
1255{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001256 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1257 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001258}
1259
1260/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001261 * If there is a window for "curbuf", make it the current window.
1262 */
1263 static void
1264find_win_for_curbuf(void)
1265{
1266 wininfo_T *wip;
1267
1268 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1269 {
1270 if (wip->wi_win != NULL)
1271 {
1272 curwin = wip->wi_win;
1273 break;
1274 }
1275 }
1276}
1277
1278/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001279 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001280 */
1281 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001282set_buffer_lines(
1283 buf_T *buf,
1284 linenr_T lnum_arg,
1285 int append,
1286 typval_T *lines,
1287 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001288{
Bram Moolenaarca851592018-06-06 21:04:07 +02001289 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1290 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291 list_T *l = NULL;
1292 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001294 linenr_T append_lnum;
1295 buf_T *curbuf_save = NULL;
1296 win_T *curwin_save = NULL;
1297 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001298
Bram Moolenaarca851592018-06-06 21:04:07 +02001299 /* When using the current buffer ml_mfp will be set if needed. Useful when
1300 * setline() is used on startup. For other buffers the buffer must be
1301 * loaded. */
1302 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001303 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001304 rettv->vval.v_number = 1; /* FAIL */
1305 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001306 }
1307
Bram Moolenaarca851592018-06-06 21:04:07 +02001308 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001309 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001310 curbuf_save = curbuf;
1311 curwin_save = curwin;
1312 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001313 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001314 }
1315
1316 if (append)
1317 // appendbufline() uses the line number below which we insert
1318 append_lnum = lnum - 1;
1319 else
1320 // setbufline() uses the line number above which we insert, we only
1321 // append if it's below the last line
1322 append_lnum = curbuf->b_ml.ml_line_count;
1323
1324 if (lines->v_type == VAR_LIST)
1325 {
1326 l = lines->vval.v_list;
1327 li = l->lv_first;
1328 }
1329 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001330 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001331
1332 /* default result is zero == OK */
1333 for (;;)
1334 {
1335 if (l != NULL)
1336 {
1337 /* list argument, get next string */
1338 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001340 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001341 li = li->li_next;
1342 }
1343
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 rettv->vval.v_number = 1; /* FAIL */
1345 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1346 break;
1347
1348 /* When coming here from Insert mode, sync undo, so that this can be
1349 * undone separately from what was previously inserted. */
1350 if (u_sync_once == 2)
1351 {
1352 u_sync_once = 1; /* notify that u_sync() was called */
1353 u_sync(TRUE);
1354 }
1355
1356 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1357 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001358 // Existing line, replace it.
1359 // Removes any existing text properties.
1360 if (u_savesub(lnum) == OK && ml_replace_len(
1361 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001362 {
1363 changed_bytes(lnum, 0);
1364 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1365 check_cursor_col();
1366 rettv->vval.v_number = 0; /* OK */
1367 }
1368 }
1369 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1370 {
1371 /* append the line */
1372 ++added;
1373 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1374 rettv->vval.v_number = 0; /* OK */
1375 }
1376
1377 if (l == NULL) /* only one string argument */
1378 break;
1379 ++lnum;
1380 }
1381
1382 if (added > 0)
1383 {
1384 win_T *wp;
1385 tabpage_T *tp;
1386
1387 appended_lines_mark(append_lnum, added);
1388 FOR_ALL_TAB_WINDOWS(tp, wp)
1389 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1390 wp->w_cursor.lnum += added;
1391 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001392 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001393 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001394
1395 if (!is_curbuf)
1396 {
1397 curbuf = curbuf_save;
1398 curwin = curwin_save;
1399 }
1400}
1401
1402/*
1403 * "append(lnum, string/list)" function
1404 */
1405 static void
1406f_append(typval_T *argvars, typval_T *rettv)
1407{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001408 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001409
1410 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1411}
1412
1413/*
1414 * "appendbufline(buf, lnum, string/list)" function
1415 */
1416 static void
1417f_appendbufline(typval_T *argvars, typval_T *rettv)
1418{
1419 linenr_T lnum;
1420 buf_T *buf;
1421
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001422 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001423 if (buf == NULL)
1424 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001425 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001426 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001427 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001428 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1429 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001430}
1431
1432/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001433 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 */
1435 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001436f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001437{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001438 win_T *wp;
1439
1440 if (argvars[0].v_type == VAR_UNKNOWN)
1441 // use the current window
1442 rettv->vval.v_number = ARGCOUNT;
1443 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001444 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001445 // use the global argument list
1446 rettv->vval.v_number = GARGCOUNT;
1447 else
1448 {
1449 // use the argument list of the specified window
1450 wp = find_win_by_nr_or_id(&argvars[0]);
1451 if (wp != NULL)
1452 rettv->vval.v_number = WARGCOUNT(wp);
1453 else
1454 rettv->vval.v_number = -1;
1455 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001456}
1457
1458/*
1459 * "argidx()" function
1460 */
1461 static void
1462f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1463{
1464 rettv->vval.v_number = curwin->w_arg_idx;
1465}
1466
1467/*
1468 * "arglistid()" function
1469 */
1470 static void
1471f_arglistid(typval_T *argvars, typval_T *rettv)
1472{
1473 win_T *wp;
1474
1475 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001476 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001477 if (wp != NULL)
1478 rettv->vval.v_number = wp->w_alist->id;
1479}
1480
1481/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001482 * Get the argument list for a given window
1483 */
1484 static void
1485get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1486{
1487 int idx;
1488
1489 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1490 for (idx = 0; idx < argcount; ++idx)
1491 list_append_string(rettv->vval.v_list,
1492 alist_name(&arglist[idx]), -1);
1493}
1494
1495/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496 * "argv(nr)" function
1497 */
1498 static void
1499f_argv(typval_T *argvars, typval_T *rettv)
1500{
1501 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001502 aentry_T *arglist = NULL;
1503 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504
1505 if (argvars[0].v_type != VAR_UNKNOWN)
1506 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001507 if (argvars[1].v_type == VAR_UNKNOWN)
1508 {
1509 arglist = ARGLIST;
1510 argcount = ARGCOUNT;
1511 }
1512 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001513 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001514 {
1515 arglist = GARGLIST;
1516 argcount = GARGCOUNT;
1517 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001518 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001519 {
1520 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1521
1522 if (wp != NULL)
1523 {
1524 /* Use the argument list of the specified window */
1525 arglist = WARGLIST(wp);
1526 argcount = WARGCOUNT(wp);
1527 }
1528 }
1529
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001530 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001531 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001532 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001533 if (arglist != NULL && idx >= 0 && idx < argcount)
1534 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1535 else if (idx == -1)
1536 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001537 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001538 else
1539 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001540}
1541
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542#ifdef FEAT_FLOAT
1543/*
1544 * "asin()" function
1545 */
1546 static void
1547f_asin(typval_T *argvars, typval_T *rettv)
1548{
1549 float_T f = 0.0;
1550
1551 rettv->v_type = VAR_FLOAT;
1552 if (get_float_arg(argvars, &f) == OK)
1553 rettv->vval.v_float = asin(f);
1554 else
1555 rettv->vval.v_float = 0.0;
1556}
1557
1558/*
1559 * "atan()" function
1560 */
1561 static void
1562f_atan(typval_T *argvars, typval_T *rettv)
1563{
1564 float_T f = 0.0;
1565
1566 rettv->v_type = VAR_FLOAT;
1567 if (get_float_arg(argvars, &f) == OK)
1568 rettv->vval.v_float = atan(f);
1569 else
1570 rettv->vval.v_float = 0.0;
1571}
1572
1573/*
1574 * "atan2()" function
1575 */
1576 static void
1577f_atan2(typval_T *argvars, typval_T *rettv)
1578{
1579 float_T fx = 0.0, fy = 0.0;
1580
1581 rettv->v_type = VAR_FLOAT;
1582 if (get_float_arg(argvars, &fx) == OK
1583 && get_float_arg(&argvars[1], &fy) == OK)
1584 rettv->vval.v_float = atan2(fx, fy);
1585 else
1586 rettv->vval.v_float = 0.0;
1587}
1588#endif
1589
1590/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001591 * "balloon_show()" function
1592 */
1593#ifdef FEAT_BEVAL
1594 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001595f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1596{
1597 rettv->v_type = VAR_STRING;
1598 if (balloonEval != NULL)
1599 {
1600 if (balloonEval->msg == NULL)
1601 rettv->vval.v_string = NULL;
1602 else
1603 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1604 }
1605}
1606
1607 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001608f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1609{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001610 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001611 {
1612 if (argvars[0].v_type == VAR_LIST
1613# ifdef FEAT_GUI
1614 && !gui.in_use
1615# endif
1616 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001617 {
1618 list_T *l = argvars[0].vval.v_list;
1619
1620 // empty list removes the balloon
1621 post_balloon(balloonEval, NULL,
1622 l == NULL || l->lv_len == 0 ? NULL : l);
1623 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001624 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001625 {
1626 char_u *mesg = tv_get_string_chk(&argvars[0]);
1627
1628 if (mesg != NULL)
1629 // empty string removes the balloon
1630 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1631 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001632 }
1633}
1634
Bram Moolenaar669a8282017-11-19 20:13:05 +01001635# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001636 static void
1637f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1638{
1639 if (rettv_list_alloc(rettv) == OK)
1640 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001641 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001642
1643 if (msg != NULL)
1644 {
1645 pumitem_T *array;
1646 int size = split_message(msg, &array);
1647 int i;
1648
1649 /* Skip the first and last item, they are always empty. */
1650 for (i = 1; i < size - 1; ++i)
1651 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001652 while (size > 0)
1653 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001654 vim_free(array);
1655 }
1656 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001657}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001658# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001659#endif
1660
1661/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001662 * "browse(save, title, initdir, default)" function
1663 */
1664 static void
1665f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1666{
1667#ifdef FEAT_BROWSE
1668 int save;
1669 char_u *title;
1670 char_u *initdir;
1671 char_u *defname;
1672 char_u buf[NUMBUFLEN];
1673 char_u buf2[NUMBUFLEN];
1674 int error = FALSE;
1675
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001676 save = (int)tv_get_number_chk(&argvars[0], &error);
1677 title = tv_get_string_chk(&argvars[1]);
1678 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1679 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001680
1681 if (error || title == NULL || initdir == NULL || defname == NULL)
1682 rettv->vval.v_string = NULL;
1683 else
1684 rettv->vval.v_string =
1685 do_browse(save ? BROWSE_SAVE : 0,
1686 title, defname, NULL, initdir, NULL, curbuf);
1687#else
1688 rettv->vval.v_string = NULL;
1689#endif
1690 rettv->v_type = VAR_STRING;
1691}
1692
1693/*
1694 * "browsedir(title, initdir)" function
1695 */
1696 static void
1697f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1698{
1699#ifdef FEAT_BROWSE
1700 char_u *title;
1701 char_u *initdir;
1702 char_u buf[NUMBUFLEN];
1703
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001704 title = tv_get_string_chk(&argvars[0]);
1705 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001706
1707 if (title == NULL || initdir == NULL)
1708 rettv->vval.v_string = NULL;
1709 else
1710 rettv->vval.v_string = do_browse(BROWSE_DIR,
1711 title, NULL, NULL, initdir, NULL, curbuf);
1712#else
1713 rettv->vval.v_string = NULL;
1714#endif
1715 rettv->v_type = VAR_STRING;
1716}
1717
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718/*
1719 * Find a buffer by number or exact name.
1720 */
1721 static buf_T *
1722find_buffer(typval_T *avar)
1723{
1724 buf_T *buf = NULL;
1725
1726 if (avar->v_type == VAR_NUMBER)
1727 buf = buflist_findnr((int)avar->vval.v_number);
1728 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1729 {
1730 buf = buflist_findname_exp(avar->vval.v_string);
1731 if (buf == NULL)
1732 {
1733 /* No full path name match, try a match with a URL or a "nofile"
1734 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001735 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001736 if (buf->b_fname != NULL
1737 && (path_with_url(buf->b_fname)
1738#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001739 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001740#endif
1741 )
1742 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1743 break;
1744 }
1745 }
1746 return buf;
1747}
1748
1749/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001750 * "bufadd(expr)" function
1751 */
1752 static void
1753f_bufadd(typval_T *argvars, typval_T *rettv)
1754{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001755 char_u *name = tv_get_string(&argvars[0]);
1756
1757 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001758}
1759
1760/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001761 * "bufexists(expr)" function
1762 */
1763 static void
1764f_bufexists(typval_T *argvars, typval_T *rettv)
1765{
1766 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1767}
1768
1769/*
1770 * "buflisted(expr)" function
1771 */
1772 static void
1773f_buflisted(typval_T *argvars, typval_T *rettv)
1774{
1775 buf_T *buf;
1776
1777 buf = find_buffer(&argvars[0]);
1778 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1779}
1780
1781/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001782 * "bufload(expr)" function
1783 */
1784 static void
1785f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1786{
1787 buf_T *buf = get_buf_arg(&argvars[0]);
1788
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001789 if (buf != NULL)
1790 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001791}
1792
1793/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794 * "bufloaded(expr)" function
1795 */
1796 static void
1797f_bufloaded(typval_T *argvars, typval_T *rettv)
1798{
1799 buf_T *buf;
1800
1801 buf = find_buffer(&argvars[0]);
1802 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1803}
1804
1805 buf_T *
1806buflist_find_by_name(char_u *name, int curtab_only)
1807{
1808 int save_magic;
1809 char_u *save_cpo;
1810 buf_T *buf;
1811
1812 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1813 save_magic = p_magic;
1814 p_magic = TRUE;
1815 save_cpo = p_cpo;
1816 p_cpo = (char_u *)"";
1817
1818 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1819 TRUE, FALSE, curtab_only));
1820
1821 p_magic = save_magic;
1822 p_cpo = save_cpo;
1823 return buf;
1824}
1825
1826/*
1827 * Get buffer by number or pattern.
1828 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001829 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001830tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001831{
1832 char_u *name = tv->vval.v_string;
1833 buf_T *buf;
1834
1835 if (tv->v_type == VAR_NUMBER)
1836 return buflist_findnr((int)tv->vval.v_number);
1837 if (tv->v_type != VAR_STRING)
1838 return NULL;
1839 if (name == NULL || *name == NUL)
1840 return curbuf;
1841 if (name[0] == '$' && name[1] == NUL)
1842 return lastbuf;
1843
1844 buf = buflist_find_by_name(name, curtab_only);
1845
1846 /* If not found, try expanding the name, like done for bufexists(). */
1847 if (buf == NULL)
1848 buf = find_buffer(tv);
1849
1850 return buf;
1851}
1852
1853/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001854 * Get the buffer from "arg" and give an error and return NULL if it is not
1855 * valid.
1856 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001857 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001858get_buf_arg(typval_T *arg)
1859{
1860 buf_T *buf;
1861
1862 ++emsg_off;
1863 buf = tv_get_buf(arg, FALSE);
1864 --emsg_off;
1865 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001866 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001867 return buf;
1868}
1869
1870/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001871 * "bufname(expr)" function
1872 */
1873 static void
1874f_bufname(typval_T *argvars, typval_T *rettv)
1875{
1876 buf_T *buf;
1877
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001878 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001879 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001880 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001881 rettv->v_type = VAR_STRING;
1882 if (buf != NULL && buf->b_fname != NULL)
1883 rettv->vval.v_string = vim_strsave(buf->b_fname);
1884 else
1885 rettv->vval.v_string = NULL;
1886 --emsg_off;
1887}
1888
1889/*
1890 * "bufnr(expr)" function
1891 */
1892 static void
1893f_bufnr(typval_T *argvars, typval_T *rettv)
1894{
1895 buf_T *buf;
1896 int error = FALSE;
1897 char_u *name;
1898
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001899 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001901 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 --emsg_off;
1903
1904 /* If the buffer isn't found and the second argument is not zero create a
1905 * new buffer. */
1906 if (buf == NULL
1907 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001908 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001909 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001910 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001911 && !error)
1912 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1913
1914 if (buf != NULL)
1915 rettv->vval.v_number = buf->b_fnum;
1916 else
1917 rettv->vval.v_number = -1;
1918}
1919
1920 static void
1921buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1922{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 win_T *wp;
1924 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001925 buf_T *buf;
1926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001927 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001929 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001930 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001931 {
1932 ++winnr;
1933 if (wp->w_buffer == buf)
1934 break;
1935 }
1936 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001937 --emsg_off;
1938}
1939
1940/*
1941 * "bufwinid(nr)" function
1942 */
1943 static void
1944f_bufwinid(typval_T *argvars, typval_T *rettv)
1945{
1946 buf_win_common(argvars, rettv, FALSE);
1947}
1948
1949/*
1950 * "bufwinnr(nr)" function
1951 */
1952 static void
1953f_bufwinnr(typval_T *argvars, typval_T *rettv)
1954{
1955 buf_win_common(argvars, rettv, TRUE);
1956}
1957
1958/*
1959 * "byte2line(byte)" function
1960 */
1961 static void
1962f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1963{
1964#ifndef FEAT_BYTEOFF
1965 rettv->vval.v_number = -1;
1966#else
1967 long boff = 0;
1968
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001969 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001970 if (boff < 0)
1971 rettv->vval.v_number = -1;
1972 else
1973 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1974 (linenr_T)0, &boff);
1975#endif
1976}
1977
1978 static void
1979byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1980{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001981 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 char_u *str;
1983 varnumber_T idx;
1984
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001985 str = tv_get_string_chk(&argvars[0]);
1986 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 rettv->vval.v_number = -1;
1988 if (str == NULL || idx < 0)
1989 return;
1990
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 t = str;
1992 for ( ; idx > 0; idx--)
1993 {
1994 if (*t == NUL) /* EOL reached */
1995 return;
1996 if (enc_utf8 && comp)
1997 t += utf_ptr2len(t);
1998 else
1999 t += (*mb_ptr2len)(t);
2000 }
2001 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002}
2003
2004/*
2005 * "byteidx()" function
2006 */
2007 static void
2008f_byteidx(typval_T *argvars, typval_T *rettv)
2009{
2010 byteidx(argvars, rettv, FALSE);
2011}
2012
2013/*
2014 * "byteidxcomp()" function
2015 */
2016 static void
2017f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2018{
2019 byteidx(argvars, rettv, TRUE);
2020}
2021
2022/*
2023 * "call(func, arglist [, dict])" function
2024 */
2025 static void
2026f_call(typval_T *argvars, typval_T *rettv)
2027{
2028 char_u *func;
2029 partial_T *partial = NULL;
2030 dict_T *selfdict = NULL;
2031
2032 if (argvars[1].v_type != VAR_LIST)
2033 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002034 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035 return;
2036 }
2037 if (argvars[1].vval.v_list == NULL)
2038 return;
2039
2040 if (argvars[0].v_type == VAR_FUNC)
2041 func = argvars[0].vval.v_string;
2042 else if (argvars[0].v_type == VAR_PARTIAL)
2043 {
2044 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002045 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 }
2047 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002048 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 if (*func == NUL)
2050 return; /* type error or empty name */
2051
2052 if (argvars[2].v_type != VAR_UNKNOWN)
2053 {
2054 if (argvars[2].v_type != VAR_DICT)
2055 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002056 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002057 return;
2058 }
2059 selfdict = argvars[2].vval.v_dict;
2060 }
2061
2062 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2063}
2064
2065#ifdef FEAT_FLOAT
2066/*
2067 * "ceil({float})" function
2068 */
2069 static void
2070f_ceil(typval_T *argvars, typval_T *rettv)
2071{
2072 float_T f = 0.0;
2073
2074 rettv->v_type = VAR_FLOAT;
2075 if (get_float_arg(argvars, &f) == OK)
2076 rettv->vval.v_float = ceil(f);
2077 else
2078 rettv->vval.v_float = 0.0;
2079}
2080#endif
2081
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082/*
2083 * "changenr()" function
2084 */
2085 static void
2086f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2087{
2088 rettv->vval.v_number = curbuf->b_u_seq_cur;
2089}
2090
2091/*
2092 * "char2nr(string)" function
2093 */
2094 static void
2095f_char2nr(typval_T *argvars, typval_T *rettv)
2096{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 if (has_mbyte)
2098 {
2099 int utf8 = 0;
2100
2101 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002102 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103
2104 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002105 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002107 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002108 }
2109 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002110 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002111}
2112
2113/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002114 * "chdir(dir)" function
2115 */
2116 static void
2117f_chdir(typval_T *argvars, typval_T *rettv)
2118{
2119 char_u *cwd;
2120 cdscope_T scope = CDSCOPE_GLOBAL;
2121
2122 rettv->v_type = VAR_STRING;
2123 rettv->vval.v_string = NULL;
2124
2125 if (argvars[0].v_type != VAR_STRING)
2126 return;
2127
2128 // Return the current directory
2129 cwd = alloc(MAXPATHL);
2130 if (cwd != NULL)
2131 {
2132 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2133 {
2134#ifdef BACKSLASH_IN_FILENAME
2135 slash_adjust(cwd);
2136#endif
2137 rettv->vval.v_string = vim_strsave(cwd);
2138 }
2139 vim_free(cwd);
2140 }
2141
2142 if (curwin->w_localdir != NULL)
2143 scope = CDSCOPE_WINDOW;
2144 else if (curtab->tp_localdir != NULL)
2145 scope = CDSCOPE_TABPAGE;
2146
2147 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2148 // Directory change failed
2149 VIM_CLEAR(rettv->vval.v_string);
2150}
2151
2152/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 * "cindent(lnum)" function
2154 */
2155 static void
2156f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2157{
2158#ifdef FEAT_CINDENT
2159 pos_T pos;
2160 linenr_T lnum;
2161
2162 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002163 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2165 {
2166 curwin->w_cursor.lnum = lnum;
2167 rettv->vval.v_number = get_c_indent();
2168 curwin->w_cursor = pos;
2169 }
2170 else
2171#endif
2172 rettv->vval.v_number = -1;
2173}
2174
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002175 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002176get_optional_window(typval_T *argvars, int idx)
2177{
2178 win_T *win = curwin;
2179
2180 if (argvars[idx].v_type != VAR_UNKNOWN)
2181 {
2182 win = find_win_by_nr_or_id(&argvars[idx]);
2183 if (win == NULL)
2184 {
2185 emsg(_(e_invalwindow));
2186 return NULL;
2187 }
2188 }
2189 return win;
2190}
2191
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002193 * "col(string)" function
2194 */
2195 static void
2196f_col(typval_T *argvars, typval_T *rettv)
2197{
2198 colnr_T col = 0;
2199 pos_T *fp;
2200 int fnum = curbuf->b_fnum;
2201
2202 fp = var2fpos(&argvars[0], FALSE, &fnum);
2203 if (fp != NULL && fnum == curbuf->b_fnum)
2204 {
2205 if (fp->col == MAXCOL)
2206 {
2207 /* '> can be MAXCOL, get the length of the line then */
2208 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2209 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2210 else
2211 col = MAXCOL;
2212 }
2213 else
2214 {
2215 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 /* col(".") when the cursor is on the NUL at the end of the line
2217 * because of "coladd" can be seen as an extra column. */
2218 if (virtual_active() && fp == &curwin->w_cursor)
2219 {
2220 char_u *p = ml_get_cursor();
2221
2222 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2223 curwin->w_virtcol - curwin->w_cursor.coladd))
2224 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002225 int l;
2226
2227 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2228 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002229 }
2230 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002231 }
2232 }
2233 rettv->vval.v_number = col;
2234}
2235
2236#if defined(FEAT_INS_EXPAND)
2237/*
2238 * "complete()" function
2239 */
2240 static void
2241f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2242{
2243 int startcol;
2244
2245 if ((State & INSERT) == 0)
2246 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002247 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002248 return;
2249 }
2250
2251 /* Check for undo allowed here, because if something was already inserted
2252 * the line was already saved for undo and this check isn't done. */
2253 if (!undo_allowed())
2254 return;
2255
2256 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2257 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002258 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002259 return;
2260 }
2261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002262 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263 if (startcol <= 0)
2264 return;
2265
2266 set_completion(startcol - 1, argvars[1].vval.v_list);
2267}
2268
2269/*
2270 * "complete_add()" function
2271 */
2272 static void
2273f_complete_add(typval_T *argvars, typval_T *rettv)
2274{
2275 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2276}
2277
2278/*
2279 * "complete_check()" function
2280 */
2281 static void
2282f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2283{
2284 int saved = RedrawingDisabled;
2285
2286 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002287 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002288 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002289 RedrawingDisabled = saved;
2290}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002291
2292/*
2293 * "complete_info()" function
2294 */
2295 static void
2296f_complete_info(typval_T *argvars, typval_T *rettv)
2297{
2298 list_T *what_list = NULL;
2299
2300 if (rettv_dict_alloc(rettv) != OK)
2301 return;
2302
2303 if (argvars[0].v_type != VAR_UNKNOWN)
2304 {
2305 if (argvars[0].v_type != VAR_LIST)
2306 {
2307 emsg(_(e_listreq));
2308 return;
2309 }
2310 what_list = argvars[0].vval.v_list;
2311 }
2312 get_complete_info(what_list, rettv->vval.v_dict);
2313}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002314#endif
2315
2316/*
2317 * "confirm(message, buttons[, default [, type]])" function
2318 */
2319 static void
2320f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2321{
2322#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2323 char_u *message;
2324 char_u *buttons = NULL;
2325 char_u buf[NUMBUFLEN];
2326 char_u buf2[NUMBUFLEN];
2327 int def = 1;
2328 int type = VIM_GENERIC;
2329 char_u *typestr;
2330 int error = FALSE;
2331
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002332 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002333 if (message == NULL)
2334 error = TRUE;
2335 if (argvars[1].v_type != VAR_UNKNOWN)
2336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002337 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002338 if (buttons == NULL)
2339 error = TRUE;
2340 if (argvars[2].v_type != VAR_UNKNOWN)
2341 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002342 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 if (argvars[3].v_type != VAR_UNKNOWN)
2344 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002345 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002346 if (typestr == NULL)
2347 error = TRUE;
2348 else
2349 {
2350 switch (TOUPPER_ASC(*typestr))
2351 {
2352 case 'E': type = VIM_ERROR; break;
2353 case 'Q': type = VIM_QUESTION; break;
2354 case 'I': type = VIM_INFO; break;
2355 case 'W': type = VIM_WARNING; break;
2356 case 'G': type = VIM_GENERIC; break;
2357 }
2358 }
2359 }
2360 }
2361 }
2362
2363 if (buttons == NULL || *buttons == NUL)
2364 buttons = (char_u *)_("&Ok");
2365
2366 if (!error)
2367 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2368 def, NULL, FALSE);
2369#endif
2370}
2371
2372/*
2373 * "copy()" function
2374 */
2375 static void
2376f_copy(typval_T *argvars, typval_T *rettv)
2377{
2378 item_copy(&argvars[0], rettv, FALSE, 0);
2379}
2380
2381#ifdef FEAT_FLOAT
2382/*
2383 * "cos()" function
2384 */
2385 static void
2386f_cos(typval_T *argvars, typval_T *rettv)
2387{
2388 float_T f = 0.0;
2389
2390 rettv->v_type = VAR_FLOAT;
2391 if (get_float_arg(argvars, &f) == OK)
2392 rettv->vval.v_float = cos(f);
2393 else
2394 rettv->vval.v_float = 0.0;
2395}
2396
2397/*
2398 * "cosh()" function
2399 */
2400 static void
2401f_cosh(typval_T *argvars, typval_T *rettv)
2402{
2403 float_T f = 0.0;
2404
2405 rettv->v_type = VAR_FLOAT;
2406 if (get_float_arg(argvars, &f) == OK)
2407 rettv->vval.v_float = cosh(f);
2408 else
2409 rettv->vval.v_float = 0.0;
2410}
2411#endif
2412
2413/*
2414 * "count()" function
2415 */
2416 static void
2417f_count(typval_T *argvars, typval_T *rettv)
2418{
2419 long n = 0;
2420 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002421 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422
Bram Moolenaar9966b212017-07-28 16:46:57 +02002423 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002424 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002425
2426 if (argvars[0].v_type == VAR_STRING)
2427 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002428 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002429 char_u *p = argvars[0].vval.v_string;
2430 char_u *next;
2431
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002432 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002433 {
2434 if (ic)
2435 {
2436 size_t len = STRLEN(expr);
2437
2438 while (*p != NUL)
2439 {
2440 if (MB_STRNICMP(p, expr, len) == 0)
2441 {
2442 ++n;
2443 p += len;
2444 }
2445 else
2446 MB_PTR_ADV(p);
2447 }
2448 }
2449 else
2450 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2451 != NULL)
2452 {
2453 ++n;
2454 p = next + STRLEN(expr);
2455 }
2456 }
2457
2458 }
2459 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 {
2461 listitem_T *li;
2462 list_T *l;
2463 long idx;
2464
2465 if ((l = argvars[0].vval.v_list) != NULL)
2466 {
2467 li = l->lv_first;
2468 if (argvars[2].v_type != VAR_UNKNOWN)
2469 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470 if (argvars[3].v_type != VAR_UNKNOWN)
2471 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002472 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002473 if (!error)
2474 {
2475 li = list_find(l, idx);
2476 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002477 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002478 }
2479 }
2480 if (error)
2481 li = NULL;
2482 }
2483
2484 for ( ; li != NULL; li = li->li_next)
2485 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2486 ++n;
2487 }
2488 }
2489 else if (argvars[0].v_type == VAR_DICT)
2490 {
2491 int todo;
2492 dict_T *d;
2493 hashitem_T *hi;
2494
2495 if ((d = argvars[0].vval.v_dict) != NULL)
2496 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002497 if (argvars[2].v_type != VAR_UNKNOWN)
2498 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002499 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002500 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 }
2502
2503 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2504 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2505 {
2506 if (!HASHITEM_EMPTY(hi))
2507 {
2508 --todo;
2509 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2510 ++n;
2511 }
2512 }
2513 }
2514 }
2515 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002516 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 rettv->vval.v_number = n;
2518}
2519
2520/*
2521 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2522 *
2523 * Checks the existence of a cscope connection.
2524 */
2525 static void
2526f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2527{
2528#ifdef FEAT_CSCOPE
2529 int num = 0;
2530 char_u *dbpath = NULL;
2531 char_u *prepend = NULL;
2532 char_u buf[NUMBUFLEN];
2533
2534 if (argvars[0].v_type != VAR_UNKNOWN
2535 && argvars[1].v_type != VAR_UNKNOWN)
2536 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002537 num = (int)tv_get_number(&argvars[0]);
2538 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002540 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 }
2542
2543 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2544#endif
2545}
2546
2547/*
2548 * "cursor(lnum, col)" function, or
2549 * "cursor(list)"
2550 *
2551 * Moves the cursor to the specified line and column.
2552 * Returns 0 when the position could be set, -1 otherwise.
2553 */
2554 static void
2555f_cursor(typval_T *argvars, typval_T *rettv)
2556{
2557 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002558 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559 int set_curswant = TRUE;
2560
2561 rettv->vval.v_number = -1;
2562 if (argvars[1].v_type == VAR_UNKNOWN)
2563 {
2564 pos_T pos;
2565 colnr_T curswant = -1;
2566
2567 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2568 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002569 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002570 return;
2571 }
2572 line = pos.lnum;
2573 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002575 if (curswant >= 0)
2576 {
2577 curwin->w_curswant = curswant - 1;
2578 set_curswant = FALSE;
2579 }
2580 }
2581 else
2582 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002583 line = tv_get_lnum(argvars);
2584 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002586 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002588 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002589 return; /* type error; errmsg already given */
2590 if (line > 0)
2591 curwin->w_cursor.lnum = line;
2592 if (col > 0)
2593 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002595
2596 /* Make sure the cursor is in a valid position. */
2597 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002598 /* Correct cursor for multi-byte character. */
2599 if (has_mbyte)
2600 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601
2602 curwin->w_set_curswant = set_curswant;
2603 rettv->vval.v_number = 0;
2604}
2605
Bram Moolenaar4f974752019-02-17 17:44:42 +01002606#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002607/*
2608 * "debugbreak()" function
2609 */
2610 static void
2611f_debugbreak(typval_T *argvars, typval_T *rettv)
2612{
2613 int pid;
2614
2615 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002616 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002617 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002618 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002619 else
2620 {
2621 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2622
2623 if (hProcess != NULL)
2624 {
2625 DebugBreakProcess(hProcess);
2626 CloseHandle(hProcess);
2627 rettv->vval.v_number = OK;
2628 }
2629 }
2630}
2631#endif
2632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633/*
2634 * "deepcopy()" function
2635 */
2636 static void
2637f_deepcopy(typval_T *argvars, typval_T *rettv)
2638{
2639 int noref = 0;
2640 int copyID;
2641
2642 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002643 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002644 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002645 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002646 else
2647 {
2648 copyID = get_copyID();
2649 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2650 }
2651}
2652
2653/*
2654 * "delete()" function
2655 */
2656 static void
2657f_delete(typval_T *argvars, typval_T *rettv)
2658{
2659 char_u nbuf[NUMBUFLEN];
2660 char_u *name;
2661 char_u *flags;
2662
2663 rettv->vval.v_number = -1;
2664 if (check_restricted() || check_secure())
2665 return;
2666
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002667 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002668 if (name == NULL || *name == NUL)
2669 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002670 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671 return;
2672 }
2673
2674 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002675 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002676 else
2677 flags = (char_u *)"";
2678
2679 if (*flags == NUL)
2680 /* delete a file */
2681 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2682 else if (STRCMP(flags, "d") == 0)
2683 /* delete an empty directory */
2684 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2685 else if (STRCMP(flags, "rf") == 0)
2686 /* delete a directory recursively */
2687 rettv->vval.v_number = delete_recursive(name);
2688 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002689 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690}
2691
2692/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002693 * "deletebufline()" function
2694 */
2695 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002696f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002697{
2698 buf_T *buf;
2699 linenr_T first, last;
2700 linenr_T lnum;
2701 long count;
2702 int is_curbuf;
2703 buf_T *curbuf_save = NULL;
2704 win_T *curwin_save = NULL;
2705 tabpage_T *tp;
2706 win_T *wp;
2707
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002708 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002709 if (buf == NULL)
2710 {
2711 rettv->vval.v_number = 1; /* FAIL */
2712 return;
2713 }
2714 is_curbuf = buf == curbuf;
2715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002716 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002717 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002718 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002719 else
2720 last = first;
2721
2722 if (buf->b_ml.ml_mfp == NULL || first < 1
2723 || first > buf->b_ml.ml_line_count || last < first)
2724 {
2725 rettv->vval.v_number = 1; /* FAIL */
2726 return;
2727 }
2728
2729 if (!is_curbuf)
2730 {
2731 curbuf_save = curbuf;
2732 curwin_save = curwin;
2733 curbuf = buf;
2734 find_win_for_curbuf();
2735 }
2736 if (last > curbuf->b_ml.ml_line_count)
2737 last = curbuf->b_ml.ml_line_count;
2738 count = last - first + 1;
2739
2740 // When coming here from Insert mode, sync undo, so that this can be
2741 // undone separately from what was previously inserted.
2742 if (u_sync_once == 2)
2743 {
2744 u_sync_once = 1; // notify that u_sync() was called
2745 u_sync(TRUE);
2746 }
2747
2748 if (u_save(first - 1, last + 1) == FAIL)
2749 {
2750 rettv->vval.v_number = 1; /* FAIL */
2751 return;
2752 }
2753
2754 for (lnum = first; lnum <= last; ++lnum)
2755 ml_delete(first, TRUE);
2756
2757 FOR_ALL_TAB_WINDOWS(tp, wp)
2758 if (wp->w_buffer == buf)
2759 {
2760 if (wp->w_cursor.lnum > last)
2761 wp->w_cursor.lnum -= count;
2762 else if (wp->w_cursor.lnum> first)
2763 wp->w_cursor.lnum = first;
2764 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2765 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2766 }
2767 check_cursor_col();
2768 deleted_lines_mark(first, count);
2769
2770 if (!is_curbuf)
2771 {
2772 curbuf = curbuf_save;
2773 curwin = curwin_save;
2774 }
2775}
2776
2777/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 * "did_filetype()" function
2779 */
2780 static void
2781f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2782{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784}
2785
2786/*
2787 * "diff_filler()" function
2788 */
2789 static void
2790f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2791{
2792#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002793 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002794#endif
2795}
2796
2797/*
2798 * "diff_hlID()" function
2799 */
2800 static void
2801f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2802{
2803#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002804 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002806 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002807 static int fnum = 0;
2808 static int change_start = 0;
2809 static int change_end = 0;
2810 static hlf_T hlID = (hlf_T)0;
2811 int filler_lines;
2812 int col;
2813
2814 if (lnum < 0) /* ignore type error in {lnum} arg */
2815 lnum = 0;
2816 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002817 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002818 || fnum != curbuf->b_fnum)
2819 {
2820 /* New line, buffer, change: need to get the values. */
2821 filler_lines = diff_check(curwin, lnum);
2822 if (filler_lines < 0)
2823 {
2824 if (filler_lines == -1)
2825 {
2826 change_start = MAXCOL;
2827 change_end = -1;
2828 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2829 hlID = HLF_ADD; /* added line */
2830 else
2831 hlID = HLF_CHD; /* changed line */
2832 }
2833 else
2834 hlID = HLF_ADD; /* added line */
2835 }
2836 else
2837 hlID = (hlf_T)0;
2838 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002839 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 fnum = curbuf->b_fnum;
2841 }
2842
2843 if (hlID == HLF_CHD || hlID == HLF_TXD)
2844 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002845 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002846 if (col >= change_start && col <= change_end)
2847 hlID = HLF_TXD; /* changed text */
2848 else
2849 hlID = HLF_CHD; /* changed line */
2850 }
2851 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2852#endif
2853}
2854
2855/*
2856 * "empty({expr})" function
2857 */
2858 static void
2859f_empty(typval_T *argvars, typval_T *rettv)
2860{
2861 int n = FALSE;
2862
2863 switch (argvars[0].v_type)
2864 {
2865 case VAR_STRING:
2866 case VAR_FUNC:
2867 n = argvars[0].vval.v_string == NULL
2868 || *argvars[0].vval.v_string == NUL;
2869 break;
2870 case VAR_PARTIAL:
2871 n = FALSE;
2872 break;
2873 case VAR_NUMBER:
2874 n = argvars[0].vval.v_number == 0;
2875 break;
2876 case VAR_FLOAT:
2877#ifdef FEAT_FLOAT
2878 n = argvars[0].vval.v_float == 0.0;
2879 break;
2880#endif
2881 case VAR_LIST:
2882 n = argvars[0].vval.v_list == NULL
2883 || argvars[0].vval.v_list->lv_first == NULL;
2884 break;
2885 case VAR_DICT:
2886 n = argvars[0].vval.v_dict == NULL
2887 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2888 break;
2889 case VAR_SPECIAL:
2890 n = argvars[0].vval.v_number != VVAL_TRUE;
2891 break;
2892
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002893 case VAR_BLOB:
2894 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002895 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2896 break;
2897
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002898 case VAR_JOB:
2899#ifdef FEAT_JOB_CHANNEL
2900 n = argvars[0].vval.v_job == NULL
2901 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2902 break;
2903#endif
2904 case VAR_CHANNEL:
2905#ifdef FEAT_JOB_CHANNEL
2906 n = argvars[0].vval.v_channel == NULL
2907 || !channel_is_open(argvars[0].vval.v_channel);
2908 break;
2909#endif
2910 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002911 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 n = TRUE;
2913 break;
2914 }
2915
2916 rettv->vval.v_number = n;
2917}
2918
2919/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002920 * "environ()" function
2921 */
2922 static void
2923f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2924{
2925#if !defined(AMIGA)
2926 int i = 0;
2927 char_u *entry, *value;
2928# ifdef MSWIN
2929 extern wchar_t **_wenviron;
2930# else
2931 extern char **environ;
2932# endif
2933
2934 if (rettv_dict_alloc(rettv) != OK)
2935 return;
2936
2937# ifdef MSWIN
2938 if (*_wenviron == NULL)
2939 return;
2940# else
2941 if (*environ == NULL)
2942 return;
2943# endif
2944
2945 for (i = 0; ; ++i)
2946 {
2947# ifdef MSWIN
2948 short_u *p;
2949
2950 if ((p = (short_u *)_wenviron[i]) == NULL)
2951 return;
2952 entry = utf16_to_enc(p, NULL);
2953# else
2954 if ((entry = (char_u *)environ[i]) == NULL)
2955 return;
2956 entry = vim_strsave(entry);
2957# endif
2958 if (entry == NULL) // out of memory
2959 return;
2960 if ((value = vim_strchr(entry, '=')) == NULL)
2961 {
2962 vim_free(entry);
2963 continue;
2964 }
2965 *value++ = NUL;
2966 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2967 vim_free(entry);
2968 }
2969#endif
2970}
2971
2972/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002973 * "escape({string}, {chars})" function
2974 */
2975 static void
2976f_escape(typval_T *argvars, typval_T *rettv)
2977{
2978 char_u buf[NUMBUFLEN];
2979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002980 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2981 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002982 rettv->v_type = VAR_STRING;
2983}
2984
2985/*
2986 * "eval()" function
2987 */
2988 static void
2989f_eval(typval_T *argvars, typval_T *rettv)
2990{
2991 char_u *s, *p;
2992
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002993 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002994 if (s != NULL)
2995 s = skipwhite(s);
2996
2997 p = s;
2998 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2999 {
3000 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003001 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003002 need_clr_eos = FALSE;
3003 rettv->v_type = VAR_NUMBER;
3004 rettv->vval.v_number = 0;
3005 }
3006 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003007 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003008}
3009
3010/*
3011 * "eventhandler()" function
3012 */
3013 static void
3014f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3015{
3016 rettv->vval.v_number = vgetc_busy;
3017}
3018
3019/*
3020 * "executable()" function
3021 */
3022 static void
3023f_executable(typval_T *argvars, typval_T *rettv)
3024{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003025 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003026
3027 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003028 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029}
3030
3031static garray_T redir_execute_ga;
3032
3033/*
3034 * Append "value[value_len]" to the execute() output.
3035 */
3036 void
3037execute_redir_str(char_u *value, int value_len)
3038{
3039 int len;
3040
3041 if (value_len == -1)
3042 len = (int)STRLEN(value); /* Append the entire string */
3043 else
3044 len = value_len; /* Append only "value_len" characters */
3045 if (ga_grow(&redir_execute_ga, len) == OK)
3046 {
3047 mch_memmove((char *)redir_execute_ga.ga_data
3048 + redir_execute_ga.ga_len, value, len);
3049 redir_execute_ga.ga_len += len;
3050 }
3051}
3052
3053/*
3054 * Get next line from a list.
3055 * Called by do_cmdline() to get the next line.
3056 * Returns allocated string, or NULL for end of function.
3057 */
3058
3059 static char_u *
3060get_list_line(
3061 int c UNUSED,
3062 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003063 int indent UNUSED,
3064 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065{
3066 listitem_T **p = (listitem_T **)cookie;
3067 listitem_T *item = *p;
3068 char_u buf[NUMBUFLEN];
3069 char_u *s;
3070
3071 if (item == NULL)
3072 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003073 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003074 *p = item->li_next;
3075 return s == NULL ? NULL : vim_strsave(s);
3076}
3077
3078/*
3079 * "execute()" function
3080 */
3081 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003082execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083{
3084 char_u *cmd = NULL;
3085 list_T *list = NULL;
3086 int save_msg_silent = msg_silent;
3087 int save_emsg_silent = emsg_silent;
3088 int save_emsg_noredir = emsg_noredir;
3089 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003090 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003091 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003092 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003093 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003094
3095 rettv->vval.v_string = NULL;
3096 rettv->v_type = VAR_STRING;
3097
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003098 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003100 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 if (list == NULL || list->lv_first == NULL)
3102 /* empty list, no commands, empty output */
3103 return;
3104 ++list->lv_refcount;
3105 }
3106 else
3107 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003108 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003109 if (cmd == NULL)
3110 return;
3111 }
3112
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003113 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003114 {
3115 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003116 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117
3118 if (s == NULL)
3119 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003120 if (*s == NUL)
3121 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003122 if (STRNCMP(s, "silent", 6) == 0)
3123 ++msg_silent;
3124 if (STRCMP(s, "silent!") == 0)
3125 {
3126 emsg_silent = TRUE;
3127 emsg_noredir = TRUE;
3128 }
3129 }
3130 else
3131 ++msg_silent;
3132
3133 if (redir_execute)
3134 save_ga = redir_execute_ga;
3135 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3136 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003137 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003138 if (!echo_output)
3139 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003140
3141 if (cmd != NULL)
3142 do_cmdline_cmd(cmd);
3143 else
3144 {
3145 listitem_T *item = list->lv_first;
3146
3147 do_cmdline(NULL, get_list_line, (void *)&item,
3148 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3149 --list->lv_refcount;
3150 }
3151
Bram Moolenaard297f352017-01-29 20:31:21 +01003152 /* Need to append a NUL to the result. */
3153 if (ga_grow(&redir_execute_ga, 1) == OK)
3154 {
3155 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3156 rettv->vval.v_string = redir_execute_ga.ga_data;
3157 }
3158 else
3159 {
3160 ga_clear(&redir_execute_ga);
3161 rettv->vval.v_string = NULL;
3162 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003163 msg_silent = save_msg_silent;
3164 emsg_silent = save_emsg_silent;
3165 emsg_noredir = save_emsg_noredir;
3166
3167 redir_execute = save_redir_execute;
3168 if (redir_execute)
3169 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003170 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003171
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003172 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003173 if (echo_output)
3174 // When not working silently: put it in column zero. A following
3175 // "echon" will overwrite the message, unavoidably.
3176 msg_col = 0;
3177 else
3178 // When working silently: Put it back where it was, since nothing
3179 // should have been written.
3180 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003181}
3182
3183/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003184 * "execute()" function
3185 */
3186 static void
3187f_execute(typval_T *argvars, typval_T *rettv)
3188{
3189 execute_common(argvars, rettv, 0);
3190}
3191
3192/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003193 * "exepath()" function
3194 */
3195 static void
3196f_exepath(typval_T *argvars, typval_T *rettv)
3197{
3198 char_u *p = NULL;
3199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003200 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003201 rettv->v_type = VAR_STRING;
3202 rettv->vval.v_string = p;
3203}
3204
3205/*
3206 * "exists()" function
3207 */
3208 static void
3209f_exists(typval_T *argvars, typval_T *rettv)
3210{
3211 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003212 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003214 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215 if (*p == '$') /* environment variable */
3216 {
3217 /* first try "normal" environment variables (fast) */
3218 if (mch_getenv(p + 1) != NULL)
3219 n = TRUE;
3220 else
3221 {
3222 /* try expanding things like $VIM and ${HOME} */
3223 p = expand_env_save(p);
3224 if (p != NULL && *p != '$')
3225 n = TRUE;
3226 vim_free(p);
3227 }
3228 }
3229 else if (*p == '&' || *p == '+') /* option */
3230 {
3231 n = (get_option_tv(&p, NULL, TRUE) == OK);
3232 if (*skipwhite(p) != NUL)
3233 n = FALSE; /* trailing garbage */
3234 }
3235 else if (*p == '*') /* internal or user defined function */
3236 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003237 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 }
3239 else if (*p == ':')
3240 {
3241 n = cmd_exists(p + 1);
3242 }
3243 else if (*p == '#')
3244 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003245 if (p[1] == '#')
3246 n = autocmd_supported(p + 2);
3247 else
3248 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003249 }
3250 else /* internal variable */
3251 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003252 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003253 }
3254
3255 rettv->vval.v_number = n;
3256}
3257
3258#ifdef FEAT_FLOAT
3259/*
3260 * "exp()" function
3261 */
3262 static void
3263f_exp(typval_T *argvars, typval_T *rettv)
3264{
3265 float_T f = 0.0;
3266
3267 rettv->v_type = VAR_FLOAT;
3268 if (get_float_arg(argvars, &f) == OK)
3269 rettv->vval.v_float = exp(f);
3270 else
3271 rettv->vval.v_float = 0.0;
3272}
3273#endif
3274
3275/*
3276 * "expand()" function
3277 */
3278 static void
3279f_expand(typval_T *argvars, typval_T *rettv)
3280{
3281 char_u *s;
3282 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003283 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3285 expand_T xpc;
3286 int error = FALSE;
3287 char_u *result;
3288
3289 rettv->v_type = VAR_STRING;
3290 if (argvars[1].v_type != VAR_UNKNOWN
3291 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003292 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003294 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003295
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003296 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 if (*s == '%' || *s == '#' || *s == '<')
3298 {
3299 ++emsg_off;
3300 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3301 --emsg_off;
3302 if (rettv->v_type == VAR_LIST)
3303 {
3304 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3305 list_append_string(rettv->vval.v_list, result, -1);
3306 else
3307 vim_free(result);
3308 }
3309 else
3310 rettv->vval.v_string = result;
3311 }
3312 else
3313 {
3314 /* When the optional second argument is non-zero, don't remove matches
3315 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3316 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003317 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003318 options |= WILD_KEEP_ALL;
3319 if (!error)
3320 {
3321 ExpandInit(&xpc);
3322 xpc.xp_context = EXPAND_FILES;
3323 if (p_wic)
3324 options += WILD_ICASE;
3325 if (rettv->v_type == VAR_STRING)
3326 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3327 options, WILD_ALL);
3328 else if (rettv_list_alloc(rettv) != FAIL)
3329 {
3330 int i;
3331
3332 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3333 for (i = 0; i < xpc.xp_numfiles; i++)
3334 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3335 ExpandCleanup(&xpc);
3336 }
3337 }
3338 else
3339 rettv->vval.v_string = NULL;
3340 }
3341}
3342
3343/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003344 * "expandcmd()" function
3345 * Expand all the special characters in a command string.
3346 */
3347 static void
3348f_expandcmd(typval_T *argvars, typval_T *rettv)
3349{
3350 exarg_T eap;
3351 char_u *cmdstr;
3352 char *errormsg = NULL;
3353
3354 rettv->v_type = VAR_STRING;
3355 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3356
3357 memset(&eap, 0, sizeof(eap));
3358 eap.cmd = cmdstr;
3359 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003360 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003361 eap.usefilter = FALSE;
3362 eap.nextcmd = NULL;
3363 eap.cmdidx = CMD_USER;
3364
3365 expand_filename(&eap, &cmdstr, &errormsg);
3366 if (errormsg != NULL && *errormsg != NUL)
3367 emsg(errormsg);
3368
3369 rettv->vval.v_string = cmdstr;
3370}
3371
3372/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003373 * "extend(list, list [, idx])" function
3374 * "extend(dict, dict [, action])" function
3375 */
3376 static void
3377f_extend(typval_T *argvars, typval_T *rettv)
3378{
3379 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3380
3381 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3382 {
3383 list_T *l1, *l2;
3384 listitem_T *item;
3385 long before;
3386 int error = FALSE;
3387
3388 l1 = argvars[0].vval.v_list;
3389 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003390 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 && l2 != NULL)
3392 {
3393 if (argvars[2].v_type != VAR_UNKNOWN)
3394 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003395 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003396 if (error)
3397 return; /* type error; errmsg already given */
3398
3399 if (before == l1->lv_len)
3400 item = NULL;
3401 else
3402 {
3403 item = list_find(l1, before);
3404 if (item == NULL)
3405 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003406 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003407 return;
3408 }
3409 }
3410 }
3411 else
3412 item = NULL;
3413 list_extend(l1, l2, item);
3414
3415 copy_tv(&argvars[0], rettv);
3416 }
3417 }
3418 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3419 {
3420 dict_T *d1, *d2;
3421 char_u *action;
3422 int i;
3423
3424 d1 = argvars[0].vval.v_dict;
3425 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003426 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 && d2 != NULL)
3428 {
3429 /* Check the third argument. */
3430 if (argvars[2].v_type != VAR_UNKNOWN)
3431 {
3432 static char *(av[]) = {"keep", "force", "error"};
3433
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003434 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 if (action == NULL)
3436 return; /* type error; errmsg already given */
3437 for (i = 0; i < 3; ++i)
3438 if (STRCMP(action, av[i]) == 0)
3439 break;
3440 if (i == 3)
3441 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003442 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003443 return;
3444 }
3445 }
3446 else
3447 action = (char_u *)"force";
3448
3449 dict_extend(d1, d2, action);
3450
3451 copy_tv(&argvars[0], rettv);
3452 }
3453 }
3454 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003455 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003456}
3457
3458/*
3459 * "feedkeys()" function
3460 */
3461 static void
3462f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3463{
3464 int remap = TRUE;
3465 int insert = FALSE;
3466 char_u *keys, *flags;
3467 char_u nbuf[NUMBUFLEN];
3468 int typed = FALSE;
3469 int execute = FALSE;
3470 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003471 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 char_u *keys_esc;
3473
3474 /* This is not allowed in the sandbox. If the commands would still be
3475 * executed in the sandbox it would be OK, but it probably happens later,
3476 * when "sandbox" is no longer set. */
3477 if (check_secure())
3478 return;
3479
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003480 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481
3482 if (argvars[1].v_type != VAR_UNKNOWN)
3483 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003484 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485 for ( ; *flags != NUL; ++flags)
3486 {
3487 switch (*flags)
3488 {
3489 case 'n': remap = FALSE; break;
3490 case 'm': remap = TRUE; break;
3491 case 't': typed = TRUE; break;
3492 case 'i': insert = TRUE; break;
3493 case 'x': execute = TRUE; break;
3494 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003495 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003496 }
3497 }
3498 }
3499
3500 if (*keys != NUL || execute)
3501 {
3502 /* Need to escape K_SPECIAL and CSI before putting the string in the
3503 * typeahead buffer. */
3504 keys_esc = vim_strsave_escape_csi(keys);
3505 if (keys_esc != NULL)
3506 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003507 if (lowlevel)
3508 {
3509#ifdef USE_INPUT_BUF
3510 add_to_input_buf(keys, (int)STRLEN(keys));
3511#else
3512 emsg(_("E980: lowlevel input not supported"));
3513#endif
3514 }
3515 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003516 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003517 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003519 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003520#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003521 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003522#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003523 )
3524 typebuf_was_filled = TRUE;
3525 }
3526 vim_free(keys_esc);
3527
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003528 if (execute)
3529 {
3530 int save_msg_scroll = msg_scroll;
3531
3532 /* Avoid a 1 second delay when the keys start Insert mode. */
3533 msg_scroll = FALSE;
3534
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003535 if (!dangerous)
3536 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003537 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003538 if (!dangerous)
3539 --ex_normal_busy;
3540
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003541 msg_scroll |= save_msg_scroll;
3542 }
3543 }
3544 }
3545}
3546
3547/*
3548 * "filereadable()" function
3549 */
3550 static void
3551f_filereadable(typval_T *argvars, typval_T *rettv)
3552{
3553 int fd;
3554 char_u *p;
3555 int n;
3556
3557#ifndef O_NONBLOCK
3558# define O_NONBLOCK 0
3559#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003560 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3562 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3563 {
3564 n = TRUE;
3565 close(fd);
3566 }
3567 else
3568 n = FALSE;
3569
3570 rettv->vval.v_number = n;
3571}
3572
3573/*
3574 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3575 * rights to write into.
3576 */
3577 static void
3578f_filewritable(typval_T *argvars, typval_T *rettv)
3579{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003580 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003581}
3582
3583 static void
3584findfilendir(
3585 typval_T *argvars UNUSED,
3586 typval_T *rettv,
3587 int find_what UNUSED)
3588{
3589#ifdef FEAT_SEARCHPATH
3590 char_u *fname;
3591 char_u *fresult = NULL;
3592 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3593 char_u *p;
3594 char_u pathbuf[NUMBUFLEN];
3595 int count = 1;
3596 int first = TRUE;
3597 int error = FALSE;
3598#endif
3599
3600 rettv->vval.v_string = NULL;
3601 rettv->v_type = VAR_STRING;
3602
3603#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003604 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605
3606 if (argvars[1].v_type != VAR_UNKNOWN)
3607 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003608 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003609 if (p == NULL)
3610 error = TRUE;
3611 else
3612 {
3613 if (*p != NUL)
3614 path = p;
3615
3616 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003617 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003618 }
3619 }
3620
3621 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3622 error = TRUE;
3623
3624 if (*fname != NUL && !error)
3625 {
3626 do
3627 {
3628 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3629 vim_free(fresult);
3630 fresult = find_file_in_path_option(first ? fname : NULL,
3631 first ? (int)STRLEN(fname) : 0,
3632 0, first, path,
3633 find_what,
3634 curbuf->b_ffname,
3635 find_what == FINDFILE_DIR
3636 ? (char_u *)"" : curbuf->b_p_sua);
3637 first = FALSE;
3638
3639 if (fresult != NULL && rettv->v_type == VAR_LIST)
3640 list_append_string(rettv->vval.v_list, fresult, -1);
3641
3642 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3643 }
3644
3645 if (rettv->v_type == VAR_STRING)
3646 rettv->vval.v_string = fresult;
3647#endif
3648}
3649
3650/*
3651 * "filter()" function
3652 */
3653 static void
3654f_filter(typval_T *argvars, typval_T *rettv)
3655{
3656 filter_map(argvars, rettv, FALSE);
3657}
3658
3659/*
3660 * "finddir({fname}[, {path}[, {count}]])" function
3661 */
3662 static void
3663f_finddir(typval_T *argvars, typval_T *rettv)
3664{
3665 findfilendir(argvars, rettv, FINDFILE_DIR);
3666}
3667
3668/*
3669 * "findfile({fname}[, {path}[, {count}]])" function
3670 */
3671 static void
3672f_findfile(typval_T *argvars, typval_T *rettv)
3673{
3674 findfilendir(argvars, rettv, FINDFILE_FILE);
3675}
3676
3677#ifdef FEAT_FLOAT
3678/*
3679 * "float2nr({float})" function
3680 */
3681 static void
3682f_float2nr(typval_T *argvars, typval_T *rettv)
3683{
3684 float_T f = 0.0;
3685
3686 if (get_float_arg(argvars, &f) == OK)
3687 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003688 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003689 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003690 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003691 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003692 else
3693 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003694 }
3695}
3696
3697/*
3698 * "floor({float})" function
3699 */
3700 static void
3701f_floor(typval_T *argvars, typval_T *rettv)
3702{
3703 float_T f = 0.0;
3704
3705 rettv->v_type = VAR_FLOAT;
3706 if (get_float_arg(argvars, &f) == OK)
3707 rettv->vval.v_float = floor(f);
3708 else
3709 rettv->vval.v_float = 0.0;
3710}
3711
3712/*
3713 * "fmod()" function
3714 */
3715 static void
3716f_fmod(typval_T *argvars, typval_T *rettv)
3717{
3718 float_T fx = 0.0, fy = 0.0;
3719
3720 rettv->v_type = VAR_FLOAT;
3721 if (get_float_arg(argvars, &fx) == OK
3722 && get_float_arg(&argvars[1], &fy) == OK)
3723 rettv->vval.v_float = fmod(fx, fy);
3724 else
3725 rettv->vval.v_float = 0.0;
3726}
3727#endif
3728
3729/*
3730 * "fnameescape({string})" function
3731 */
3732 static void
3733f_fnameescape(typval_T *argvars, typval_T *rettv)
3734{
3735 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003736 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003737 rettv->v_type = VAR_STRING;
3738}
3739
3740/*
3741 * "fnamemodify({fname}, {mods})" function
3742 */
3743 static void
3744f_fnamemodify(typval_T *argvars, typval_T *rettv)
3745{
3746 char_u *fname;
3747 char_u *mods;
3748 int usedlen = 0;
3749 int len;
3750 char_u *fbuf = NULL;
3751 char_u buf[NUMBUFLEN];
3752
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003753 fname = tv_get_string_chk(&argvars[0]);
3754 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003755 if (fname == NULL || mods == NULL)
3756 fname = NULL;
3757 else
3758 {
3759 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003760 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 }
3762
3763 rettv->v_type = VAR_STRING;
3764 if (fname == NULL)
3765 rettv->vval.v_string = NULL;
3766 else
3767 rettv->vval.v_string = vim_strnsave(fname, len);
3768 vim_free(fbuf);
3769}
3770
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003771/*
3772 * "foldclosed()" function
3773 */
3774 static void
3775foldclosed_both(
3776 typval_T *argvars UNUSED,
3777 typval_T *rettv,
3778 int end UNUSED)
3779{
3780#ifdef FEAT_FOLDING
3781 linenr_T lnum;
3782 linenr_T first, last;
3783
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003784 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3786 {
3787 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3788 {
3789 if (end)
3790 rettv->vval.v_number = (varnumber_T)last;
3791 else
3792 rettv->vval.v_number = (varnumber_T)first;
3793 return;
3794 }
3795 }
3796#endif
3797 rettv->vval.v_number = -1;
3798}
3799
3800/*
3801 * "foldclosed()" function
3802 */
3803 static void
3804f_foldclosed(typval_T *argvars, typval_T *rettv)
3805{
3806 foldclosed_both(argvars, rettv, FALSE);
3807}
3808
3809/*
3810 * "foldclosedend()" function
3811 */
3812 static void
3813f_foldclosedend(typval_T *argvars, typval_T *rettv)
3814{
3815 foldclosed_both(argvars, rettv, TRUE);
3816}
3817
3818/*
3819 * "foldlevel()" function
3820 */
3821 static void
3822f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3823{
3824#ifdef FEAT_FOLDING
3825 linenr_T lnum;
3826
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003827 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003828 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3829 rettv->vval.v_number = foldLevel(lnum);
3830#endif
3831}
3832
3833/*
3834 * "foldtext()" function
3835 */
3836 static void
3837f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3838{
3839#ifdef FEAT_FOLDING
3840 linenr_T foldstart;
3841 linenr_T foldend;
3842 char_u *dashes;
3843 linenr_T lnum;
3844 char_u *s;
3845 char_u *r;
3846 int len;
3847 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003848 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003849#endif
3850
3851 rettv->v_type = VAR_STRING;
3852 rettv->vval.v_string = NULL;
3853#ifdef FEAT_FOLDING
3854 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3855 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3856 dashes = get_vim_var_str(VV_FOLDDASHES);
3857 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3858 && dashes != NULL)
3859 {
3860 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003861 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003862 if (!linewhite(lnum))
3863 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864
3865 /* Find interesting text in this line. */
3866 s = skipwhite(ml_get(lnum));
3867 /* skip C comment-start */
3868 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3869 {
3870 s = skipwhite(s + 2);
3871 if (*skipwhite(s) == NUL
3872 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3873 {
3874 s = skipwhite(ml_get(lnum + 1));
3875 if (*s == '*')
3876 s = skipwhite(s + 1);
3877 }
3878 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003879 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003880 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003881 r = alloc(STRLEN(txt)
3882 + STRLEN(dashes) // for %s
3883 + 20 // for %3ld
3884 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003885 if (r != NULL)
3886 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003887 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003888 len = (int)STRLEN(r);
3889 STRCAT(r, s);
3890 /* remove 'foldmarker' and 'commentstring' */
3891 foldtext_cleanup(r + len);
3892 rettv->vval.v_string = r;
3893 }
3894 }
3895#endif
3896}
3897
3898/*
3899 * "foldtextresult(lnum)" function
3900 */
3901 static void
3902f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3903{
3904#ifdef FEAT_FOLDING
3905 linenr_T lnum;
3906 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003907 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003908 foldinfo_T foldinfo;
3909 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003910 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003911#endif
3912
3913 rettv->v_type = VAR_STRING;
3914 rettv->vval.v_string = NULL;
3915#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003916 if (entered)
3917 return; /* reject recursive use */
3918 entered = TRUE;
3919
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003920 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 /* treat illegal types and illegal string values for {lnum} the same */
3922 if (lnum < 0)
3923 lnum = 0;
3924 fold_count = foldedCount(curwin, lnum, &foldinfo);
3925 if (fold_count > 0)
3926 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003927 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3928 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003929 if (text == buf)
3930 text = vim_strsave(text);
3931 rettv->vval.v_string = text;
3932 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003933
3934 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003935#endif
3936}
3937
3938/*
3939 * "foreground()" function
3940 */
3941 static void
3942f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3943{
3944#ifdef FEAT_GUI
3945 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003946 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003947 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003948 return;
3949 }
3950#endif
3951#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003952 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953#endif
3954}
3955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003957common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958{
3959 char_u *s;
3960 char_u *name;
3961 int use_string = FALSE;
3962 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003963 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003964
3965 if (argvars[0].v_type == VAR_FUNC)
3966 {
3967 /* function(MyFunc, [arg], dict) */
3968 s = argvars[0].vval.v_string;
3969 }
3970 else if (argvars[0].v_type == VAR_PARTIAL
3971 && argvars[0].vval.v_partial != NULL)
3972 {
3973 /* function(dict.MyFunc, [arg]) */
3974 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003975 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003976 }
3977 else
3978 {
3979 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003980 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003981 use_string = TRUE;
3982 }
3983
Bram Moolenaar843b8842016-08-21 14:36:15 +02003984 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003985 {
3986 name = s;
3987 trans_name = trans_function_name(&name, FALSE,
3988 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3989 if (*name != NUL)
3990 s = NULL;
3991 }
3992
Bram Moolenaar843b8842016-08-21 14:36:15 +02003993 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3994 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003995 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003996 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003997 else if (trans_name != NULL && (is_funcref
3998 ? find_func(trans_name) == NULL
3999 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004000 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004001 else
4002 {
4003 int dict_idx = 0;
4004 int arg_idx = 0;
4005 list_T *list = NULL;
4006
4007 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4008 {
4009 char sid_buf[25];
4010 int off = *s == 's' ? 2 : 5;
4011
4012 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4013 * also be called from another script. Using trans_function_name()
4014 * would also work, but some plugins depend on the name being
4015 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004016 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004017 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004018 if (name != NULL)
4019 {
4020 STRCPY(name, sid_buf);
4021 STRCAT(name, s + off);
4022 }
4023 }
4024 else
4025 name = vim_strsave(s);
4026
4027 if (argvars[1].v_type != VAR_UNKNOWN)
4028 {
4029 if (argvars[2].v_type != VAR_UNKNOWN)
4030 {
4031 /* function(name, [args], dict) */
4032 arg_idx = 1;
4033 dict_idx = 2;
4034 }
4035 else if (argvars[1].v_type == VAR_DICT)
4036 /* function(name, dict) */
4037 dict_idx = 1;
4038 else
4039 /* function(name, [args]) */
4040 arg_idx = 1;
4041 if (dict_idx > 0)
4042 {
4043 if (argvars[dict_idx].v_type != VAR_DICT)
4044 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004045 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004047 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048 }
4049 if (argvars[dict_idx].vval.v_dict == NULL)
4050 dict_idx = 0;
4051 }
4052 if (arg_idx > 0)
4053 {
4054 if (argvars[arg_idx].v_type != VAR_LIST)
4055 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004056 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004058 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004059 }
4060 list = argvars[arg_idx].vval.v_list;
4061 if (list == NULL || list->lv_len == 0)
4062 arg_idx = 0;
4063 }
4064 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004065 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004066 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004067 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068
4069 /* result is a VAR_PARTIAL */
4070 if (pt == NULL)
4071 vim_free(name);
4072 else
4073 {
4074 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4075 {
4076 listitem_T *li;
4077 int i = 0;
4078 int arg_len = 0;
4079 int lv_len = 0;
4080
4081 if (arg_pt != NULL)
4082 arg_len = arg_pt->pt_argc;
4083 if (list != NULL)
4084 lv_len = list->lv_len;
4085 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004086 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004087 if (pt->pt_argv == NULL)
4088 {
4089 vim_free(pt);
4090 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004091 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004092 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004093 for (i = 0; i < arg_len; i++)
4094 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4095 if (lv_len > 0)
4096 for (li = list->lv_first; li != NULL;
4097 li = li->li_next)
4098 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099 }
4100
4101 /* For "function(dict.func, [], dict)" and "func" is a partial
4102 * use "dict". That is backwards compatible. */
4103 if (dict_idx > 0)
4104 {
4105 /* The dict is bound explicitly, pt_auto is FALSE. */
4106 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4107 ++pt->pt_dict->dv_refcount;
4108 }
4109 else if (arg_pt != NULL)
4110 {
4111 /* If the dict was bound automatically the result is also
4112 * bound automatically. */
4113 pt->pt_dict = arg_pt->pt_dict;
4114 pt->pt_auto = arg_pt->pt_auto;
4115 if (pt->pt_dict != NULL)
4116 ++pt->pt_dict->dv_refcount;
4117 }
4118
4119 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004120 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4121 {
4122 pt->pt_func = arg_pt->pt_func;
4123 func_ptr_ref(pt->pt_func);
4124 vim_free(name);
4125 }
4126 else if (is_funcref)
4127 {
4128 pt->pt_func = find_func(trans_name);
4129 func_ptr_ref(pt->pt_func);
4130 vim_free(name);
4131 }
4132 else
4133 {
4134 pt->pt_name = name;
4135 func_ref(name);
4136 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004137 }
4138 rettv->v_type = VAR_PARTIAL;
4139 rettv->vval.v_partial = pt;
4140 }
4141 else
4142 {
4143 /* result is a VAR_FUNC */
4144 rettv->v_type = VAR_FUNC;
4145 rettv->vval.v_string = name;
4146 func_ref(name);
4147 }
4148 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004149theend:
4150 vim_free(trans_name);
4151}
4152
4153/*
4154 * "funcref()" function
4155 */
4156 static void
4157f_funcref(typval_T *argvars, typval_T *rettv)
4158{
4159 common_function(argvars, rettv, TRUE);
4160}
4161
4162/*
4163 * "function()" function
4164 */
4165 static void
4166f_function(typval_T *argvars, typval_T *rettv)
4167{
4168 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169}
4170
4171/*
4172 * "garbagecollect()" function
4173 */
4174 static void
4175f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4176{
4177 /* This is postponed until we are back at the toplevel, because we may be
4178 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4179 want_garbage_collect = TRUE;
4180
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004181 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004182 garbage_collect_at_exit = TRUE;
4183}
4184
4185/*
4186 * "get()" function
4187 */
4188 static void
4189f_get(typval_T *argvars, typval_T *rettv)
4190{
4191 listitem_T *li;
4192 list_T *l;
4193 dictitem_T *di;
4194 dict_T *d;
4195 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004196 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004197
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004198 if (argvars[0].v_type == VAR_BLOB)
4199 {
4200 int error = FALSE;
4201 int idx = tv_get_number_chk(&argvars[1], &error);
4202
4203 if (!error)
4204 {
4205 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004206 if (idx < 0)
4207 idx = blob_len(argvars[0].vval.v_blob) + idx;
4208 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4209 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004210 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004211 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004212 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004213 tv = rettv;
4214 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004215 }
4216 }
4217 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218 {
4219 if ((l = argvars[0].vval.v_list) != NULL)
4220 {
4221 int error = FALSE;
4222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004223 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004224 if (!error && li != NULL)
4225 tv = &li->li_tv;
4226 }
4227 }
4228 else if (argvars[0].v_type == VAR_DICT)
4229 {
4230 if ((d = argvars[0].vval.v_dict) != NULL)
4231 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004232 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004233 if (di != NULL)
4234 tv = &di->di_tv;
4235 }
4236 }
4237 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4238 {
4239 partial_T *pt;
4240 partial_T fref_pt;
4241
4242 if (argvars[0].v_type == VAR_PARTIAL)
4243 pt = argvars[0].vval.v_partial;
4244 else
4245 {
4246 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4247 fref_pt.pt_name = argvars[0].vval.v_string;
4248 pt = &fref_pt;
4249 }
4250
4251 if (pt != NULL)
4252 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004253 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004254 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255
4256 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4257 {
4258 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004259 n = partial_name(pt);
4260 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004261 rettv->vval.v_string = NULL;
4262 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004263 {
4264 rettv->vval.v_string = vim_strsave(n);
4265 if (rettv->v_type == VAR_FUNC)
4266 func_ref(rettv->vval.v_string);
4267 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004268 }
4269 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004270 {
4271 what_is_dict = TRUE;
4272 if (pt->pt_dict != NULL)
4273 rettv_dict_set(rettv, pt->pt_dict);
4274 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 else if (STRCMP(what, "args") == 0)
4276 {
4277 rettv->v_type = VAR_LIST;
4278 if (rettv_list_alloc(rettv) == OK)
4279 {
4280 int i;
4281
4282 for (i = 0; i < pt->pt_argc; ++i)
4283 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4284 }
4285 }
4286 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004287 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004288
4289 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4290 // third argument
4291 if (!what_is_dict)
4292 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293 }
4294 }
4295 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004296 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297
4298 if (tv == NULL)
4299 {
4300 if (argvars[2].v_type != VAR_UNKNOWN)
4301 copy_tv(&argvars[2], rettv);
4302 }
4303 else
4304 copy_tv(tv, rettv);
4305}
4306
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004307/*
4308 * Returns buffer options, variables and other attributes in a dictionary.
4309 */
4310 static dict_T *
4311get_buffer_info(buf_T *buf)
4312{
4313 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004314 tabpage_T *tp;
4315 win_T *wp;
4316 list_T *windows;
4317
4318 dict = dict_alloc();
4319 if (dict == NULL)
4320 return NULL;
4321
Bram Moolenaare0be1672018-07-08 16:50:37 +02004322 dict_add_number(dict, "bufnr", buf->b_fnum);
4323 dict_add_string(dict, "name", buf->b_ffname);
4324 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4325 : buflist_findlnum(buf));
4326 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4327 dict_add_number(dict, "listed", buf->b_p_bl);
4328 dict_add_number(dict, "changed", bufIsChanged(buf));
4329 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4330 dict_add_number(dict, "hidden",
4331 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004332
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004333 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004334 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004335
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004336 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004337 windows = list_alloc();
4338 if (windows != NULL)
4339 {
4340 FOR_ALL_TAB_WINDOWS(tp, wp)
4341 if (wp->w_buffer == buf)
4342 list_append_number(windows, (varnumber_T)wp->w_id);
4343 dict_add_list(dict, "windows", windows);
4344 }
4345
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004346#ifdef FEAT_TEXT_PROP
4347 // List of popup windows displaying this buffer
4348 windows = list_alloc();
4349 if (windows != NULL)
4350 {
4351 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4352 if (wp->w_buffer == buf)
4353 list_append_number(windows, (varnumber_T)wp->w_id);
4354 FOR_ALL_TABPAGES(tp)
4355 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4356 if (wp->w_buffer == buf)
4357 list_append_number(windows, (varnumber_T)wp->w_id);
4358
4359 dict_add_list(dict, "popups", windows);
4360 }
4361#endif
4362
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004363#ifdef FEAT_SIGNS
4364 if (buf->b_signlist != NULL)
4365 {
4366 /* List of signs placed in this buffer */
4367 list_T *signs = list_alloc();
4368 if (signs != NULL)
4369 {
4370 get_buffer_signs(buf, signs);
4371 dict_add_list(dict, "signs", signs);
4372 }
4373 }
4374#endif
4375
4376 return dict;
4377}
4378
4379/*
4380 * "getbufinfo()" function
4381 */
4382 static void
4383f_getbufinfo(typval_T *argvars, typval_T *rettv)
4384{
4385 buf_T *buf = NULL;
4386 buf_T *argbuf = NULL;
4387 dict_T *d;
4388 int filtered = FALSE;
4389 int sel_buflisted = FALSE;
4390 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004391 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004392
4393 if (rettv_list_alloc(rettv) != OK)
4394 return;
4395
4396 /* List of all the buffers or selected buffers */
4397 if (argvars[0].v_type == VAR_DICT)
4398 {
4399 dict_T *sel_d = argvars[0].vval.v_dict;
4400
4401 if (sel_d != NULL)
4402 {
4403 dictitem_T *di;
4404
4405 filtered = TRUE;
4406
4407 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004408 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004409 sel_buflisted = TRUE;
4410
4411 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004412 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004413 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004414
4415 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004416 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004417 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004418 }
4419 }
4420 else if (argvars[0].v_type != VAR_UNKNOWN)
4421 {
4422 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004423 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004424 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004425 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004426 --emsg_off;
4427 if (argbuf == NULL)
4428 return;
4429 }
4430
4431 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004432 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004433 {
4434 if (argbuf != NULL && argbuf != buf)
4435 continue;
4436 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004437 || (sel_buflisted && !buf->b_p_bl)
4438 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004439 continue;
4440
4441 d = get_buffer_info(buf);
4442 if (d != NULL)
4443 list_append_dict(rettv->vval.v_list, d);
4444 if (argbuf != NULL)
4445 return;
4446 }
4447}
4448
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004449/*
4450 * Get line or list of lines from buffer "buf" into "rettv".
4451 * Return a range (from start to end) of lines in rettv from the specified
4452 * buffer.
4453 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4454 */
4455 static void
4456get_buffer_lines(
4457 buf_T *buf,
4458 linenr_T start,
4459 linenr_T end,
4460 int retlist,
4461 typval_T *rettv)
4462{
4463 char_u *p;
4464
4465 rettv->v_type = VAR_STRING;
4466 rettv->vval.v_string = NULL;
4467 if (retlist && rettv_list_alloc(rettv) == FAIL)
4468 return;
4469
4470 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4471 return;
4472
4473 if (!retlist)
4474 {
4475 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4476 p = ml_get_buf(buf, start, FALSE);
4477 else
4478 p = (char_u *)"";
4479 rettv->vval.v_string = vim_strsave(p);
4480 }
4481 else
4482 {
4483 if (end < start)
4484 return;
4485
4486 if (start < 1)
4487 start = 1;
4488 if (end > buf->b_ml.ml_line_count)
4489 end = buf->b_ml.ml_line_count;
4490 while (start <= end)
4491 if (list_append_string(rettv->vval.v_list,
4492 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4493 break;
4494 }
4495}
4496
4497/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004498 * "getbufline()" function
4499 */
4500 static void
4501f_getbufline(typval_T *argvars, typval_T *rettv)
4502{
4503 linenr_T lnum;
4504 linenr_T end;
4505 buf_T *buf;
4506
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004507 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004508 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004509 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004510 --emsg_off;
4511
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004512 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004513 if (argvars[2].v_type == VAR_UNKNOWN)
4514 end = lnum;
4515 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004516 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517
4518 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4519}
4520
4521/*
4522 * "getbufvar()" function
4523 */
4524 static void
4525f_getbufvar(typval_T *argvars, typval_T *rettv)
4526{
4527 buf_T *buf;
4528 buf_T *save_curbuf;
4529 char_u *varname;
4530 dictitem_T *v;
4531 int done = FALSE;
4532
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004533 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4534 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004536 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004537
4538 rettv->v_type = VAR_STRING;
4539 rettv->vval.v_string = NULL;
4540
4541 if (buf != NULL && varname != NULL)
4542 {
4543 /* set curbuf to be our buf, temporarily */
4544 save_curbuf = curbuf;
4545 curbuf = buf;
4546
Bram Moolenaar30567352016-08-27 21:25:44 +02004547 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004548 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004549 if (varname[1] == NUL)
4550 {
4551 /* get all buffer-local options in a dict */
4552 dict_T *opts = get_winbuf_options(TRUE);
4553
4554 if (opts != NULL)
4555 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004556 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004557 done = TRUE;
4558 }
4559 }
4560 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4561 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004562 done = TRUE;
4563 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004564 else
4565 {
4566 /* Look up the variable. */
4567 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4568 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4569 'b', varname, FALSE);
4570 if (v != NULL)
4571 {
4572 copy_tv(&v->di_tv, rettv);
4573 done = TRUE;
4574 }
4575 }
4576
4577 /* restore previous notion of curbuf */
4578 curbuf = save_curbuf;
4579 }
4580
4581 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4582 /* use the default value */
4583 copy_tv(&argvars[2], rettv);
4584
4585 --emsg_off;
4586}
4587
4588/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004589 * "getchangelist()" function
4590 */
4591 static void
4592f_getchangelist(typval_T *argvars, typval_T *rettv)
4593{
4594#ifdef FEAT_JUMPLIST
4595 buf_T *buf;
4596 int i;
4597 list_T *l;
4598 dict_T *d;
4599#endif
4600
4601 if (rettv_list_alloc(rettv) != OK)
4602 return;
4603
4604#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004605 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004606 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004607 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004608 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004609 if (buf == NULL)
4610 return;
4611
4612 l = list_alloc();
4613 if (l == NULL)
4614 return;
4615
4616 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4617 return;
4618 /*
4619 * The current window change list index tracks only the position in the
4620 * current buffer change list. For other buffers, use the change list
4621 * length as the current index.
4622 */
4623 list_append_number(rettv->vval.v_list,
4624 (varnumber_T)((buf == curwin->w_buffer)
4625 ? curwin->w_changelistidx : buf->b_changelistlen));
4626
4627 for (i = 0; i < buf->b_changelistlen; ++i)
4628 {
4629 if (buf->b_changelist[i].lnum == 0)
4630 continue;
4631 if ((d = dict_alloc()) == NULL)
4632 return;
4633 if (list_append_dict(l, d) == FAIL)
4634 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004635 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4636 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004637 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004638 }
4639#endif
4640}
4641/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004642 * "getchar()" function
4643 */
4644 static void
4645f_getchar(typval_T *argvars, typval_T *rettv)
4646{
4647 varnumber_T n;
4648 int error = FALSE;
4649
Bram Moolenaar84d93902018-09-11 20:10:20 +02004650#ifdef MESSAGE_QUEUE
4651 // vpeekc() used to check for messages, but that caused problems, invoking
4652 // a callback where it was not expected. Some plugins use getchar(1) in a
4653 // loop to await a message, therefore make sure we check for messages here.
4654 parse_queued_messages();
4655#endif
4656
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004657 /* Position the cursor. Needed after a message that ends in a space. */
4658 windgoto(msg_row, msg_col);
4659
4660 ++no_mapping;
4661 ++allow_keys;
4662 for (;;)
4663 {
4664 if (argvars[0].v_type == VAR_UNKNOWN)
4665 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004666 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004667 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004668 /* getchar(1): only check if char avail */
4669 n = vpeekc_any();
4670 else if (error || vpeekc_any() == NUL)
4671 /* illegal argument or getchar(0) and no char avail: return zero */
4672 n = 0;
4673 else
4674 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004675 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004676
4677 if (n == K_IGNORE)
4678 continue;
4679 break;
4680 }
4681 --no_mapping;
4682 --allow_keys;
4683
4684 set_vim_var_nr(VV_MOUSE_WIN, 0);
4685 set_vim_var_nr(VV_MOUSE_WINID, 0);
4686 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4687 set_vim_var_nr(VV_MOUSE_COL, 0);
4688
4689 rettv->vval.v_number = n;
4690 if (IS_SPECIAL(n) || mod_mask != 0)
4691 {
4692 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4693 int i = 0;
4694
4695 /* Turn a special key into three bytes, plus modifier. */
4696 if (mod_mask != 0)
4697 {
4698 temp[i++] = K_SPECIAL;
4699 temp[i++] = KS_MODIFIER;
4700 temp[i++] = mod_mask;
4701 }
4702 if (IS_SPECIAL(n))
4703 {
4704 temp[i++] = K_SPECIAL;
4705 temp[i++] = K_SECOND(n);
4706 temp[i++] = K_THIRD(n);
4707 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 else if (has_mbyte)
4709 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710 else
4711 temp[i++] = n;
4712 temp[i++] = NUL;
4713 rettv->v_type = VAR_STRING;
4714 rettv->vval.v_string = vim_strsave(temp);
4715
4716#ifdef FEAT_MOUSE
4717 if (is_mouse_key(n))
4718 {
4719 int row = mouse_row;
4720 int col = mouse_col;
4721 win_T *win;
4722 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004723 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004724 int winnr = 1;
4725
4726 if (row >= 0 && col >= 0)
4727 {
4728 /* Find the window at the mouse coordinates and compute the
4729 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004730 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004731 if (win == NULL)
4732 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004733 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004734# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004735 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004736 winnr = 0;
4737 else
4738# endif
4739 for (wp = firstwin; wp != win && wp != NULL;
4740 wp = wp->w_next)
4741 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004742 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4743 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4744 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4745 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4746 }
4747 }
4748#endif
4749 }
4750}
4751
4752/*
4753 * "getcharmod()" function
4754 */
4755 static void
4756f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4757{
4758 rettv->vval.v_number = mod_mask;
4759}
4760
4761/*
4762 * "getcharsearch()" function
4763 */
4764 static void
4765f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4766{
4767 if (rettv_dict_alloc(rettv) != FAIL)
4768 {
4769 dict_T *dict = rettv->vval.v_dict;
4770
Bram Moolenaare0be1672018-07-08 16:50:37 +02004771 dict_add_string(dict, "char", last_csearch());
4772 dict_add_number(dict, "forward", last_csearch_forward());
4773 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004774 }
4775}
4776
4777/*
4778 * "getcmdline()" function
4779 */
4780 static void
4781f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4782{
4783 rettv->v_type = VAR_STRING;
4784 rettv->vval.v_string = get_cmdline_str();
4785}
4786
4787/*
4788 * "getcmdpos()" function
4789 */
4790 static void
4791f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4792{
4793 rettv->vval.v_number = get_cmdline_pos() + 1;
4794}
4795
4796/*
4797 * "getcmdtype()" function
4798 */
4799 static void
4800f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4801{
4802 rettv->v_type = VAR_STRING;
4803 rettv->vval.v_string = alloc(2);
4804 if (rettv->vval.v_string != NULL)
4805 {
4806 rettv->vval.v_string[0] = get_cmdline_type();
4807 rettv->vval.v_string[1] = NUL;
4808 }
4809}
4810
4811/*
4812 * "getcmdwintype()" function
4813 */
4814 static void
4815f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4816{
4817 rettv->v_type = VAR_STRING;
4818 rettv->vval.v_string = NULL;
4819#ifdef FEAT_CMDWIN
4820 rettv->vval.v_string = alloc(2);
4821 if (rettv->vval.v_string != NULL)
4822 {
4823 rettv->vval.v_string[0] = cmdwin_type;
4824 rettv->vval.v_string[1] = NUL;
4825 }
4826#endif
4827}
4828
4829#if defined(FEAT_CMDL_COMPL)
4830/*
4831 * "getcompletion()" function
4832 */
4833 static void
4834f_getcompletion(typval_T *argvars, typval_T *rettv)
4835{
4836 char_u *pat;
4837 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004838 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004839 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4840 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004842 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004843 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004844
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004845 if (p_wic)
4846 options |= WILD_ICASE;
4847
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004848 /* For filtered results, 'wildignore' is used */
4849 if (!filtered)
4850 options |= WILD_KEEP_ALL;
4851
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004853 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004854 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004855 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004856 if (xpc.xp_context == EXPAND_NOTHING)
4857 {
4858 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004859 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004860 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004861 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004862 return;
4863 }
4864
4865# if defined(FEAT_MENU)
4866 if (xpc.xp_context == EXPAND_MENUS)
4867 {
4868 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4869 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4870 }
4871# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004872#ifdef FEAT_CSCOPE
4873 if (xpc.xp_context == EXPAND_CSCOPE)
4874 {
4875 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4876 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4877 }
4878#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004879#ifdef FEAT_SIGNS
4880 if (xpc.xp_context == EXPAND_SIGN)
4881 {
4882 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4883 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4884 }
4885#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886
4887 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4888 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4889 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004890 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004891
4892 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4893
4894 for (i = 0; i < xpc.xp_numfiles; i++)
4895 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4896 }
4897 vim_free(pat);
4898 ExpandCleanup(&xpc);
4899}
4900#endif
4901
4902/*
4903 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004904 *
4905 * Return the current working directory of a window in a tab page.
4906 * First optional argument 'winnr' is the window number or -1 and the second
4907 * optional argument 'tabnr' is the tab page number.
4908 *
4909 * If no arguments are supplied, then return the directory of the current
4910 * window.
4911 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4912 * the specified window.
4913 * If 'winnr' is 0 then return the directory of the current window.
4914 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4915 * directory of the specified tab page. Otherwise return the directory of the
4916 * specified window in the specified tab page.
4917 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004918 */
4919 static void
4920f_getcwd(typval_T *argvars, typval_T *rettv)
4921{
4922 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004923 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004924 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004925 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004926
4927 rettv->v_type = VAR_STRING;
4928 rettv->vval.v_string = NULL;
4929
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004930 if (argvars[0].v_type == VAR_NUMBER
4931 && argvars[0].vval.v_number == -1
4932 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004933 global = TRUE;
4934 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004935 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004936
4937 if (wp != NULL && wp->w_localdir != NULL)
4938 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004939 else if (tp != NULL && tp->tp_localdir != NULL)
4940 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4941 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004943 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944 rettv->vval.v_string = vim_strsave(globaldir);
4945 else
4946 {
4947 cwd = alloc(MAXPATHL);
4948 if (cwd != NULL)
4949 {
4950 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4951 rettv->vval.v_string = vim_strsave(cwd);
4952 vim_free(cwd);
4953 }
4954 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004956#ifdef BACKSLASH_IN_FILENAME
4957 if (rettv->vval.v_string != NULL)
4958 slash_adjust(rettv->vval.v_string);
4959#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004960}
4961
4962/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004963 * "getenv()" function
4964 */
4965 static void
4966f_getenv(typval_T *argvars, typval_T *rettv)
4967{
4968 int mustfree = FALSE;
4969 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4970
4971 if (p == NULL)
4972 {
4973 rettv->v_type = VAR_SPECIAL;
4974 rettv->vval.v_number = VVAL_NULL;
4975 return;
4976 }
4977 if (!mustfree)
4978 p = vim_strsave(p);
4979 rettv->vval.v_string = p;
4980 rettv->v_type = VAR_STRING;
4981}
4982
4983/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984 * "getfontname()" function
4985 */
4986 static void
4987f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4988{
4989 rettv->v_type = VAR_STRING;
4990 rettv->vval.v_string = NULL;
4991#ifdef FEAT_GUI
4992 if (gui.in_use)
4993 {
4994 GuiFont font;
4995 char_u *name = NULL;
4996
4997 if (argvars[0].v_type == VAR_UNKNOWN)
4998 {
4999 /* Get the "Normal" font. Either the name saved by
5000 * hl_set_font_name() or from the font ID. */
5001 font = gui.norm_font;
5002 name = hl_get_font_name();
5003 }
5004 else
5005 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005006 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005007 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5008 return;
5009 font = gui_mch_get_font(name, FALSE);
5010 if (font == NOFONT)
5011 return; /* Invalid font name, return empty string. */
5012 }
5013 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5014 if (argvars[0].v_type != VAR_UNKNOWN)
5015 gui_mch_free_font(font);
5016 }
5017#endif
5018}
5019
5020/*
5021 * "getfperm({fname})" function
5022 */
5023 static void
5024f_getfperm(typval_T *argvars, typval_T *rettv)
5025{
5026 char_u *fname;
5027 stat_T st;
5028 char_u *perm = NULL;
5029 char_u flags[] = "rwx";
5030 int i;
5031
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005032 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005033
5034 rettv->v_type = VAR_STRING;
5035 if (mch_stat((char *)fname, &st) >= 0)
5036 {
5037 perm = vim_strsave((char_u *)"---------");
5038 if (perm != NULL)
5039 {
5040 for (i = 0; i < 9; i++)
5041 {
5042 if (st.st_mode & (1 << (8 - i)))
5043 perm[i] = flags[i % 3];
5044 }
5045 }
5046 }
5047 rettv->vval.v_string = perm;
5048}
5049
5050/*
5051 * "getfsize({fname})" function
5052 */
5053 static void
5054f_getfsize(typval_T *argvars, typval_T *rettv)
5055{
5056 char_u *fname;
5057 stat_T st;
5058
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005059 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060
5061 rettv->v_type = VAR_NUMBER;
5062
5063 if (mch_stat((char *)fname, &st) >= 0)
5064 {
5065 if (mch_isdir(fname))
5066 rettv->vval.v_number = 0;
5067 else
5068 {
5069 rettv->vval.v_number = (varnumber_T)st.st_size;
5070
5071 /* non-perfect check for overflow */
5072 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5073 rettv->vval.v_number = -2;
5074 }
5075 }
5076 else
5077 rettv->vval.v_number = -1;
5078}
5079
5080/*
5081 * "getftime({fname})" function
5082 */
5083 static void
5084f_getftime(typval_T *argvars, typval_T *rettv)
5085{
5086 char_u *fname;
5087 stat_T st;
5088
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005089 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005090
5091 if (mch_stat((char *)fname, &st) >= 0)
5092 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5093 else
5094 rettv->vval.v_number = -1;
5095}
5096
5097/*
5098 * "getftype({fname})" function
5099 */
5100 static void
5101f_getftype(typval_T *argvars, typval_T *rettv)
5102{
5103 char_u *fname;
5104 stat_T st;
5105 char_u *type = NULL;
5106 char *t;
5107
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005108 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109
5110 rettv->v_type = VAR_STRING;
5111 if (mch_lstat((char *)fname, &st) >= 0)
5112 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 if (S_ISREG(st.st_mode))
5114 t = "file";
5115 else if (S_ISDIR(st.st_mode))
5116 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 else if (S_ISLNK(st.st_mode))
5118 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005119 else if (S_ISBLK(st.st_mode))
5120 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005121 else if (S_ISCHR(st.st_mode))
5122 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005123 else if (S_ISFIFO(st.st_mode))
5124 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005125 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005126 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127 else
5128 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005129 type = vim_strsave((char_u *)t);
5130 }
5131 rettv->vval.v_string = type;
5132}
5133
5134/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005135 * "getjumplist()" function
5136 */
5137 static void
5138f_getjumplist(typval_T *argvars, typval_T *rettv)
5139{
5140#ifdef FEAT_JUMPLIST
5141 win_T *wp;
5142 int i;
5143 list_T *l;
5144 dict_T *d;
5145#endif
5146
5147 if (rettv_list_alloc(rettv) != OK)
5148 return;
5149
5150#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005151 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005152 if (wp == NULL)
5153 return;
5154
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005155 cleanup_jumplist(wp, TRUE);
5156
Bram Moolenaar4f505882018-02-10 21:06:32 +01005157 l = list_alloc();
5158 if (l == NULL)
5159 return;
5160
5161 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5162 return;
5163 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5164
5165 for (i = 0; i < wp->w_jumplistlen; ++i)
5166 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005167 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5168 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005169 if ((d = dict_alloc()) == NULL)
5170 return;
5171 if (list_append_dict(l, d) == FAIL)
5172 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005173 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5174 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005175 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005176 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005177 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005178 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005179 }
5180#endif
5181}
5182
5183/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184 * "getline(lnum, [end])" function
5185 */
5186 static void
5187f_getline(typval_T *argvars, typval_T *rettv)
5188{
5189 linenr_T lnum;
5190 linenr_T end;
5191 int retlist;
5192
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005193 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005194 if (argvars[1].v_type == VAR_UNKNOWN)
5195 {
5196 end = 0;
5197 retlist = FALSE;
5198 }
5199 else
5200 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005201 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005202 retlist = TRUE;
5203 }
5204
5205 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5206}
5207
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005208#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005209 static void
5210get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5211{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005212 if (what_arg->v_type == VAR_UNKNOWN)
5213 {
5214 if (rettv_list_alloc(rettv) == OK)
5215 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005216 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005217 }
5218 else
5219 {
5220 if (rettv_dict_alloc(rettv) == OK)
5221 if (is_qf || (wp != NULL))
5222 {
5223 if (what_arg->v_type == VAR_DICT)
5224 {
5225 dict_T *d = what_arg->vval.v_dict;
5226
5227 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005228 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005229 }
5230 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005231 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005232 }
5233 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005234}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005235#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005236
5237/*
5238 * "getloclist()" function
5239 */
5240 static void
5241f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5242{
5243#ifdef FEAT_QUICKFIX
5244 win_T *wp;
5245
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005246 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005247 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5248#endif
5249}
5250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005251/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005252 * "getpid()" function
5253 */
5254 static void
5255f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5256{
5257 rettv->vval.v_number = mch_get_pid();
5258}
5259
5260 static void
5261getpos_both(
5262 typval_T *argvars,
5263 typval_T *rettv,
5264 int getcurpos)
5265{
5266 pos_T *fp;
5267 list_T *l;
5268 int fnum = -1;
5269
5270 if (rettv_list_alloc(rettv) == OK)
5271 {
5272 l = rettv->vval.v_list;
5273 if (getcurpos)
5274 fp = &curwin->w_cursor;
5275 else
5276 fp = var2fpos(&argvars[0], TRUE, &fnum);
5277 if (fnum != -1)
5278 list_append_number(l, (varnumber_T)fnum);
5279 else
5280 list_append_number(l, (varnumber_T)0);
5281 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5282 : (varnumber_T)0);
5283 list_append_number(l, (fp != NULL)
5284 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5285 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005286 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005287 (varnumber_T)0);
5288 if (getcurpos)
5289 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005290 int save_set_curswant = curwin->w_set_curswant;
5291 colnr_T save_curswant = curwin->w_curswant;
5292 colnr_T save_virtcol = curwin->w_virtcol;
5293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 update_curswant();
5295 list_append_number(l, curwin->w_curswant == MAXCOL ?
5296 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005297
5298 // Do not change "curswant", as it is unexpected that a get
5299 // function has a side effect.
5300 if (save_set_curswant)
5301 {
5302 curwin->w_set_curswant = save_set_curswant;
5303 curwin->w_curswant = save_curswant;
5304 curwin->w_virtcol = save_virtcol;
5305 curwin->w_valid &= ~VALID_VIRTCOL;
5306 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005307 }
5308 }
5309 else
5310 rettv->vval.v_number = FALSE;
5311}
5312
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005313/*
5314 * "getcurpos()" function
5315 */
5316 static void
5317f_getcurpos(typval_T *argvars, typval_T *rettv)
5318{
5319 getpos_both(argvars, rettv, TRUE);
5320}
5321
5322/*
5323 * "getpos(string)" function
5324 */
5325 static void
5326f_getpos(typval_T *argvars, typval_T *rettv)
5327{
5328 getpos_both(argvars, rettv, FALSE);
5329}
5330
5331/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005332 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005333 */
5334 static void
5335f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5336{
5337#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005338 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005339#endif
5340}
5341
5342/*
5343 * "getreg()" function
5344 */
5345 static void
5346f_getreg(typval_T *argvars, typval_T *rettv)
5347{
5348 char_u *strregname;
5349 int regname;
5350 int arg2 = FALSE;
5351 int return_list = FALSE;
5352 int error = FALSE;
5353
5354 if (argvars[0].v_type != VAR_UNKNOWN)
5355 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005356 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005357 error = strregname == NULL;
5358 if (argvars[1].v_type != VAR_UNKNOWN)
5359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005360 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005362 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005363 }
5364 }
5365 else
5366 strregname = get_vim_var_str(VV_REG);
5367
5368 if (error)
5369 return;
5370
5371 regname = (strregname == NULL ? '"' : *strregname);
5372 if (regname == 0)
5373 regname = '"';
5374
5375 if (return_list)
5376 {
5377 rettv->v_type = VAR_LIST;
5378 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5379 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5380 if (rettv->vval.v_list == NULL)
5381 (void)rettv_list_alloc(rettv);
5382 else
5383 ++rettv->vval.v_list->lv_refcount;
5384 }
5385 else
5386 {
5387 rettv->v_type = VAR_STRING;
5388 rettv->vval.v_string = get_reg_contents(regname,
5389 arg2 ? GREG_EXPR_SRC : 0);
5390 }
5391}
5392
5393/*
5394 * "getregtype()" function
5395 */
5396 static void
5397f_getregtype(typval_T *argvars, typval_T *rettv)
5398{
5399 char_u *strregname;
5400 int regname;
5401 char_u buf[NUMBUFLEN + 2];
5402 long reglen = 0;
5403
5404 if (argvars[0].v_type != VAR_UNKNOWN)
5405 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005406 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005407 if (strregname == NULL) /* type error; errmsg already given */
5408 {
5409 rettv->v_type = VAR_STRING;
5410 rettv->vval.v_string = NULL;
5411 return;
5412 }
5413 }
5414 else
5415 /* Default to v:register */
5416 strregname = get_vim_var_str(VV_REG);
5417
5418 regname = (strregname == NULL ? '"' : *strregname);
5419 if (regname == 0)
5420 regname = '"';
5421
5422 buf[0] = NUL;
5423 buf[1] = NUL;
5424 switch (get_reg_type(regname, &reglen))
5425 {
5426 case MLINE: buf[0] = 'V'; break;
5427 case MCHAR: buf[0] = 'v'; break;
5428 case MBLOCK:
5429 buf[0] = Ctrl_V;
5430 sprintf((char *)buf + 1, "%ld", reglen + 1);
5431 break;
5432 }
5433 rettv->v_type = VAR_STRING;
5434 rettv->vval.v_string = vim_strsave(buf);
5435}
5436
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005437/*
5438 * Returns information (variables, options, etc.) about a tab page
5439 * as a dictionary.
5440 */
5441 static dict_T *
5442get_tabpage_info(tabpage_T *tp, int tp_idx)
5443{
5444 win_T *wp;
5445 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005446 list_T *l;
5447
5448 dict = dict_alloc();
5449 if (dict == NULL)
5450 return NULL;
5451
Bram Moolenaare0be1672018-07-08 16:50:37 +02005452 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005453
5454 l = list_alloc();
5455 if (l != NULL)
5456 {
5457 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005458 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005459 list_append_number(l, (varnumber_T)wp->w_id);
5460 dict_add_list(dict, "windows", l);
5461 }
5462
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005463 /* Make a reference to tabpage variables */
5464 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005465
5466 return dict;
5467}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005468
5469/*
5470 * "gettabinfo()" function
5471 */
5472 static void
5473f_gettabinfo(typval_T *argvars, typval_T *rettv)
5474{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005475 tabpage_T *tp, *tparg = NULL;
5476 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005477 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005478
5479 if (rettv_list_alloc(rettv) != OK)
5480 return;
5481
5482 if (argvars[0].v_type != VAR_UNKNOWN)
5483 {
5484 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005485 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005486 if (tparg == NULL)
5487 return;
5488 }
5489
5490 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005491 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005492 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005493 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005494 if (tparg != NULL && tp != tparg)
5495 continue;
5496 d = get_tabpage_info(tp, tpnr);
5497 if (d != NULL)
5498 list_append_dict(rettv->vval.v_list, d);
5499 if (tparg != NULL)
5500 return;
5501 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005502}
5503
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504/*
5505 * "gettabvar()" function
5506 */
5507 static void
5508f_gettabvar(typval_T *argvars, typval_T *rettv)
5509{
5510 win_T *oldcurwin;
5511 tabpage_T *tp, *oldtabpage;
5512 dictitem_T *v;
5513 char_u *varname;
5514 int done = FALSE;
5515
5516 rettv->v_type = VAR_STRING;
5517 rettv->vval.v_string = NULL;
5518
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005519 varname = tv_get_string_chk(&argvars[1]);
5520 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 if (tp != NULL && varname != NULL)
5522 {
5523 /* Set tp to be our tabpage, temporarily. Also set the window to the
5524 * first window in the tabpage, otherwise the window is not valid. */
5525 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005526 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5527 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528 {
5529 /* look up the variable */
5530 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5531 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5532 if (v != NULL)
5533 {
5534 copy_tv(&v->di_tv, rettv);
5535 done = TRUE;
5536 }
5537 }
5538
5539 /* restore previous notion of curwin */
5540 restore_win(oldcurwin, oldtabpage, TRUE);
5541 }
5542
5543 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5544 copy_tv(&argvars[2], rettv);
5545}
5546
5547/*
5548 * "gettabwinvar()" function
5549 */
5550 static void
5551f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5552{
5553 getwinvar(argvars, rettv, 1);
5554}
5555
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005556/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005557 * "gettagstack()" function
5558 */
5559 static void
5560f_gettagstack(typval_T *argvars, typval_T *rettv)
5561{
5562 win_T *wp = curwin; // default is current window
5563
5564 if (rettv_dict_alloc(rettv) != OK)
5565 return;
5566
5567 if (argvars[0].v_type != VAR_UNKNOWN)
5568 {
5569 wp = find_win_by_nr_or_id(&argvars[0]);
5570 if (wp == NULL)
5571 return;
5572 }
5573
5574 get_tagstack(wp, rettv->vval.v_dict);
5575}
5576
5577/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005578 * Returns information about a window as a dictionary.
5579 */
5580 static dict_T *
5581get_win_info(win_T *wp, short tpnr, short winnr)
5582{
5583 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005584
5585 dict = dict_alloc();
5586 if (dict == NULL)
5587 return NULL;
5588
Bram Moolenaare0be1672018-07-08 16:50:37 +02005589 dict_add_number(dict, "tabnr", tpnr);
5590 dict_add_number(dict, "winnr", winnr);
5591 dict_add_number(dict, "winid", wp->w_id);
5592 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005593 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005594 dict_add_number(dict, "topline", wp->w_topline);
5595 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005596#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005597 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005598#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005599 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005600 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005601 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005602
Bram Moolenaar69905d12017-08-13 18:14:47 +02005603#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005604 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005605#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005606#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005607 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5608 dict_add_number(dict, "loclist",
5609 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005610#endif
5611
Bram Moolenaar30567352016-08-27 21:25:44 +02005612 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005613 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005614
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005615 return dict;
5616}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005617
5618/*
5619 * "getwininfo()" function
5620 */
5621 static void
5622f_getwininfo(typval_T *argvars, typval_T *rettv)
5623{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005624 tabpage_T *tp;
5625 win_T *wp = NULL, *wparg = NULL;
5626 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005627 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005628
5629 if (rettv_list_alloc(rettv) != OK)
5630 return;
5631
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632 if (argvars[0].v_type != VAR_UNKNOWN)
5633 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005634 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005635 if (wparg == NULL)
5636 return;
5637 }
5638
5639 /* Collect information about either all the windows across all the tab
5640 * pages or one particular window.
5641 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005642 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005643 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005644 tabnr++;
5645 winnr = 0;
5646 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005647 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005648 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005649 if (wparg != NULL && wp != wparg)
5650 continue;
5651 d = get_win_info(wp, tabnr, winnr);
5652 if (d != NULL)
5653 list_append_dict(rettv->vval.v_list, d);
5654 if (wparg != NULL)
5655 /* found information about a specific window */
5656 return;
5657 }
5658 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005659}
5660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005661/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005662 * "win_execute()" function
5663 */
5664 static void
5665f_win_execute(typval_T *argvars, typval_T *rettv)
5666{
5667 int id = (int)tv_get_number(argvars);
5668 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005669 win_T *save_curwin;
5670 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005671
5672 if (wp != NULL)
5673 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005674 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5675 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005676 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005677 check_cursor();
5678 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005679 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005680 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005681 }
5682}
5683
5684/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685 * "win_findbuf()" function
5686 */
5687 static void
5688f_win_findbuf(typval_T *argvars, typval_T *rettv)
5689{
5690 if (rettv_list_alloc(rettv) != FAIL)
5691 win_findbuf(argvars, rettv->vval.v_list);
5692}
5693
5694/*
5695 * "win_getid()" function
5696 */
5697 static void
5698f_win_getid(typval_T *argvars, typval_T *rettv)
5699{
5700 rettv->vval.v_number = win_getid(argvars);
5701}
5702
5703/*
5704 * "win_gotoid()" function
5705 */
5706 static void
5707f_win_gotoid(typval_T *argvars, typval_T *rettv)
5708{
5709 rettv->vval.v_number = win_gotoid(argvars);
5710}
5711
5712/*
5713 * "win_id2tabwin()" function
5714 */
5715 static void
5716f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5717{
5718 if (rettv_list_alloc(rettv) != FAIL)
5719 win_id2tabwin(argvars, rettv->vval.v_list);
5720}
5721
5722/*
5723 * "win_id2win()" function
5724 */
5725 static void
5726f_win_id2win(typval_T *argvars, typval_T *rettv)
5727{
5728 rettv->vval.v_number = win_id2win(argvars);
5729}
5730
5731/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005732 * "win_screenpos()" function
5733 */
5734 static void
5735f_win_screenpos(typval_T *argvars, typval_T *rettv)
5736{
5737 win_T *wp;
5738
5739 if (rettv_list_alloc(rettv) == FAIL)
5740 return;
5741
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005742 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005743 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5744 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5745}
5746
5747/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005748 * "getwinpos({timeout})" function
5749 */
5750 static void
5751f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5752{
5753 int x = -1;
5754 int y = -1;
5755
5756 if (rettv_list_alloc(rettv) == FAIL)
5757 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005758#if defined(FEAT_GUI) \
5759 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5760 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005761 {
5762 varnumber_T timeout = 100;
5763
5764 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005765 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005766
5767 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005768 }
5769#endif
5770 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5771 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5772}
5773
5774
5775/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005776 * "getwinposx()" function
5777 */
5778 static void
5779f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5780{
5781 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005782#if defined(FEAT_GUI) \
5783 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5784 || defined(MSWIN)
5785
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005786 {
5787 int x, y;
5788
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005789 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005790 rettv->vval.v_number = x;
5791 }
5792#endif
5793}
5794
5795/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796 * "getwinposy()" function
5797 */
5798 static void
5799f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5800{
5801 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005802#if defined(FEAT_GUI) \
5803 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5804 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005805 {
5806 int x, y;
5807
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005808 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005809 rettv->vval.v_number = y;
5810 }
5811#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005812}
5813
5814/*
5815 * "getwinvar()" function
5816 */
5817 static void
5818f_getwinvar(typval_T *argvars, typval_T *rettv)
5819{
5820 getwinvar(argvars, rettv, 0);
5821}
5822
5823/*
5824 * "glob()" function
5825 */
5826 static void
5827f_glob(typval_T *argvars, typval_T *rettv)
5828{
5829 int options = WILD_SILENT|WILD_USE_NL;
5830 expand_T xpc;
5831 int error = FALSE;
5832
5833 /* When the optional second argument is non-zero, don't remove matches
5834 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5835 rettv->v_type = VAR_STRING;
5836 if (argvars[1].v_type != VAR_UNKNOWN)
5837 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005838 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839 options |= WILD_KEEP_ALL;
5840 if (argvars[2].v_type != VAR_UNKNOWN)
5841 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005842 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005843 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005844 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005845 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005846 options |= WILD_ALLLINKS;
5847 }
5848 }
5849 if (!error)
5850 {
5851 ExpandInit(&xpc);
5852 xpc.xp_context = EXPAND_FILES;
5853 if (p_wic)
5854 options += WILD_ICASE;
5855 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005856 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857 NULL, options, WILD_ALL);
5858 else if (rettv_list_alloc(rettv) != FAIL)
5859 {
5860 int i;
5861
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005862 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005863 NULL, options, WILD_ALL_KEEP);
5864 for (i = 0; i < xpc.xp_numfiles; i++)
5865 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5866
5867 ExpandCleanup(&xpc);
5868 }
5869 }
5870 else
5871 rettv->vval.v_string = NULL;
5872}
5873
5874/*
5875 * "globpath()" function
5876 */
5877 static void
5878f_globpath(typval_T *argvars, typval_T *rettv)
5879{
5880 int flags = 0;
5881 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005882 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883 int error = FALSE;
5884 garray_T ga;
5885 int i;
5886
5887 /* When the optional second argument is non-zero, don't remove matches
5888 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5889 rettv->v_type = VAR_STRING;
5890 if (argvars[2].v_type != VAR_UNKNOWN)
5891 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005892 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005893 flags |= WILD_KEEP_ALL;
5894 if (argvars[3].v_type != VAR_UNKNOWN)
5895 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005896 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005897 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005899 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900 flags |= WILD_ALLLINKS;
5901 }
5902 }
5903 if (file != NULL && !error)
5904 {
5905 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005906 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005907 if (rettv->v_type == VAR_STRING)
5908 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5909 else if (rettv_list_alloc(rettv) != FAIL)
5910 for (i = 0; i < ga.ga_len; ++i)
5911 list_append_string(rettv->vval.v_list,
5912 ((char_u **)(ga.ga_data))[i], -1);
5913 ga_clear_strings(&ga);
5914 }
5915 else
5916 rettv->vval.v_string = NULL;
5917}
5918
5919/*
5920 * "glob2regpat()" function
5921 */
5922 static void
5923f_glob2regpat(typval_T *argvars, typval_T *rettv)
5924{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005925 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005926
5927 rettv->v_type = VAR_STRING;
5928 rettv->vval.v_string = (pat == NULL)
5929 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5930}
5931
5932/* for VIM_VERSION_ defines */
5933#include "version.h"
5934
5935/*
5936 * "has()" function
5937 */
5938 static void
5939f_has(typval_T *argvars, typval_T *rettv)
5940{
5941 int i;
5942 char_u *name;
5943 int n = FALSE;
5944 static char *(has_list[]) =
5945 {
5946#ifdef AMIGA
5947 "amiga",
5948# ifdef FEAT_ARP
5949 "arp",
5950# endif
5951#endif
5952#ifdef __BEOS__
5953 "beos",
5954#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005955#if defined(BSD) && !defined(MACOS_X)
5956 "bsd",
5957#endif
5958#ifdef hpux
5959 "hpux",
5960#endif
5961#ifdef __linux__
5962 "linux",
5963#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005964#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005965 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5966 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005967# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005968 "macunix", /* Mac OS X, with the darwin feature */
5969 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005970# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005971#endif
5972#ifdef __QNX__
5973 "qnx",
5974#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005975#ifdef SUN_SYSTEM
5976 "sun",
5977#else
5978 "moon",
5979#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980#ifdef UNIX
5981 "unix",
5982#endif
5983#ifdef VMS
5984 "vms",
5985#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005986#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005987 "win32",
5988#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005989#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005990 "win32unix",
5991#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005992#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005993 "win64",
5994#endif
5995#ifdef EBCDIC
5996 "ebcdic",
5997#endif
5998#ifndef CASE_INSENSITIVE_FILENAME
5999 "fname_case",
6000#endif
6001#ifdef HAVE_ACL
6002 "acl",
6003#endif
6004#ifdef FEAT_ARABIC
6005 "arabic",
6006#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006007 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006008#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006009 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006010#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006011#ifdef FEAT_AUTOSERVERNAME
6012 "autoservername",
6013#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006014#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006015 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006016# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 "balloon_multiline",
6018# endif
6019#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006020#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006021 "balloon_eval_term",
6022#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6024 "builtin_terms",
6025# ifdef ALL_BUILTIN_TCAPS
6026 "all_builtin_terms",
6027# endif
6028#endif
6029#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006030 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031 || defined(FEAT_GUI_MOTIF))
6032 "browsefilter",
6033#endif
6034#ifdef FEAT_BYTEOFF
6035 "byte_offset",
6036#endif
6037#ifdef FEAT_JOB_CHANNEL
6038 "channel",
6039#endif
6040#ifdef FEAT_CINDENT
6041 "cindent",
6042#endif
6043#ifdef FEAT_CLIENTSERVER
6044 "clientserver",
6045#endif
6046#ifdef FEAT_CLIPBOARD
6047 "clipboard",
6048#endif
6049#ifdef FEAT_CMDL_COMPL
6050 "cmdline_compl",
6051#endif
6052#ifdef FEAT_CMDHIST
6053 "cmdline_hist",
6054#endif
6055#ifdef FEAT_COMMENTS
6056 "comments",
6057#endif
6058#ifdef FEAT_CONCEAL
6059 "conceal",
6060#endif
6061#ifdef FEAT_CRYPT
6062 "cryptv",
6063 "crypt-blowfish",
6064 "crypt-blowfish2",
6065#endif
6066#ifdef FEAT_CSCOPE
6067 "cscope",
6068#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006069 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006070#ifdef CURSOR_SHAPE
6071 "cursorshape",
6072#endif
6073#ifdef DEBUG
6074 "debug",
6075#endif
6076#ifdef FEAT_CON_DIALOG
6077 "dialog_con",
6078#endif
6079#ifdef FEAT_GUI_DIALOG
6080 "dialog_gui",
6081#endif
6082#ifdef FEAT_DIFF
6083 "diff",
6084#endif
6085#ifdef FEAT_DIGRAPHS
6086 "digraphs",
6087#endif
6088#ifdef FEAT_DIRECTX
6089 "directx",
6090#endif
6091#ifdef FEAT_DND
6092 "dnd",
6093#endif
6094#ifdef FEAT_EMACS_TAGS
6095 "emacs_tags",
6096#endif
6097 "eval", /* always present, of course! */
6098 "ex_extra", /* graduated feature */
6099#ifdef FEAT_SEARCH_EXTRA
6100 "extra_search",
6101#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006102#ifdef FEAT_SEARCHPATH
6103 "file_in_path",
6104#endif
6105#ifdef FEAT_FILTERPIPE
6106 "filterpipe",
6107#endif
6108#ifdef FEAT_FIND_ID
6109 "find_in_path",
6110#endif
6111#ifdef FEAT_FLOAT
6112 "float",
6113#endif
6114#ifdef FEAT_FOLDING
6115 "folding",
6116#endif
6117#ifdef FEAT_FOOTER
6118 "footer",
6119#endif
6120#if !defined(USE_SYSTEM) && defined(UNIX)
6121 "fork",
6122#endif
6123#ifdef FEAT_GETTEXT
6124 "gettext",
6125#endif
6126#ifdef FEAT_GUI
6127 "gui",
6128#endif
6129#ifdef FEAT_GUI_ATHENA
6130# ifdef FEAT_GUI_NEXTAW
6131 "gui_neXtaw",
6132# else
6133 "gui_athena",
6134# endif
6135#endif
6136#ifdef FEAT_GUI_GTK
6137 "gui_gtk",
6138# ifdef USE_GTK3
6139 "gui_gtk3",
6140# else
6141 "gui_gtk2",
6142# endif
6143#endif
6144#ifdef FEAT_GUI_GNOME
6145 "gui_gnome",
6146#endif
6147#ifdef FEAT_GUI_MAC
6148 "gui_mac",
6149#endif
6150#ifdef FEAT_GUI_MOTIF
6151 "gui_motif",
6152#endif
6153#ifdef FEAT_GUI_PHOTON
6154 "gui_photon",
6155#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006156#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006157 "gui_win32",
6158#endif
6159#ifdef FEAT_HANGULIN
6160 "hangul_input",
6161#endif
6162#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6163 "iconv",
6164#endif
6165#ifdef FEAT_INS_EXPAND
6166 "insert_expand",
6167#endif
6168#ifdef FEAT_JOB_CHANNEL
6169 "job",
6170#endif
6171#ifdef FEAT_JUMPLIST
6172 "jumplist",
6173#endif
6174#ifdef FEAT_KEYMAP
6175 "keymap",
6176#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006177 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006178#ifdef FEAT_LANGMAP
6179 "langmap",
6180#endif
6181#ifdef FEAT_LIBCALL
6182 "libcall",
6183#endif
6184#ifdef FEAT_LINEBREAK
6185 "linebreak",
6186#endif
6187#ifdef FEAT_LISP
6188 "lispindent",
6189#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191#ifdef FEAT_LOCALMAP
6192 "localmap",
6193#endif
6194#ifdef FEAT_LUA
6195# ifndef DYNAMIC_LUA
6196 "lua",
6197# endif
6198#endif
6199#ifdef FEAT_MENU
6200 "menu",
6201#endif
6202#ifdef FEAT_SESSION
6203 "mksession",
6204#endif
6205#ifdef FEAT_MODIFY_FNAME
6206 "modify_fname",
6207#endif
6208#ifdef FEAT_MOUSE
6209 "mouse",
6210#endif
6211#ifdef FEAT_MOUSESHAPE
6212 "mouseshape",
6213#endif
6214#if defined(UNIX) || defined(VMS)
6215# ifdef FEAT_MOUSE_DEC
6216 "mouse_dec",
6217# endif
6218# ifdef FEAT_MOUSE_GPM
6219 "mouse_gpm",
6220# endif
6221# ifdef FEAT_MOUSE_JSB
6222 "mouse_jsbterm",
6223# endif
6224# ifdef FEAT_MOUSE_NET
6225 "mouse_netterm",
6226# endif
6227# ifdef FEAT_MOUSE_PTERM
6228 "mouse_pterm",
6229# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006230# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006231 "mouse_sgr",
6232# endif
6233# ifdef FEAT_SYSMOUSE
6234 "mouse_sysmouse",
6235# endif
6236# ifdef FEAT_MOUSE_URXVT
6237 "mouse_urxvt",
6238# endif
6239# ifdef FEAT_MOUSE_XTERM
6240 "mouse_xterm",
6241# endif
6242#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006243 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006244#ifdef FEAT_MBYTE_IME
6245 "multi_byte_ime",
6246#endif
6247#ifdef FEAT_MULTI_LANG
6248 "multi_lang",
6249#endif
6250#ifdef FEAT_MZSCHEME
6251#ifndef DYNAMIC_MZSCHEME
6252 "mzscheme",
6253#endif
6254#endif
6255#ifdef FEAT_NUM64
6256 "num64",
6257#endif
6258#ifdef FEAT_OLE
6259 "ole",
6260#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006261#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006262 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006263#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264#ifdef FEAT_PATH_EXTRA
6265 "path_extra",
6266#endif
6267#ifdef FEAT_PERL
6268#ifndef DYNAMIC_PERL
6269 "perl",
6270#endif
6271#endif
6272#ifdef FEAT_PERSISTENT_UNDO
6273 "persistent_undo",
6274#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006275#if defined(FEAT_PYTHON)
6276 "python_compiled",
6277# if defined(DYNAMIC_PYTHON)
6278 "python_dynamic",
6279# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006281 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006282# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006284#if defined(FEAT_PYTHON3)
6285 "python3_compiled",
6286# if defined(DYNAMIC_PYTHON3)
6287 "python3_dynamic",
6288# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006289 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006290 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006291# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006292#endif
6293#ifdef FEAT_POSTSCRIPT
6294 "postscript",
6295#endif
6296#ifdef FEAT_PRINTER
6297 "printer",
6298#endif
6299#ifdef FEAT_PROFILE
6300 "profile",
6301#endif
6302#ifdef FEAT_RELTIME
6303 "reltime",
6304#endif
6305#ifdef FEAT_QUICKFIX
6306 "quickfix",
6307#endif
6308#ifdef FEAT_RIGHTLEFT
6309 "rightleft",
6310#endif
6311#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6312 "ruby",
6313#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006314 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315#ifdef FEAT_CMDL_INFO
6316 "showcmd",
6317 "cmdline_info",
6318#endif
6319#ifdef FEAT_SIGNS
6320 "signs",
6321#endif
6322#ifdef FEAT_SMARTINDENT
6323 "smartindent",
6324#endif
6325#ifdef STARTUPTIME
6326 "startuptime",
6327#endif
6328#ifdef FEAT_STL_OPT
6329 "statusline",
6330#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006331#ifdef FEAT_NETBEANS_INTG
6332 "netbeans_intg",
6333#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006334#ifdef FEAT_SOUND
6335 "sound",
6336#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337#ifdef FEAT_SPELL
6338 "spell",
6339#endif
6340#ifdef FEAT_SYN_HL
6341 "syntax",
6342#endif
6343#if defined(USE_SYSTEM) || !defined(UNIX)
6344 "system",
6345#endif
6346#ifdef FEAT_TAG_BINS
6347 "tag_binary",
6348#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006349#ifdef FEAT_TCL
6350# ifndef DYNAMIC_TCL
6351 "tcl",
6352# endif
6353#endif
6354#ifdef FEAT_TERMGUICOLORS
6355 "termguicolors",
6356#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006357#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006358 "terminal",
6359#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360#ifdef TERMINFO
6361 "terminfo",
6362#endif
6363#ifdef FEAT_TERMRESPONSE
6364 "termresponse",
6365#endif
6366#ifdef FEAT_TEXTOBJ
6367 "textobjects",
6368#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006369#ifdef FEAT_TEXT_PROP
6370 "textprop",
6371#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372#ifdef HAVE_TGETENT
6373 "tgetent",
6374#endif
6375#ifdef FEAT_TIMERS
6376 "timers",
6377#endif
6378#ifdef FEAT_TITLE
6379 "title",
6380#endif
6381#ifdef FEAT_TOOLBAR
6382 "toolbar",
6383#endif
6384#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6385 "unnamedplus",
6386#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387 "user-commands", /* was accidentally included in 5.4 */
6388 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006389#ifdef FEAT_VARTABS
6390 "vartabs",
6391#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006392 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393#ifdef FEAT_VIMINFO
6394 "viminfo",
6395#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006396 "vimscript-1",
6397 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006398 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006401 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006402 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006403#ifdef FEAT_VTP
6404 "vtp",
6405#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406#ifdef FEAT_WILDIGN
6407 "wildignore",
6408#endif
6409#ifdef FEAT_WILDMENU
6410 "wildmenu",
6411#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006413#ifdef FEAT_WAK
6414 "winaltkeys",
6415#endif
6416#ifdef FEAT_WRITEBACKUP
6417 "writebackup",
6418#endif
6419#ifdef FEAT_XIM
6420 "xim",
6421#endif
6422#ifdef FEAT_XFONTSET
6423 "xfontset",
6424#endif
6425#ifdef FEAT_XPM_W32
6426 "xpm",
6427 "xpm_w32", /* for backward compatibility */
6428#else
6429# if defined(HAVE_XPM)
6430 "xpm",
6431# endif
6432#endif
6433#ifdef USE_XSMP
6434 "xsmp",
6435#endif
6436#ifdef USE_XSMP_INTERACT
6437 "xsmp_interact",
6438#endif
6439#ifdef FEAT_XCLIPBOARD
6440 "xterm_clipboard",
6441#endif
6442#ifdef FEAT_XTERM_SAVE
6443 "xterm_save",
6444#endif
6445#if defined(UNIX) && defined(FEAT_X11)
6446 "X11",
6447#endif
6448 NULL
6449 };
6450
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006451 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 for (i = 0; has_list[i] != NULL; ++i)
6453 if (STRICMP(name, has_list[i]) == 0)
6454 {
6455 n = TRUE;
6456 break;
6457 }
6458
6459 if (n == FALSE)
6460 {
6461 if (STRNICMP(name, "patch", 5) == 0)
6462 {
6463 if (name[5] == '-'
6464 && STRLEN(name) >= 11
6465 && vim_isdigit(name[6])
6466 && vim_isdigit(name[8])
6467 && vim_isdigit(name[10]))
6468 {
6469 int major = atoi((char *)name + 6);
6470 int minor = atoi((char *)name + 8);
6471
6472 /* Expect "patch-9.9.01234". */
6473 n = (major < VIM_VERSION_MAJOR
6474 || (major == VIM_VERSION_MAJOR
6475 && (minor < VIM_VERSION_MINOR
6476 || (minor == VIM_VERSION_MINOR
6477 && has_patch(atoi((char *)name + 10))))));
6478 }
6479 else
6480 n = has_patch(atoi((char *)name + 5));
6481 }
6482 else if (STRICMP(name, "vim_starting") == 0)
6483 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006484 else if (STRICMP(name, "ttyin") == 0)
6485 n = mch_input_isatty();
6486 else if (STRICMP(name, "ttyout") == 0)
6487 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006488 else if (STRICMP(name, "multi_byte_encoding") == 0)
6489 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006490#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 else if (STRICMP(name, "balloon_multiline") == 0)
6492 n = multiline_balloon_available();
6493#endif
6494#ifdef DYNAMIC_TCL
6495 else if (STRICMP(name, "tcl") == 0)
6496 n = tcl_enabled(FALSE);
6497#endif
6498#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6499 else if (STRICMP(name, "iconv") == 0)
6500 n = iconv_enabled(FALSE);
6501#endif
6502#ifdef DYNAMIC_LUA
6503 else if (STRICMP(name, "lua") == 0)
6504 n = lua_enabled(FALSE);
6505#endif
6506#ifdef DYNAMIC_MZSCHEME
6507 else if (STRICMP(name, "mzscheme") == 0)
6508 n = mzscheme_enabled(FALSE);
6509#endif
6510#ifdef DYNAMIC_RUBY
6511 else if (STRICMP(name, "ruby") == 0)
6512 n = ruby_enabled(FALSE);
6513#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514#ifdef DYNAMIC_PYTHON
6515 else if (STRICMP(name, "python") == 0)
6516 n = python_enabled(FALSE);
6517#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518#ifdef DYNAMIC_PYTHON3
6519 else if (STRICMP(name, "python3") == 0)
6520 n = python3_enabled(FALSE);
6521#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006522#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6523 else if (STRICMP(name, "pythonx") == 0)
6524 {
6525# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6526 if (p_pyx == 0)
6527 n = python3_enabled(FALSE) || python_enabled(FALSE);
6528 else if (p_pyx == 3)
6529 n = python3_enabled(FALSE);
6530 else if (p_pyx == 2)
6531 n = python_enabled(FALSE);
6532# elif defined(DYNAMIC_PYTHON)
6533 n = python_enabled(FALSE);
6534# elif defined(DYNAMIC_PYTHON3)
6535 n = python3_enabled(FALSE);
6536# endif
6537 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538#endif
6539#ifdef DYNAMIC_PERL
6540 else if (STRICMP(name, "perl") == 0)
6541 n = perl_enabled(FALSE);
6542#endif
6543#ifdef FEAT_GUI
6544 else if (STRICMP(name, "gui_running") == 0)
6545 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006546# ifdef FEAT_BROWSE
6547 else if (STRICMP(name, "browse") == 0)
6548 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6549# endif
6550#endif
6551#ifdef FEAT_SYN_HL
6552 else if (STRICMP(name, "syntax_items") == 0)
6553 n = syntax_present(curwin);
6554#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006555#ifdef FEAT_VTP
6556 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006557 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006558#endif
6559#ifdef FEAT_NETBEANS_INTG
6560 else if (STRICMP(name, "netbeans_enabled") == 0)
6561 n = netbeans_active();
6562#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006563#ifdef FEAT_MOUSE_GPM
6564 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6565 n = gpm_enabled();
6566#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006567#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006568 else if (STRICMP(name, "terminal") == 0)
6569 n = terminal_enabled();
6570#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006571#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006572 else if (STRICMP(name, "conpty") == 0)
6573 n = use_conpty();
6574#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006575 }
6576
6577 rettv->vval.v_number = n;
6578}
6579
6580/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006581 * "haslocaldir()" function
6582 */
6583 static void
6584f_haslocaldir(typval_T *argvars, typval_T *rettv)
6585{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006586 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006587 win_T *wp = NULL;
6588
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006589 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6590
6591 // Check for window-local and tab-local directories
6592 if (wp != NULL && wp->w_localdir != NULL)
6593 rettv->vval.v_number = 1;
6594 else if (tp != NULL && tp->tp_localdir != NULL)
6595 rettv->vval.v_number = 2;
6596 else
6597 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006598}
6599
6600/*
6601 * "hasmapto()" function
6602 */
6603 static void
6604f_hasmapto(typval_T *argvars, typval_T *rettv)
6605{
6606 char_u *name;
6607 char_u *mode;
6608 char_u buf[NUMBUFLEN];
6609 int abbr = FALSE;
6610
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006611 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006612 if (argvars[1].v_type == VAR_UNKNOWN)
6613 mode = (char_u *)"nvo";
6614 else
6615 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006616 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006617 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006618 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006619 }
6620
6621 if (map_to_exists(name, mode, abbr))
6622 rettv->vval.v_number = TRUE;
6623 else
6624 rettv->vval.v_number = FALSE;
6625}
6626
6627/*
6628 * "histadd()" function
6629 */
6630 static void
6631f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6632{
6633#ifdef FEAT_CMDHIST
6634 int histype;
6635 char_u *str;
6636 char_u buf[NUMBUFLEN];
6637#endif
6638
6639 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006640 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 return;
6642#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006643 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006644 histype = str != NULL ? get_histtype(str) : -1;
6645 if (histype >= 0)
6646 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006647 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006648 if (*str != NUL)
6649 {
6650 init_history();
6651 add_to_history(histype, str, FALSE, NUL);
6652 rettv->vval.v_number = TRUE;
6653 return;
6654 }
6655 }
6656#endif
6657}
6658
6659/*
6660 * "histdel()" function
6661 */
6662 static void
6663f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6664{
6665#ifdef FEAT_CMDHIST
6666 int n;
6667 char_u buf[NUMBUFLEN];
6668 char_u *str;
6669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006670 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671 if (str == NULL)
6672 n = 0;
6673 else if (argvars[1].v_type == VAR_UNKNOWN)
6674 /* only one argument: clear entire history */
6675 n = clr_history(get_histtype(str));
6676 else if (argvars[1].v_type == VAR_NUMBER)
6677 /* index given: remove that entry */
6678 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006679 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006680 else
6681 /* string given: remove all matching entries */
6682 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006683 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006684 rettv->vval.v_number = n;
6685#endif
6686}
6687
6688/*
6689 * "histget()" function
6690 */
6691 static void
6692f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6693{
6694#ifdef FEAT_CMDHIST
6695 int type;
6696 int idx;
6697 char_u *str;
6698
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006699 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 if (str == NULL)
6701 rettv->vval.v_string = NULL;
6702 else
6703 {
6704 type = get_histtype(str);
6705 if (argvars[1].v_type == VAR_UNKNOWN)
6706 idx = get_history_idx(type);
6707 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006708 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006709 /* -1 on type error */
6710 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6711 }
6712#else
6713 rettv->vval.v_string = NULL;
6714#endif
6715 rettv->v_type = VAR_STRING;
6716}
6717
6718/*
6719 * "histnr()" function
6720 */
6721 static void
6722f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6723{
6724 int i;
6725
6726#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006727 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006728
6729 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6730 if (i >= HIST_CMD && i < HIST_COUNT)
6731 i = get_history_idx(i);
6732 else
6733#endif
6734 i = -1;
6735 rettv->vval.v_number = i;
6736}
6737
6738/*
6739 * "highlightID(name)" function
6740 */
6741 static void
6742f_hlID(typval_T *argvars, typval_T *rettv)
6743{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006744 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006745}
6746
6747/*
6748 * "highlight_exists()" function
6749 */
6750 static void
6751f_hlexists(typval_T *argvars, typval_T *rettv)
6752{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006753 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006754}
6755
6756/*
6757 * "hostname()" function
6758 */
6759 static void
6760f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6761{
6762 char_u hostname[256];
6763
6764 mch_get_host_name(hostname, 256);
6765 rettv->v_type = VAR_STRING;
6766 rettv->vval.v_string = vim_strsave(hostname);
6767}
6768
6769/*
6770 * iconv() function
6771 */
6772 static void
6773f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6774{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775 char_u buf1[NUMBUFLEN];
6776 char_u buf2[NUMBUFLEN];
6777 char_u *from, *to, *str;
6778 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779
6780 rettv->v_type = VAR_STRING;
6781 rettv->vval.v_string = NULL;
6782
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006783 str = tv_get_string(&argvars[0]);
6784 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6785 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006786 vimconv.vc_type = CONV_NONE;
6787 convert_setup(&vimconv, from, to);
6788
6789 /* If the encodings are equal, no conversion needed. */
6790 if (vimconv.vc_type == CONV_NONE)
6791 rettv->vval.v_string = vim_strsave(str);
6792 else
6793 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6794
6795 convert_setup(&vimconv, NULL, NULL);
6796 vim_free(from);
6797 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798}
6799
6800/*
6801 * "indent()" function
6802 */
6803 static void
6804f_indent(typval_T *argvars, typval_T *rettv)
6805{
6806 linenr_T lnum;
6807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006808 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006809 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6810 rettv->vval.v_number = get_indent_lnum(lnum);
6811 else
6812 rettv->vval.v_number = -1;
6813}
6814
6815/*
6816 * "index()" function
6817 */
6818 static void
6819f_index(typval_T *argvars, typval_T *rettv)
6820{
6821 list_T *l;
6822 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006823 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006824 long idx = 0;
6825 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006826 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006827
6828 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006829 if (argvars[0].v_type == VAR_BLOB)
6830 {
6831 typval_T tv;
6832 int start = 0;
6833
6834 if (argvars[2].v_type != VAR_UNKNOWN)
6835 {
6836 start = tv_get_number_chk(&argvars[2], &error);
6837 if (error)
6838 return;
6839 }
6840 b = argvars[0].vval.v_blob;
6841 if (b == NULL)
6842 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006843 if (start < 0)
6844 {
6845 start = blob_len(b) + start;
6846 if (start < 0)
6847 start = 0;
6848 }
6849
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006850 for (idx = start; idx < blob_len(b); ++idx)
6851 {
6852 tv.v_type = VAR_NUMBER;
6853 tv.vval.v_number = blob_get(b, idx);
6854 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6855 {
6856 rettv->vval.v_number = idx;
6857 return;
6858 }
6859 }
6860 return;
6861 }
6862 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006863 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006864 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 return;
6866 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006867
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 l = argvars[0].vval.v_list;
6869 if (l != NULL)
6870 {
6871 item = l->lv_first;
6872 if (argvars[2].v_type != VAR_UNKNOWN)
6873 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 /* Start at specified item. Use the cached index that list_find()
6875 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006876 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 idx = l->lv_idx;
6878 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006879 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 if (error)
6881 item = NULL;
6882 }
6883
6884 for ( ; item != NULL; item = item->li_next, ++idx)
6885 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6886 {
6887 rettv->vval.v_number = idx;
6888 break;
6889 }
6890 }
6891}
6892
6893static int inputsecret_flag = 0;
6894
6895/*
6896 * "input()" function
6897 * Also handles inputsecret() when inputsecret is set.
6898 */
6899 static void
6900f_input(typval_T *argvars, typval_T *rettv)
6901{
6902 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6903}
6904
6905/*
6906 * "inputdialog()" function
6907 */
6908 static void
6909f_inputdialog(typval_T *argvars, typval_T *rettv)
6910{
6911#if defined(FEAT_GUI_TEXTDIALOG)
6912 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6913 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6914 {
6915 char_u *message;
6916 char_u buf[NUMBUFLEN];
6917 char_u *defstr = (char_u *)"";
6918
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006919 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006921 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6923 else
6924 IObuff[0] = NUL;
6925 if (message != NULL && defstr != NULL
6926 && do_dialog(VIM_QUESTION, NULL, message,
6927 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6928 rettv->vval.v_string = vim_strsave(IObuff);
6929 else
6930 {
6931 if (message != NULL && defstr != NULL
6932 && argvars[1].v_type != VAR_UNKNOWN
6933 && argvars[2].v_type != VAR_UNKNOWN)
6934 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006935 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 else
6937 rettv->vval.v_string = NULL;
6938 }
6939 rettv->v_type = VAR_STRING;
6940 }
6941 else
6942#endif
6943 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6944}
6945
6946/*
6947 * "inputlist()" function
6948 */
6949 static void
6950f_inputlist(typval_T *argvars, typval_T *rettv)
6951{
6952 listitem_T *li;
6953 int selected;
6954 int mouse_used;
6955
6956#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006957 /* While starting up, there is no place to enter text. When running tests
6958 * with --not-a-term we assume feedkeys() will be used. */
6959 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960 return;
6961#endif
6962 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6963 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006964 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006965 return;
6966 }
6967
6968 msg_start();
6969 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6970 lines_left = Rows; /* avoid more prompt */
6971 msg_scroll = TRUE;
6972 msg_clr_eos();
6973
6974 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6975 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006976 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006977 msg_putchar('\n');
6978 }
6979
6980 /* Ask for choice. */
6981 selected = prompt_for_number(&mouse_used);
6982 if (mouse_used)
6983 selected -= lines_left;
6984
6985 rettv->vval.v_number = selected;
6986}
6987
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006988static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6989
6990/*
6991 * "inputrestore()" function
6992 */
6993 static void
6994f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6995{
6996 if (ga_userinput.ga_len > 0)
6997 {
6998 --ga_userinput.ga_len;
6999 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7000 + ga_userinput.ga_len);
7001 /* default return is zero == OK */
7002 }
7003 else if (p_verbose > 1)
7004 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007005 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007006 rettv->vval.v_number = 1; /* Failed */
7007 }
7008}
7009
7010/*
7011 * "inputsave()" function
7012 */
7013 static void
7014f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7015{
7016 /* Add an entry to the stack of typeahead storage. */
7017 if (ga_grow(&ga_userinput, 1) == OK)
7018 {
7019 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7020 + ga_userinput.ga_len);
7021 ++ga_userinput.ga_len;
7022 /* default return is zero == OK */
7023 }
7024 else
7025 rettv->vval.v_number = 1; /* Failed */
7026}
7027
7028/*
7029 * "inputsecret()" function
7030 */
7031 static void
7032f_inputsecret(typval_T *argvars, typval_T *rettv)
7033{
7034 ++cmdline_star;
7035 ++inputsecret_flag;
7036 f_input(argvars, rettv);
7037 --cmdline_star;
7038 --inputsecret_flag;
7039}
7040
7041/*
7042 * "insert()" function
7043 */
7044 static void
7045f_insert(typval_T *argvars, typval_T *rettv)
7046{
7047 long before = 0;
7048 listitem_T *item;
7049 list_T *l;
7050 int error = FALSE;
7051
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007052 if (argvars[0].v_type == VAR_BLOB)
7053 {
7054 int val, len;
7055 char_u *p;
7056
7057 len = blob_len(argvars[0].vval.v_blob);
7058 if (argvars[2].v_type != VAR_UNKNOWN)
7059 {
7060 before = (long)tv_get_number_chk(&argvars[2], &error);
7061 if (error)
7062 return; // type error; errmsg already given
7063 if (before < 0 || before > len)
7064 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007065 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007066 return;
7067 }
7068 }
7069 val = tv_get_number_chk(&argvars[1], &error);
7070 if (error)
7071 return;
7072 if (val < 0 || val > 255)
7073 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007074 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007075 return;
7076 }
7077
7078 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7079 return;
7080 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7081 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7082 *(p + before) = val;
7083 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7084
7085 copy_tv(&argvars[0], rettv);
7086 }
7087 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007088 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007089 else if ((l = argvars[0].vval.v_list) != NULL
7090 && !var_check_lock(l->lv_lock,
7091 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 {
7093 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007094 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 if (error)
7096 return; /* type error; errmsg already given */
7097
7098 if (before == l->lv_len)
7099 item = NULL;
7100 else
7101 {
7102 item = list_find(l, before);
7103 if (item == NULL)
7104 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007105 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007106 l = NULL;
7107 }
7108 }
7109 if (l != NULL)
7110 {
7111 list_insert_tv(l, &argvars[1], item);
7112 copy_tv(&argvars[0], rettv);
7113 }
7114 }
7115}
7116
7117/*
7118 * "invert(expr)" function
7119 */
7120 static void
7121f_invert(typval_T *argvars, typval_T *rettv)
7122{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007123 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124}
7125
7126/*
7127 * "isdirectory()" function
7128 */
7129 static void
7130f_isdirectory(typval_T *argvars, typval_T *rettv)
7131{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007132 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133}
7134
7135/*
7136 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7137 * or it refers to a List or Dictionary that is locked.
7138 */
7139 static int
7140tv_islocked(typval_T *tv)
7141{
7142 return (tv->v_lock & VAR_LOCKED)
7143 || (tv->v_type == VAR_LIST
7144 && tv->vval.v_list != NULL
7145 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7146 || (tv->v_type == VAR_DICT
7147 && tv->vval.v_dict != NULL
7148 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7149}
7150
7151/*
7152 * "islocked()" function
7153 */
7154 static void
7155f_islocked(typval_T *argvars, typval_T *rettv)
7156{
7157 lval_T lv;
7158 char_u *end;
7159 dictitem_T *di;
7160
7161 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007162 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007163 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 if (end != NULL && lv.ll_name != NULL)
7165 {
7166 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007167 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007168 else
7169 {
7170 if (lv.ll_tv == NULL)
7171 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007172 di = find_var(lv.ll_name, NULL, TRUE);
7173 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007174 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007175 /* Consider a variable locked when:
7176 * 1. the variable itself is locked
7177 * 2. the value of the variable is locked.
7178 * 3. the List or Dict value is locked.
7179 */
7180 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7181 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007182 }
7183 }
7184 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007185 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007187 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 else if (lv.ll_list != NULL)
7189 /* List item. */
7190 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7191 else
7192 /* Dictionary item. */
7193 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7194 }
7195 }
7196
7197 clear_lval(&lv);
7198}
7199
7200#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7201/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007202 * "isinf()" function
7203 */
7204 static void
7205f_isinf(typval_T *argvars, typval_T *rettv)
7206{
7207 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7208 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7209}
7210
7211/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212 * "isnan()" function
7213 */
7214 static void
7215f_isnan(typval_T *argvars, typval_T *rettv)
7216{
7217 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7218 && isnan(argvars[0].vval.v_float);
7219}
7220#endif
7221
7222/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007223 * "last_buffer_nr()" function.
7224 */
7225 static void
7226f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7227{
7228 int n = 0;
7229 buf_T *buf;
7230
Bram Moolenaar29323592016-07-24 22:04:11 +02007231 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007232 if (n < buf->b_fnum)
7233 n = buf->b_fnum;
7234
7235 rettv->vval.v_number = n;
7236}
7237
7238/*
7239 * "len()" function
7240 */
7241 static void
7242f_len(typval_T *argvars, typval_T *rettv)
7243{
7244 switch (argvars[0].v_type)
7245 {
7246 case VAR_STRING:
7247 case VAR_NUMBER:
7248 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007249 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007251 case VAR_BLOB:
7252 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7253 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 case VAR_LIST:
7255 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7256 break;
7257 case VAR_DICT:
7258 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7259 break;
7260 case VAR_UNKNOWN:
7261 case VAR_SPECIAL:
7262 case VAR_FLOAT:
7263 case VAR_FUNC:
7264 case VAR_PARTIAL:
7265 case VAR_JOB:
7266 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007267 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007268 break;
7269 }
7270}
7271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007272 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007273libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274{
7275#ifdef FEAT_LIBCALL
7276 char_u *string_in;
7277 char_u **string_result;
7278 int nr_result;
7279#endif
7280
7281 rettv->v_type = type;
7282 if (type != VAR_NUMBER)
7283 rettv->vval.v_string = NULL;
7284
7285 if (check_restricted() || check_secure())
7286 return;
7287
7288#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007289 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007290 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7291 {
7292 string_in = NULL;
7293 if (argvars[2].v_type == VAR_STRING)
7294 string_in = argvars[2].vval.v_string;
7295 if (type == VAR_NUMBER)
7296 string_result = NULL;
7297 else
7298 string_result = &rettv->vval.v_string;
7299 if (mch_libcall(argvars[0].vval.v_string,
7300 argvars[1].vval.v_string,
7301 string_in,
7302 argvars[2].vval.v_number,
7303 string_result,
7304 &nr_result) == OK
7305 && type == VAR_NUMBER)
7306 rettv->vval.v_number = nr_result;
7307 }
7308#endif
7309}
7310
7311/*
7312 * "libcall()" function
7313 */
7314 static void
7315f_libcall(typval_T *argvars, typval_T *rettv)
7316{
7317 libcall_common(argvars, rettv, VAR_STRING);
7318}
7319
7320/*
7321 * "libcallnr()" function
7322 */
7323 static void
7324f_libcallnr(typval_T *argvars, typval_T *rettv)
7325{
7326 libcall_common(argvars, rettv, VAR_NUMBER);
7327}
7328
7329/*
7330 * "line(string)" function
7331 */
7332 static void
7333f_line(typval_T *argvars, typval_T *rettv)
7334{
7335 linenr_T lnum = 0;
7336 pos_T *fp;
7337 int fnum;
7338
7339 fp = var2fpos(&argvars[0], TRUE, &fnum);
7340 if (fp != NULL)
7341 lnum = fp->lnum;
7342 rettv->vval.v_number = lnum;
7343}
7344
7345/*
7346 * "line2byte(lnum)" function
7347 */
7348 static void
7349f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7350{
7351#ifndef FEAT_BYTEOFF
7352 rettv->vval.v_number = -1;
7353#else
7354 linenr_T lnum;
7355
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007356 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007357 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7358 rettv->vval.v_number = -1;
7359 else
7360 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7361 if (rettv->vval.v_number >= 0)
7362 ++rettv->vval.v_number;
7363#endif
7364}
7365
7366/*
7367 * "lispindent(lnum)" function
7368 */
7369 static void
7370f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7371{
7372#ifdef FEAT_LISP
7373 pos_T pos;
7374 linenr_T lnum;
7375
7376 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7379 {
7380 curwin->w_cursor.lnum = lnum;
7381 rettv->vval.v_number = get_lisp_indent();
7382 curwin->w_cursor = pos;
7383 }
7384 else
7385#endif
7386 rettv->vval.v_number = -1;
7387}
7388
7389/*
7390 * "localtime()" function
7391 */
7392 static void
7393f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7394{
7395 rettv->vval.v_number = (varnumber_T)time(NULL);
7396}
7397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 static void
7399get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7400{
7401 char_u *keys;
7402 char_u *which;
7403 char_u buf[NUMBUFLEN];
7404 char_u *keys_buf = NULL;
7405 char_u *rhs;
7406 int mode;
7407 int abbr = FALSE;
7408 int get_dict = FALSE;
7409 mapblock_T *mp;
7410 int buffer_local;
7411
7412 /* return empty string for failure */
7413 rettv->v_type = VAR_STRING;
7414 rettv->vval.v_string = NULL;
7415
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007416 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007417 if (*keys == NUL)
7418 return;
7419
7420 if (argvars[1].v_type != VAR_UNKNOWN)
7421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007422 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 if (argvars[2].v_type != VAR_UNKNOWN)
7424 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007425 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007427 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 }
7429 }
7430 else
7431 which = (char_u *)"";
7432 if (which == NULL)
7433 return;
7434
7435 mode = get_map_mode(&which, 0);
7436
7437 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7438 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7439 vim_free(keys_buf);
7440
7441 if (!get_dict)
7442 {
7443 /* Return a string. */
7444 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007445 {
7446 if (*rhs == NUL)
7447 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7448 else
7449 rettv->vval.v_string = str2special_save(rhs, FALSE);
7450 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007451
7452 }
7453 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7454 {
7455 /* Return a dictionary. */
7456 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7457 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7458 dict_T *dict = rettv->vval.v_dict;
7459
Bram Moolenaare0be1672018-07-08 16:50:37 +02007460 dict_add_string(dict, "lhs", lhs);
7461 dict_add_string(dict, "rhs", mp->m_orig_str);
7462 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7463 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7464 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007465 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7466 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007467 dict_add_number(dict, "buffer", (long)buffer_local);
7468 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7469 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470
7471 vim_free(lhs);
7472 vim_free(mapmode);
7473 }
7474}
7475
7476#ifdef FEAT_FLOAT
7477/*
7478 * "log()" function
7479 */
7480 static void
7481f_log(typval_T *argvars, typval_T *rettv)
7482{
7483 float_T f = 0.0;
7484
7485 rettv->v_type = VAR_FLOAT;
7486 if (get_float_arg(argvars, &f) == OK)
7487 rettv->vval.v_float = log(f);
7488 else
7489 rettv->vval.v_float = 0.0;
7490}
7491
7492/*
7493 * "log10()" function
7494 */
7495 static void
7496f_log10(typval_T *argvars, typval_T *rettv)
7497{
7498 float_T f = 0.0;
7499
7500 rettv->v_type = VAR_FLOAT;
7501 if (get_float_arg(argvars, &f) == OK)
7502 rettv->vval.v_float = log10(f);
7503 else
7504 rettv->vval.v_float = 0.0;
7505}
7506#endif
7507
7508#ifdef FEAT_LUA
7509/*
7510 * "luaeval()" function
7511 */
7512 static void
7513f_luaeval(typval_T *argvars, typval_T *rettv)
7514{
7515 char_u *str;
7516 char_u buf[NUMBUFLEN];
7517
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007518 if (check_restricted() || check_secure())
7519 return;
7520
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007521 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 do_luaeval(str, argvars + 1, rettv);
7523}
7524#endif
7525
7526/*
7527 * "map()" function
7528 */
7529 static void
7530f_map(typval_T *argvars, typval_T *rettv)
7531{
7532 filter_map(argvars, rettv, TRUE);
7533}
7534
7535/*
7536 * "maparg()" function
7537 */
7538 static void
7539f_maparg(typval_T *argvars, typval_T *rettv)
7540{
7541 get_maparg(argvars, rettv, TRUE);
7542}
7543
7544/*
7545 * "mapcheck()" function
7546 */
7547 static void
7548f_mapcheck(typval_T *argvars, typval_T *rettv)
7549{
7550 get_maparg(argvars, rettv, FALSE);
7551}
7552
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007553typedef enum
7554{
7555 MATCH_END, /* matchend() */
7556 MATCH_MATCH, /* match() */
7557 MATCH_STR, /* matchstr() */
7558 MATCH_LIST, /* matchlist() */
7559 MATCH_POS /* matchstrpos() */
7560} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561
7562 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007563find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007564{
7565 char_u *str = NULL;
7566 long len = 0;
7567 char_u *expr = NULL;
7568 char_u *pat;
7569 regmatch_T regmatch;
7570 char_u patbuf[NUMBUFLEN];
7571 char_u strbuf[NUMBUFLEN];
7572 char_u *save_cpo;
7573 long start = 0;
7574 long nth = 1;
7575 colnr_T startcol = 0;
7576 int match = 0;
7577 list_T *l = NULL;
7578 listitem_T *li = NULL;
7579 long idx = 0;
7580 char_u *tofree = NULL;
7581
7582 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7583 save_cpo = p_cpo;
7584 p_cpo = (char_u *)"";
7585
7586 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007587 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007589 /* type MATCH_LIST: return empty list when there are no matches.
7590 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007591 if (rettv_list_alloc(rettv) == FAIL)
7592 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007593 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007594 && (list_append_string(rettv->vval.v_list,
7595 (char_u *)"", 0) == FAIL
7596 || list_append_number(rettv->vval.v_list,
7597 (varnumber_T)-1) == FAIL
7598 || list_append_number(rettv->vval.v_list,
7599 (varnumber_T)-1) == FAIL
7600 || list_append_number(rettv->vval.v_list,
7601 (varnumber_T)-1) == FAIL))
7602 {
7603 list_free(rettv->vval.v_list);
7604 rettv->vval.v_list = NULL;
7605 goto theend;
7606 }
7607 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007608 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007609 {
7610 rettv->v_type = VAR_STRING;
7611 rettv->vval.v_string = NULL;
7612 }
7613
7614 if (argvars[0].v_type == VAR_LIST)
7615 {
7616 if ((l = argvars[0].vval.v_list) == NULL)
7617 goto theend;
7618 li = l->lv_first;
7619 }
7620 else
7621 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007622 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007623 len = (long)STRLEN(str);
7624 }
7625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007626 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 if (pat == NULL)
7628 goto theend;
7629
7630 if (argvars[2].v_type != VAR_UNKNOWN)
7631 {
7632 int error = FALSE;
7633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007634 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007635 if (error)
7636 goto theend;
7637 if (l != NULL)
7638 {
7639 li = list_find(l, start);
7640 if (li == NULL)
7641 goto theend;
7642 idx = l->lv_idx; /* use the cached index */
7643 }
7644 else
7645 {
7646 if (start < 0)
7647 start = 0;
7648 if (start > len)
7649 goto theend;
7650 /* When "count" argument is there ignore matches before "start",
7651 * otherwise skip part of the string. Differs when pattern is "^"
7652 * or "\<". */
7653 if (argvars[3].v_type != VAR_UNKNOWN)
7654 startcol = start;
7655 else
7656 {
7657 str += start;
7658 len -= start;
7659 }
7660 }
7661
7662 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007663 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007664 if (error)
7665 goto theend;
7666 }
7667
7668 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7669 if (regmatch.regprog != NULL)
7670 {
7671 regmatch.rm_ic = p_ic;
7672
7673 for (;;)
7674 {
7675 if (l != NULL)
7676 {
7677 if (li == NULL)
7678 {
7679 match = FALSE;
7680 break;
7681 }
7682 vim_free(tofree);
7683 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7684 if (str == NULL)
7685 break;
7686 }
7687
7688 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7689
7690 if (match && --nth <= 0)
7691 break;
7692 if (l == NULL && !match)
7693 break;
7694
7695 /* Advance to just after the match. */
7696 if (l != NULL)
7697 {
7698 li = li->li_next;
7699 ++idx;
7700 }
7701 else
7702 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007703 startcol = (colnr_T)(regmatch.startp[0]
7704 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007705 if (startcol > (colnr_T)len
7706 || str + startcol <= regmatch.startp[0])
7707 {
7708 match = FALSE;
7709 break;
7710 }
7711 }
7712 }
7713
7714 if (match)
7715 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007716 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717 {
7718 listitem_T *li1 = rettv->vval.v_list->lv_first;
7719 listitem_T *li2 = li1->li_next;
7720 listitem_T *li3 = li2->li_next;
7721 listitem_T *li4 = li3->li_next;
7722
7723 vim_free(li1->li_tv.vval.v_string);
7724 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7725 (int)(regmatch.endp[0] - regmatch.startp[0]));
7726 li3->li_tv.vval.v_number =
7727 (varnumber_T)(regmatch.startp[0] - expr);
7728 li4->li_tv.vval.v_number =
7729 (varnumber_T)(regmatch.endp[0] - expr);
7730 if (l != NULL)
7731 li2->li_tv.vval.v_number = (varnumber_T)idx;
7732 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007733 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007734 {
7735 int i;
7736
7737 /* return list with matched string and submatches */
7738 for (i = 0; i < NSUBEXP; ++i)
7739 {
7740 if (regmatch.endp[i] == NULL)
7741 {
7742 if (list_append_string(rettv->vval.v_list,
7743 (char_u *)"", 0) == FAIL)
7744 break;
7745 }
7746 else if (list_append_string(rettv->vval.v_list,
7747 regmatch.startp[i],
7748 (int)(regmatch.endp[i] - regmatch.startp[i]))
7749 == FAIL)
7750 break;
7751 }
7752 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007753 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754 {
7755 /* return matched string */
7756 if (l != NULL)
7757 copy_tv(&li->li_tv, rettv);
7758 else
7759 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7760 (int)(regmatch.endp[0] - regmatch.startp[0]));
7761 }
7762 else if (l != NULL)
7763 rettv->vval.v_number = idx;
7764 else
7765 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007766 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767 rettv->vval.v_number =
7768 (varnumber_T)(regmatch.startp[0] - str);
7769 else
7770 rettv->vval.v_number =
7771 (varnumber_T)(regmatch.endp[0] - str);
7772 rettv->vval.v_number += (varnumber_T)(str - expr);
7773 }
7774 }
7775 vim_regfree(regmatch.regprog);
7776 }
7777
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007778theend:
7779 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780 /* matchstrpos() without a list: drop the second item. */
7781 listitem_remove(rettv->vval.v_list,
7782 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007783 vim_free(tofree);
7784 p_cpo = save_cpo;
7785}
7786
7787/*
7788 * "match()" function
7789 */
7790 static void
7791f_match(typval_T *argvars, typval_T *rettv)
7792{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007793 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007794}
7795
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796/*
7797 * "matchend()" function
7798 */
7799 static void
7800f_matchend(typval_T *argvars, typval_T *rettv)
7801{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007802 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007803}
7804
7805/*
7806 * "matchlist()" function
7807 */
7808 static void
7809f_matchlist(typval_T *argvars, typval_T *rettv)
7810{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007811 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007812}
7813
7814/*
7815 * "matchstr()" function
7816 */
7817 static void
7818f_matchstr(typval_T *argvars, typval_T *rettv)
7819{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007820 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007821}
7822
7823/*
7824 * "matchstrpos()" function
7825 */
7826 static void
7827f_matchstrpos(typval_T *argvars, typval_T *rettv)
7828{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007829 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007830}
7831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 static void
7833max_min(typval_T *argvars, typval_T *rettv, int domax)
7834{
7835 varnumber_T n = 0;
7836 varnumber_T i;
7837 int error = FALSE;
7838
7839 if (argvars[0].v_type == VAR_LIST)
7840 {
7841 list_T *l;
7842 listitem_T *li;
7843
7844 l = argvars[0].vval.v_list;
7845 if (l != NULL)
7846 {
7847 li = l->lv_first;
7848 if (li != NULL)
7849 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007850 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007851 for (;;)
7852 {
7853 li = li->li_next;
7854 if (li == NULL)
7855 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007856 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 if (domax ? i > n : i < n)
7858 n = i;
7859 }
7860 }
7861 }
7862 }
7863 else if (argvars[0].v_type == VAR_DICT)
7864 {
7865 dict_T *d;
7866 int first = TRUE;
7867 hashitem_T *hi;
7868 int todo;
7869
7870 d = argvars[0].vval.v_dict;
7871 if (d != NULL)
7872 {
7873 todo = (int)d->dv_hashtab.ht_used;
7874 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7875 {
7876 if (!HASHITEM_EMPTY(hi))
7877 {
7878 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007879 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 if (first)
7881 {
7882 n = i;
7883 first = FALSE;
7884 }
7885 else if (domax ? i > n : i < n)
7886 n = i;
7887 }
7888 }
7889 }
7890 }
7891 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007892 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 rettv->vval.v_number = error ? 0 : n;
7894}
7895
7896/*
7897 * "max()" function
7898 */
7899 static void
7900f_max(typval_T *argvars, typval_T *rettv)
7901{
7902 max_min(argvars, rettv, TRUE);
7903}
7904
7905/*
7906 * "min()" function
7907 */
7908 static void
7909f_min(typval_T *argvars, typval_T *rettv)
7910{
7911 max_min(argvars, rettv, FALSE);
7912}
7913
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914/*
7915 * Create the directory in which "dir" is located, and higher levels when
7916 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007917 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918 */
7919 static int
7920mkdir_recurse(char_u *dir, int prot)
7921{
7922 char_u *p;
7923 char_u *updir;
7924 int r = FAIL;
7925
7926 /* Get end of directory name in "dir".
7927 * We're done when it's "/" or "c:/". */
7928 p = gettail_sep(dir);
7929 if (p <= get_past_head(dir))
7930 return OK;
7931
7932 /* If the directory exists we're done. Otherwise: create it.*/
7933 updir = vim_strnsave(dir, (int)(p - dir));
7934 if (updir == NULL)
7935 return FAIL;
7936 if (mch_isdir(updir))
7937 r = OK;
7938 else if (mkdir_recurse(updir, prot) == OK)
7939 r = vim_mkdir_emsg(updir, prot);
7940 vim_free(updir);
7941 return r;
7942}
7943
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944/*
7945 * "mkdir()" function
7946 */
7947 static void
7948f_mkdir(typval_T *argvars, typval_T *rettv)
7949{
7950 char_u *dir;
7951 char_u buf[NUMBUFLEN];
7952 int prot = 0755;
7953
7954 rettv->vval.v_number = FAIL;
7955 if (check_restricted() || check_secure())
7956 return;
7957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007958 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007959 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007960 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007961
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007962 if (*gettail(dir) == NUL)
7963 /* remove trailing slashes */
7964 *gettail_sep(dir) = NUL;
7965
7966 if (argvars[1].v_type != VAR_UNKNOWN)
7967 {
7968 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007970 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007971 if (prot == -1)
7972 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007974 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007975 {
7976 if (mch_isdir(dir))
7977 {
7978 /* With the "p" flag it's OK if the dir already exists. */
7979 rettv->vval.v_number = OK;
7980 return;
7981 }
7982 mkdir_recurse(dir, prot);
7983 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007985 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987
7988/*
7989 * "mode()" function
7990 */
7991 static void
7992f_mode(typval_T *argvars, typval_T *rettv)
7993{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007994 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995
Bram Moolenaar612cc382018-07-29 15:34:26 +02007996 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997
7998 if (time_for_testing == 93784)
7999 {
8000 /* Testing the two-character code. */
8001 buf[0] = 'x';
8002 buf[1] = '!';
8003 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008004#ifdef FEAT_TERMINAL
8005 else if (term_use_loop())
8006 buf[0] = 't';
8007#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 else if (VIsual_active)
8009 {
8010 if (VIsual_select)
8011 buf[0] = VIsual_mode + 's' - 'v';
8012 else
8013 buf[0] = VIsual_mode;
8014 }
8015 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8016 || State == CONFIRM)
8017 {
8018 buf[0] = 'r';
8019 if (State == ASKMORE)
8020 buf[1] = 'm';
8021 else if (State == CONFIRM)
8022 buf[1] = '?';
8023 }
8024 else if (State == EXTERNCMD)
8025 buf[0] = '!';
8026 else if (State & INSERT)
8027 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008028 if (State & VREPLACE_FLAG)
8029 {
8030 buf[0] = 'R';
8031 buf[1] = 'v';
8032 }
8033 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008034 {
8035 if (State & REPLACE_FLAG)
8036 buf[0] = 'R';
8037 else
8038 buf[0] = 'i';
8039#ifdef FEAT_INS_EXPAND
8040 if (ins_compl_active())
8041 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008042 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008043 buf[1] = 'x';
8044#endif
8045 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008046 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008047 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008048 {
8049 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008050 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008051 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008052 else if (exmode_active == EXMODE_NORMAL)
8053 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054 }
8055 else
8056 {
8057 buf[0] = 'n';
8058 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008059 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008060 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008061 // to be able to detect force-linewise/blockwise/characterwise operations
8062 buf[2] = motion_force;
8063 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008064 else if (restart_edit == 'I' || restart_edit == 'R'
8065 || restart_edit == 'V')
8066 {
8067 buf[1] = 'i';
8068 buf[2] = restart_edit;
8069 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070 }
8071
8072 /* Clear out the minor mode when the argument is not a non-zero number or
8073 * non-empty string. */
8074 if (!non_zero_arg(&argvars[0]))
8075 buf[1] = NUL;
8076
8077 rettv->vval.v_string = vim_strsave(buf);
8078 rettv->v_type = VAR_STRING;
8079}
8080
8081#if defined(FEAT_MZSCHEME) || defined(PROTO)
8082/*
8083 * "mzeval()" function
8084 */
8085 static void
8086f_mzeval(typval_T *argvars, typval_T *rettv)
8087{
8088 char_u *str;
8089 char_u buf[NUMBUFLEN];
8090
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008091 if (check_restricted() || check_secure())
8092 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008093 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008094 do_mzeval(str, rettv);
8095}
8096
8097 void
8098mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8099{
8100 typval_T argvars[3];
8101
8102 argvars[0].v_type = VAR_STRING;
8103 argvars[0].vval.v_string = name;
8104 copy_tv(args, &argvars[1]);
8105 argvars[2].v_type = VAR_UNKNOWN;
8106 f_call(argvars, rettv);
8107 clear_tv(&argvars[1]);
8108}
8109#endif
8110
8111/*
8112 * "nextnonblank()" function
8113 */
8114 static void
8115f_nextnonblank(typval_T *argvars, typval_T *rettv)
8116{
8117 linenr_T lnum;
8118
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008119 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008120 {
8121 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8122 {
8123 lnum = 0;
8124 break;
8125 }
8126 if (*skipwhite(ml_get(lnum)) != NUL)
8127 break;
8128 }
8129 rettv->vval.v_number = lnum;
8130}
8131
8132/*
8133 * "nr2char()" function
8134 */
8135 static void
8136f_nr2char(typval_T *argvars, typval_T *rettv)
8137{
8138 char_u buf[NUMBUFLEN];
8139
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140 if (has_mbyte)
8141 {
8142 int utf8 = 0;
8143
8144 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008145 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008147 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008149 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150 }
8151 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008152 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008153 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008154 buf[1] = NUL;
8155 }
8156 rettv->v_type = VAR_STRING;
8157 rettv->vval.v_string = vim_strsave(buf);
8158}
8159
8160/*
8161 * "or(expr, expr)" function
8162 */
8163 static void
8164f_or(typval_T *argvars, typval_T *rettv)
8165{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008166 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8167 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008168}
8169
8170/*
8171 * "pathshorten()" function
8172 */
8173 static void
8174f_pathshorten(typval_T *argvars, typval_T *rettv)
8175{
8176 char_u *p;
8177
8178 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008179 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008180 if (p == NULL)
8181 rettv->vval.v_string = NULL;
8182 else
8183 {
8184 p = vim_strsave(p);
8185 rettv->vval.v_string = p;
8186 if (p != NULL)
8187 shorten_dir(p);
8188 }
8189}
8190
8191#ifdef FEAT_PERL
8192/*
8193 * "perleval()" function
8194 */
8195 static void
8196f_perleval(typval_T *argvars, typval_T *rettv)
8197{
8198 char_u *str;
8199 char_u buf[NUMBUFLEN];
8200
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008201 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202 do_perleval(str, rettv);
8203}
8204#endif
8205
8206#ifdef FEAT_FLOAT
8207/*
8208 * "pow()" function
8209 */
8210 static void
8211f_pow(typval_T *argvars, typval_T *rettv)
8212{
8213 float_T fx = 0.0, fy = 0.0;
8214
8215 rettv->v_type = VAR_FLOAT;
8216 if (get_float_arg(argvars, &fx) == OK
8217 && get_float_arg(&argvars[1], &fy) == OK)
8218 rettv->vval.v_float = pow(fx, fy);
8219 else
8220 rettv->vval.v_float = 0.0;
8221}
8222#endif
8223
8224/*
8225 * "prevnonblank()" function
8226 */
8227 static void
8228f_prevnonblank(typval_T *argvars, typval_T *rettv)
8229{
8230 linenr_T lnum;
8231
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008232 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8234 lnum = 0;
8235 else
8236 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8237 --lnum;
8238 rettv->vval.v_number = lnum;
8239}
8240
8241/* This dummy va_list is here because:
8242 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8243 * - locally in the function results in a "used before set" warning
8244 * - using va_start() to initialize it gives "function with fixed args" error */
8245static va_list ap;
8246
8247/*
8248 * "printf()" function
8249 */
8250 static void
8251f_printf(typval_T *argvars, typval_T *rettv)
8252{
8253 char_u buf[NUMBUFLEN];
8254 int len;
8255 char_u *s;
8256 int saved_did_emsg = did_emsg;
8257 char *fmt;
8258
8259 rettv->v_type = VAR_STRING;
8260 rettv->vval.v_string = NULL;
8261
8262 /* Get the required length, allocate the buffer and do it for real. */
8263 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008264 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008265 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008266 if (!did_emsg)
8267 {
8268 s = alloc(len + 1);
8269 if (s != NULL)
8270 {
8271 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008272 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8273 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008274 }
8275 }
8276 did_emsg |= saved_did_emsg;
8277}
8278
8279/*
8280 * "pumvisible()" function
8281 */
8282 static void
8283f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8284{
8285#ifdef FEAT_INS_EXPAND
8286 if (pum_visible())
8287 rettv->vval.v_number = 1;
8288#endif
8289}
8290
8291#ifdef FEAT_PYTHON3
8292/*
8293 * "py3eval()" function
8294 */
8295 static void
8296f_py3eval(typval_T *argvars, typval_T *rettv)
8297{
8298 char_u *str;
8299 char_u buf[NUMBUFLEN];
8300
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008301 if (check_restricted() || check_secure())
8302 return;
8303
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008304 if (p_pyx == 0)
8305 p_pyx = 3;
8306
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008307 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 do_py3eval(str, rettv);
8309}
8310#endif
8311
8312#ifdef FEAT_PYTHON
8313/*
8314 * "pyeval()" function
8315 */
8316 static void
8317f_pyeval(typval_T *argvars, typval_T *rettv)
8318{
8319 char_u *str;
8320 char_u buf[NUMBUFLEN];
8321
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008322 if (check_restricted() || check_secure())
8323 return;
8324
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008325 if (p_pyx == 0)
8326 p_pyx = 2;
8327
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008328 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329 do_pyeval(str, rettv);
8330}
8331#endif
8332
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008333#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8334/*
8335 * "pyxeval()" function
8336 */
8337 static void
8338f_pyxeval(typval_T *argvars, typval_T *rettv)
8339{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008340 if (check_restricted() || check_secure())
8341 return;
8342
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008343# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8344 init_pyxversion();
8345 if (p_pyx == 2)
8346 f_pyeval(argvars, rettv);
8347 else
8348 f_py3eval(argvars, rettv);
8349# elif defined(FEAT_PYTHON)
8350 f_pyeval(argvars, rettv);
8351# elif defined(FEAT_PYTHON3)
8352 f_py3eval(argvars, rettv);
8353# endif
8354}
8355#endif
8356
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008357/*
8358 * "range()" function
8359 */
8360 static void
8361f_range(typval_T *argvars, typval_T *rettv)
8362{
8363 varnumber_T start;
8364 varnumber_T end;
8365 varnumber_T stride = 1;
8366 varnumber_T i;
8367 int error = FALSE;
8368
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008369 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008370 if (argvars[1].v_type == VAR_UNKNOWN)
8371 {
8372 end = start - 1;
8373 start = 0;
8374 }
8375 else
8376 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008377 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008378 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008379 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008380 }
8381
8382 if (error)
8383 return; /* type error; errmsg already given */
8384 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008385 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008387 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 else
8389 {
8390 if (rettv_list_alloc(rettv) == OK)
8391 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8392 if (list_append_number(rettv->vval.v_list,
8393 (varnumber_T)i) == FAIL)
8394 break;
8395 }
8396}
8397
8398/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008399 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008400 */
8401 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008402readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008403{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008404 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008405 typval_T save_val;
8406 typval_T rettv;
8407 typval_T argv[2];
8408 int retval = 0;
8409 int error = FALSE;
8410
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008411 if (expr->v_type == VAR_UNKNOWN)
8412 return 1;
8413
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008414 prepare_vimvar(VV_VAL, &save_val);
8415 set_vim_var_string(VV_VAL, name, -1);
8416 argv[0].v_type = VAR_STRING;
8417 argv[0].vval.v_string = name;
8418
8419 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8420 goto theend;
8421
8422 retval = tv_get_number_chk(&rettv, &error);
8423 if (error)
8424 retval = -1;
8425 clear_tv(&rettv);
8426
8427theend:
8428 set_vim_var_string(VV_VAL, NULL, 0);
8429 restore_vimvar(VV_VAL, &save_val);
8430 return retval;
8431}
8432
8433/*
8434 * "readdir()" function
8435 */
8436 static void
8437f_readdir(typval_T *argvars, typval_T *rettv)
8438{
8439 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008440 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008441 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008442 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008443 garray_T ga;
8444 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008445
8446 if (rettv_list_alloc(rettv) == FAIL)
8447 return;
8448 path = tv_get_string(&argvars[0]);
8449 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008450
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008451 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8452 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008453 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008454 for (i = 0; i < ga.ga_len; i++)
8455 {
8456 p = ((char_u **)ga.ga_data)[i];
8457 list_append_string(rettv->vval.v_list, p, -1);
8458 }
8459 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008460 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008461}
8462
8463/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008464 * "readfile()" function
8465 */
8466 static void
8467f_readfile(typval_T *argvars, typval_T *rettv)
8468{
8469 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008470 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 int failed = FALSE;
8472 char_u *fname;
8473 FILE *fd;
8474 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8475 int io_size = sizeof(buf);
8476 int readlen; /* size of last fread() */
8477 char_u *prev = NULL; /* previously read bytes, if any */
8478 long prevlen = 0; /* length of data in prev */
8479 long prevsize = 0; /* size of prev buffer */
8480 long maxline = MAXLNUM;
8481 long cnt = 0;
8482 char_u *p; /* position in buf */
8483 char_u *start; /* start of current line */
8484
8485 if (argvars[1].v_type != VAR_UNKNOWN)
8486 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008487 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008488 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008489 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8490 blob = TRUE;
8491
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008492 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008493 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008494 }
8495
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008496 if (blob)
8497 {
8498 if (rettv_blob_alloc(rettv) == FAIL)
8499 return;
8500 }
8501 else
8502 {
8503 if (rettv_list_alloc(rettv) == FAIL)
8504 return;
8505 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008506
8507 /* Always open the file in binary mode, library functions have a mind of
8508 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008509 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008510 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8511 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008512 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008513 return;
8514 }
8515
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008516 if (blob)
8517 {
8518 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8519 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008520 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008521 blob_free(rettv->vval.v_blob);
8522 }
8523 fclose(fd);
8524 return;
8525 }
8526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008527 while (cnt < maxline || maxline < 0)
8528 {
8529 readlen = (int)fread(buf, 1, io_size, fd);
8530
8531 /* This for loop processes what was read, but is also entered at end
8532 * of file so that either:
8533 * - an incomplete line gets written
8534 * - a "binary" file gets an empty line at the end if it ends in a
8535 * newline. */
8536 for (p = buf, start = buf;
8537 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8538 ++p)
8539 {
8540 if (*p == '\n' || readlen <= 0)
8541 {
8542 listitem_T *li;
8543 char_u *s = NULL;
8544 long_u len = p - start;
8545
8546 /* Finished a line. Remove CRs before NL. */
8547 if (readlen > 0 && !binary)
8548 {
8549 while (len > 0 && start[len - 1] == '\r')
8550 --len;
8551 /* removal may cross back to the "prev" string */
8552 if (len == 0)
8553 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8554 --prevlen;
8555 }
8556 if (prevlen == 0)
8557 s = vim_strnsave(start, (int)len);
8558 else
8559 {
8560 /* Change "prev" buffer to be the right size. This way
8561 * the bytes are only copied once, and very long lines are
8562 * allocated only once. */
8563 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8564 {
8565 mch_memmove(s + prevlen, start, len);
8566 s[prevlen + len] = NUL;
8567 prev = NULL; /* the list will own the string */
8568 prevlen = prevsize = 0;
8569 }
8570 }
8571 if (s == NULL)
8572 {
8573 do_outofmem_msg((long_u) prevlen + len + 1);
8574 failed = TRUE;
8575 break;
8576 }
8577
8578 if ((li = listitem_alloc()) == NULL)
8579 {
8580 vim_free(s);
8581 failed = TRUE;
8582 break;
8583 }
8584 li->li_tv.v_type = VAR_STRING;
8585 li->li_tv.v_lock = 0;
8586 li->li_tv.vval.v_string = s;
8587 list_append(rettv->vval.v_list, li);
8588
8589 start = p + 1; /* step over newline */
8590 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8591 break;
8592 }
8593 else if (*p == NUL)
8594 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8596 * when finding the BF and check the previous two bytes. */
8597 else if (*p == 0xbf && enc_utf8 && !binary)
8598 {
8599 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8600 * + 1, these may be in the "prev" string. */
8601 char_u back1 = p >= buf + 1 ? p[-1]
8602 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8603 char_u back2 = p >= buf + 2 ? p[-2]
8604 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8605 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8606
8607 if (back2 == 0xef && back1 == 0xbb)
8608 {
8609 char_u *dest = p - 2;
8610
8611 /* Usually a BOM is at the beginning of a file, and so at
8612 * the beginning of a line; then we can just step over it.
8613 */
8614 if (start == dest)
8615 start = p + 1;
8616 else
8617 {
8618 /* have to shuffle buf to close gap */
8619 int adjust_prevlen = 0;
8620
8621 if (dest < buf)
8622 {
8623 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8624 dest = buf;
8625 }
8626 if (readlen > p - buf + 1)
8627 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8628 readlen -= 3 - adjust_prevlen;
8629 prevlen -= adjust_prevlen;
8630 p = dest - 1;
8631 }
8632 }
8633 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634 } /* for */
8635
8636 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8637 break;
8638 if (start < p)
8639 {
8640 /* There's part of a line in buf, store it in "prev". */
8641 if (p - start + prevlen >= prevsize)
8642 {
8643 /* need bigger "prev" buffer */
8644 char_u *newprev;
8645
8646 /* A common use case is ordinary text files and "prev" gets a
8647 * fragment of a line, so the first allocation is made
8648 * small, to avoid repeatedly 'allocing' large and
8649 * 'reallocing' small. */
8650 if (prevsize == 0)
8651 prevsize = (long)(p - start);
8652 else
8653 {
8654 long grow50pc = (prevsize * 3) / 2;
8655 long growmin = (long)((p - start) * 2 + prevlen);
8656 prevsize = grow50pc > growmin ? grow50pc : growmin;
8657 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008658 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008659 if (newprev == NULL)
8660 {
8661 do_outofmem_msg((long_u)prevsize);
8662 failed = TRUE;
8663 break;
8664 }
8665 prev = newprev;
8666 }
8667 /* Add the line part to end of "prev". */
8668 mch_memmove(prev + prevlen, start, p - start);
8669 prevlen += (long)(p - start);
8670 }
8671 } /* while */
8672
8673 /*
8674 * For a negative line count use only the lines at the end of the file,
8675 * free the rest.
8676 */
8677 if (!failed && maxline < 0)
8678 while (cnt > -maxline)
8679 {
8680 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8681 --cnt;
8682 }
8683
8684 if (failed)
8685 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008686 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008687 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008688 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689 }
8690
8691 vim_free(prev);
8692 fclose(fd);
8693}
8694
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008695 static void
8696return_register(int regname, typval_T *rettv)
8697{
8698 char_u buf[2] = {0, 0};
8699
8700 buf[0] = (char_u)regname;
8701 rettv->v_type = VAR_STRING;
8702 rettv->vval.v_string = vim_strsave(buf);
8703}
8704
8705/*
8706 * "reg_executing()" function
8707 */
8708 static void
8709f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8710{
8711 return_register(reg_executing, rettv);
8712}
8713
8714/*
8715 * "reg_recording()" function
8716 */
8717 static void
8718f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8719{
8720 return_register(reg_recording, rettv);
8721}
8722
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008723#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724/*
8725 * Convert a List to proftime_T.
8726 * Return FAIL when there is something wrong.
8727 */
8728 static int
8729list2proftime(typval_T *arg, proftime_T *tm)
8730{
8731 long n1, n2;
8732 int error = FALSE;
8733
8734 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8735 || arg->vval.v_list->lv_len != 2)
8736 return FAIL;
8737 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8738 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008739# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008740 tm->HighPart = n1;
8741 tm->LowPart = n2;
8742# else
8743 tm->tv_sec = n1;
8744 tm->tv_usec = n2;
8745# endif
8746 return error ? FAIL : OK;
8747}
8748#endif /* FEAT_RELTIME */
8749
8750/*
8751 * "reltime()" function
8752 */
8753 static void
8754f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8755{
8756#ifdef FEAT_RELTIME
8757 proftime_T res;
8758 proftime_T start;
8759
8760 if (argvars[0].v_type == VAR_UNKNOWN)
8761 {
8762 /* No arguments: get current time. */
8763 profile_start(&res);
8764 }
8765 else if (argvars[1].v_type == VAR_UNKNOWN)
8766 {
8767 if (list2proftime(&argvars[0], &res) == FAIL)
8768 return;
8769 profile_end(&res);
8770 }
8771 else
8772 {
8773 /* Two arguments: compute the difference. */
8774 if (list2proftime(&argvars[0], &start) == FAIL
8775 || list2proftime(&argvars[1], &res) == FAIL)
8776 return;
8777 profile_sub(&res, &start);
8778 }
8779
8780 if (rettv_list_alloc(rettv) == OK)
8781 {
8782 long n1, n2;
8783
Bram Moolenaar4f974752019-02-17 17:44:42 +01008784# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 n1 = res.HighPart;
8786 n2 = res.LowPart;
8787# else
8788 n1 = res.tv_sec;
8789 n2 = res.tv_usec;
8790# endif
8791 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8792 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8793 }
8794#endif
8795}
8796
8797#ifdef FEAT_FLOAT
8798/*
8799 * "reltimefloat()" function
8800 */
8801 static void
8802f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8803{
8804# ifdef FEAT_RELTIME
8805 proftime_T tm;
8806# endif
8807
8808 rettv->v_type = VAR_FLOAT;
8809 rettv->vval.v_float = 0;
8810# ifdef FEAT_RELTIME
8811 if (list2proftime(&argvars[0], &tm) == OK)
8812 rettv->vval.v_float = profile_float(&tm);
8813# endif
8814}
8815#endif
8816
8817/*
8818 * "reltimestr()" function
8819 */
8820 static void
8821f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8822{
8823#ifdef FEAT_RELTIME
8824 proftime_T tm;
8825#endif
8826
8827 rettv->v_type = VAR_STRING;
8828 rettv->vval.v_string = NULL;
8829#ifdef FEAT_RELTIME
8830 if (list2proftime(&argvars[0], &tm) == OK)
8831 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8832#endif
8833}
8834
8835#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008836 static void
8837make_connection(void)
8838{
8839 if (X_DISPLAY == NULL
8840# ifdef FEAT_GUI
8841 && !gui.in_use
8842# endif
8843 )
8844 {
8845 x_force_connect = TRUE;
8846 setup_term_clip();
8847 x_force_connect = FALSE;
8848 }
8849}
8850
8851 static int
8852check_connection(void)
8853{
8854 make_connection();
8855 if (X_DISPLAY == NULL)
8856 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008857 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008858 return FAIL;
8859 }
8860 return OK;
8861}
8862#endif
8863
8864#ifdef FEAT_CLIENTSERVER
8865 static void
8866remote_common(typval_T *argvars, typval_T *rettv, int expr)
8867{
8868 char_u *server_name;
8869 char_u *keys;
8870 char_u *r = NULL;
8871 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008872 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008873# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874 HWND w;
8875# else
8876 Window w;
8877# endif
8878
8879 if (check_restricted() || check_secure())
8880 return;
8881
8882# ifdef FEAT_X11
8883 if (check_connection() == FAIL)
8884 return;
8885# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008886 if (argvars[2].v_type != VAR_UNKNOWN
8887 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008888 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008889
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008890 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008891 if (server_name == NULL)
8892 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008893 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008894# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008895 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008896# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008897 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8898 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008899# endif
8900 {
8901 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008902 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008903 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008904 vim_free(r);
8905 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008906 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008907 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008908 return;
8909 }
8910
8911 rettv->vval.v_string = r;
8912
8913 if (argvars[2].v_type != VAR_UNKNOWN)
8914 {
8915 dictitem_T v;
8916 char_u str[30];
8917 char_u *idvar;
8918
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008919 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008920 if (idvar != NULL && *idvar != NUL)
8921 {
8922 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8923 v.di_tv.v_type = VAR_STRING;
8924 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008925 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008926 vim_free(v.di_tv.vval.v_string);
8927 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008928 }
8929}
8930#endif
8931
8932/*
8933 * "remote_expr()" function
8934 */
8935 static void
8936f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8937{
8938 rettv->v_type = VAR_STRING;
8939 rettv->vval.v_string = NULL;
8940#ifdef FEAT_CLIENTSERVER
8941 remote_common(argvars, rettv, TRUE);
8942#endif
8943}
8944
8945/*
8946 * "remote_foreground()" function
8947 */
8948 static void
8949f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8950{
8951#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008952# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008953 /* On Win32 it's done in this application. */
8954 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008955 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008956
8957 if (server_name != NULL)
8958 serverForeground(server_name);
8959 }
8960# else
8961 /* Send a foreground() expression to the server. */
8962 argvars[1].v_type = VAR_STRING;
8963 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8964 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008965 rettv->v_type = VAR_STRING;
8966 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008967 remote_common(argvars, rettv, TRUE);
8968 vim_free(argvars[1].vval.v_string);
8969# endif
8970#endif
8971}
8972
8973 static void
8974f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8975{
8976#ifdef FEAT_CLIENTSERVER
8977 dictitem_T v;
8978 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008979# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008980 long_u n = 0;
8981# endif
8982 char_u *serverid;
8983
8984 if (check_restricted() || check_secure())
8985 {
8986 rettv->vval.v_number = -1;
8987 return;
8988 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008989 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008990 if (serverid == NULL)
8991 {
8992 rettv->vval.v_number = -1;
8993 return; /* type error; errmsg already given */
8994 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008995# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008996 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8997 if (n == 0)
8998 rettv->vval.v_number = -1;
8999 else
9000 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009001 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009002 rettv->vval.v_number = (s != NULL);
9003 }
9004# else
9005 if (check_connection() == FAIL)
9006 return;
9007
9008 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9009 serverStrToWin(serverid), &s);
9010# endif
9011
9012 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9013 {
9014 char_u *retvar;
9015
9016 v.di_tv.v_type = VAR_STRING;
9017 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009018 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009019 if (retvar != NULL)
9020 set_var(retvar, &v.di_tv, FALSE);
9021 vim_free(v.di_tv.vval.v_string);
9022 }
9023#else
9024 rettv->vval.v_number = -1;
9025#endif
9026}
9027
9028 static void
9029f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9030{
9031 char_u *r = NULL;
9032
9033#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009034 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009035
9036 if (serverid != NULL && !check_restricted() && !check_secure())
9037 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009038 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009039# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009040 /* The server's HWND is encoded in the 'id' parameter */
9041 long_u n = 0;
9042# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009043
9044 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009045 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009046
Bram Moolenaar4f974752019-02-17 17:44:42 +01009047# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009048 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9049 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009050 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009051 if (r == NULL)
9052# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009053 if (check_connection() == FAIL
9054 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9055 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009056# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009057 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009058 }
9059#endif
9060 rettv->v_type = VAR_STRING;
9061 rettv->vval.v_string = r;
9062}
9063
9064/*
9065 * "remote_send()" function
9066 */
9067 static void
9068f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9069{
9070 rettv->v_type = VAR_STRING;
9071 rettv->vval.v_string = NULL;
9072#ifdef FEAT_CLIENTSERVER
9073 remote_common(argvars, rettv, FALSE);
9074#endif
9075}
9076
9077/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009078 * "remote_startserver()" function
9079 */
9080 static void
9081f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9082{
9083#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009084 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009085
9086 if (server == NULL)
9087 return; /* type error; errmsg already given */
9088 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009089 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009090 else
9091 {
9092# ifdef FEAT_X11
9093 if (check_connection() == OK)
9094 serverRegisterName(X_DISPLAY, server);
9095# else
9096 serverSetName(server);
9097# endif
9098 }
9099#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009100 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009101#endif
9102}
9103
9104/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009105 * "remove()" function
9106 */
9107 static void
9108f_remove(typval_T *argvars, typval_T *rettv)
9109{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009110 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9111
9112 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009113 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009114 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009115 blob_remove(argvars, rettv);
9116 else if (argvars[0].v_type == VAR_LIST)
9117 list_remove(argvars, rettv, arg_errmsg);
9118 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009119 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009120}
9121
9122/*
9123 * "rename({from}, {to})" function
9124 */
9125 static void
9126f_rename(typval_T *argvars, typval_T *rettv)
9127{
9128 char_u buf[NUMBUFLEN];
9129
9130 if (check_restricted() || check_secure())
9131 rettv->vval.v_number = -1;
9132 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009133 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9134 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009135}
9136
9137/*
9138 * "repeat()" function
9139 */
9140 static void
9141f_repeat(typval_T *argvars, typval_T *rettv)
9142{
9143 char_u *p;
9144 int n;
9145 int slen;
9146 int len;
9147 char_u *r;
9148 int i;
9149
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009150 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009151 if (argvars[0].v_type == VAR_LIST)
9152 {
9153 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9154 while (n-- > 0)
9155 if (list_extend(rettv->vval.v_list,
9156 argvars[0].vval.v_list, NULL) == FAIL)
9157 break;
9158 }
9159 else
9160 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009161 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009162 rettv->v_type = VAR_STRING;
9163 rettv->vval.v_string = NULL;
9164
9165 slen = (int)STRLEN(p);
9166 len = slen * n;
9167 if (len <= 0)
9168 return;
9169
9170 r = alloc(len + 1);
9171 if (r != NULL)
9172 {
9173 for (i = 0; i < n; i++)
9174 mch_memmove(r + i * slen, p, (size_t)slen);
9175 r[len] = NUL;
9176 }
9177
9178 rettv->vval.v_string = r;
9179 }
9180}
9181
9182/*
9183 * "resolve()" function
9184 */
9185 static void
9186f_resolve(typval_T *argvars, typval_T *rettv)
9187{
9188 char_u *p;
9189#ifdef HAVE_READLINK
9190 char_u *buf = NULL;
9191#endif
9192
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009193 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009194#ifdef FEAT_SHORTCUT
9195 {
9196 char_u *v = NULL;
9197
Bram Moolenaardce1e892019-02-10 23:18:53 +01009198 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009199 if (v != NULL)
9200 rettv->vval.v_string = v;
9201 else
9202 rettv->vval.v_string = vim_strsave(p);
9203 }
9204#else
9205# ifdef HAVE_READLINK
9206 {
9207 char_u *cpy;
9208 int len;
9209 char_u *remain = NULL;
9210 char_u *q;
9211 int is_relative_to_current = FALSE;
9212 int has_trailing_pathsep = FALSE;
9213 int limit = 100;
9214
9215 p = vim_strsave(p);
9216
9217 if (p[0] == '.' && (vim_ispathsep(p[1])
9218 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9219 is_relative_to_current = TRUE;
9220
9221 len = STRLEN(p);
9222 if (len > 0 && after_pathsep(p, p + len))
9223 {
9224 has_trailing_pathsep = TRUE;
9225 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9226 }
9227
9228 q = getnextcomp(p);
9229 if (*q != NUL)
9230 {
9231 /* Separate the first path component in "p", and keep the
9232 * remainder (beginning with the path separator). */
9233 remain = vim_strsave(q - 1);
9234 q[-1] = NUL;
9235 }
9236
9237 buf = alloc(MAXPATHL + 1);
9238 if (buf == NULL)
9239 goto fail;
9240
9241 for (;;)
9242 {
9243 for (;;)
9244 {
9245 len = readlink((char *)p, (char *)buf, MAXPATHL);
9246 if (len <= 0)
9247 break;
9248 buf[len] = NUL;
9249
9250 if (limit-- == 0)
9251 {
9252 vim_free(p);
9253 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009254 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009255 rettv->vval.v_string = NULL;
9256 goto fail;
9257 }
9258
9259 /* Ensure that the result will have a trailing path separator
9260 * if the argument has one. */
9261 if (remain == NULL && has_trailing_pathsep)
9262 add_pathsep(buf);
9263
9264 /* Separate the first path component in the link value and
9265 * concatenate the remainders. */
9266 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9267 if (*q != NUL)
9268 {
9269 if (remain == NULL)
9270 remain = vim_strsave(q - 1);
9271 else
9272 {
9273 cpy = concat_str(q - 1, remain);
9274 if (cpy != NULL)
9275 {
9276 vim_free(remain);
9277 remain = cpy;
9278 }
9279 }
9280 q[-1] = NUL;
9281 }
9282
9283 q = gettail(p);
9284 if (q > p && *q == NUL)
9285 {
9286 /* Ignore trailing path separator. */
9287 q[-1] = NUL;
9288 q = gettail(p);
9289 }
9290 if (q > p && !mch_isFullName(buf))
9291 {
9292 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009293 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009294 if (cpy != NULL)
9295 {
9296 STRCPY(cpy, p);
9297 STRCPY(gettail(cpy), buf);
9298 vim_free(p);
9299 p = cpy;
9300 }
9301 }
9302 else
9303 {
9304 vim_free(p);
9305 p = vim_strsave(buf);
9306 }
9307 }
9308
9309 if (remain == NULL)
9310 break;
9311
9312 /* Append the first path component of "remain" to "p". */
9313 q = getnextcomp(remain + 1);
9314 len = q - remain - (*q != NUL);
9315 cpy = vim_strnsave(p, STRLEN(p) + len);
9316 if (cpy != NULL)
9317 {
9318 STRNCAT(cpy, remain, len);
9319 vim_free(p);
9320 p = cpy;
9321 }
9322 /* Shorten "remain". */
9323 if (*q != NUL)
9324 STRMOVE(remain, q - 1);
9325 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009326 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009327 }
9328
9329 /* If the result is a relative path name, make it explicitly relative to
9330 * the current directory if and only if the argument had this form. */
9331 if (!vim_ispathsep(*p))
9332 {
9333 if (is_relative_to_current
9334 && *p != NUL
9335 && !(p[0] == '.'
9336 && (p[1] == NUL
9337 || vim_ispathsep(p[1])
9338 || (p[1] == '.'
9339 && (p[2] == NUL
9340 || vim_ispathsep(p[2]))))))
9341 {
9342 /* Prepend "./". */
9343 cpy = concat_str((char_u *)"./", p);
9344 if (cpy != NULL)
9345 {
9346 vim_free(p);
9347 p = cpy;
9348 }
9349 }
9350 else if (!is_relative_to_current)
9351 {
9352 /* Strip leading "./". */
9353 q = p;
9354 while (q[0] == '.' && vim_ispathsep(q[1]))
9355 q += 2;
9356 if (q > p)
9357 STRMOVE(p, p + 2);
9358 }
9359 }
9360
9361 /* Ensure that the result will have no trailing path separator
9362 * if the argument had none. But keep "/" or "//". */
9363 if (!has_trailing_pathsep)
9364 {
9365 q = p + STRLEN(p);
9366 if (after_pathsep(p, q))
9367 *gettail_sep(p) = NUL;
9368 }
9369
9370 rettv->vval.v_string = p;
9371 }
9372# else
9373 rettv->vval.v_string = vim_strsave(p);
9374# endif
9375#endif
9376
9377 simplify_filename(rettv->vval.v_string);
9378
9379#ifdef HAVE_READLINK
9380fail:
9381 vim_free(buf);
9382#endif
9383 rettv->v_type = VAR_STRING;
9384}
9385
9386/*
9387 * "reverse({list})" function
9388 */
9389 static void
9390f_reverse(typval_T *argvars, typval_T *rettv)
9391{
9392 list_T *l;
9393 listitem_T *li, *ni;
9394
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009395 if (argvars[0].v_type == VAR_BLOB)
9396 {
9397 blob_T *b = argvars[0].vval.v_blob;
9398 int i, len = blob_len(b);
9399
9400 for (i = 0; i < len / 2; i++)
9401 {
9402 int tmp = blob_get(b, i);
9403
9404 blob_set(b, i, blob_get(b, len - i - 1));
9405 blob_set(b, len - i - 1, tmp);
9406 }
9407 rettv_blob_set(rettv, b);
9408 return;
9409 }
9410
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009411 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009412 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009413 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009414 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009415 (char_u *)N_("reverse() argument"), TRUE))
9416 {
9417 li = l->lv_last;
9418 l->lv_first = l->lv_last = NULL;
9419 l->lv_len = 0;
9420 while (li != NULL)
9421 {
9422 ni = li->li_prev;
9423 list_append(l, li);
9424 li = ni;
9425 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009426 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009427 l->lv_idx = l->lv_len - l->lv_idx - 1;
9428 }
9429}
9430
9431#define SP_NOMOVE 0x01 /* don't move cursor */
9432#define SP_REPEAT 0x02 /* repeat to find outer pair */
9433#define SP_RETCOUNT 0x04 /* return matchcount */
9434#define SP_SETPCMARK 0x08 /* set previous context mark */
9435#define SP_START 0x10 /* accept match at start position */
9436#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9437#define SP_END 0x40 /* leave cursor at end of match */
9438#define SP_COLUMN 0x80 /* start at cursor column */
9439
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009440/*
9441 * Get flags for a search function.
9442 * Possibly sets "p_ws".
9443 * Returns BACKWARD, FORWARD or zero (for an error).
9444 */
9445 static int
9446get_search_arg(typval_T *varp, int *flagsp)
9447{
9448 int dir = FORWARD;
9449 char_u *flags;
9450 char_u nbuf[NUMBUFLEN];
9451 int mask;
9452
9453 if (varp->v_type != VAR_UNKNOWN)
9454 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009455 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009456 if (flags == NULL)
9457 return 0; /* type error; errmsg already given */
9458 while (*flags != NUL)
9459 {
9460 switch (*flags)
9461 {
9462 case 'b': dir = BACKWARD; break;
9463 case 'w': p_ws = TRUE; break;
9464 case 'W': p_ws = FALSE; break;
9465 default: mask = 0;
9466 if (flagsp != NULL)
9467 switch (*flags)
9468 {
9469 case 'c': mask = SP_START; break;
9470 case 'e': mask = SP_END; break;
9471 case 'm': mask = SP_RETCOUNT; break;
9472 case 'n': mask = SP_NOMOVE; break;
9473 case 'p': mask = SP_SUBPAT; break;
9474 case 'r': mask = SP_REPEAT; break;
9475 case 's': mask = SP_SETPCMARK; break;
9476 case 'z': mask = SP_COLUMN; break;
9477 }
9478 if (mask == 0)
9479 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009480 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009481 dir = 0;
9482 }
9483 else
9484 *flagsp |= mask;
9485 }
9486 if (dir == 0)
9487 break;
9488 ++flags;
9489 }
9490 }
9491 return dir;
9492}
9493
9494/*
9495 * Shared by search() and searchpos() functions.
9496 */
9497 static int
9498search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9499{
9500 int flags;
9501 char_u *pat;
9502 pos_T pos;
9503 pos_T save_cursor;
9504 int save_p_ws = p_ws;
9505 int dir;
9506 int retval = 0; /* default: FAIL */
9507 long lnum_stop = 0;
9508 proftime_T tm;
9509#ifdef FEAT_RELTIME
9510 long time_limit = 0;
9511#endif
9512 int options = SEARCH_KEEP;
9513 int subpatnum;
9514
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009515 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009516 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9517 if (dir == 0)
9518 goto theend;
9519 flags = *flagsp;
9520 if (flags & SP_START)
9521 options |= SEARCH_START;
9522 if (flags & SP_END)
9523 options |= SEARCH_END;
9524 if (flags & SP_COLUMN)
9525 options |= SEARCH_COL;
9526
9527 /* Optional arguments: line number to stop searching and timeout. */
9528 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9529 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009530 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009531 if (lnum_stop < 0)
9532 goto theend;
9533#ifdef FEAT_RELTIME
9534 if (argvars[3].v_type != VAR_UNKNOWN)
9535 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009536 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009537 if (time_limit < 0)
9538 goto theend;
9539 }
9540#endif
9541 }
9542
9543#ifdef FEAT_RELTIME
9544 /* Set the time limit, if there is one. */
9545 profile_setlimit(time_limit, &tm);
9546#endif
9547
9548 /*
9549 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9550 * Check to make sure only those flags are set.
9551 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9552 * flags cannot be set. Check for that condition also.
9553 */
9554 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9555 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9556 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009557 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009558 goto theend;
9559 }
9560
9561 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009562 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009563 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009564 if (subpatnum != FAIL)
9565 {
9566 if (flags & SP_SUBPAT)
9567 retval = subpatnum;
9568 else
9569 retval = pos.lnum;
9570 if (flags & SP_SETPCMARK)
9571 setpcmark();
9572 curwin->w_cursor = pos;
9573 if (match_pos != NULL)
9574 {
9575 /* Store the match cursor position */
9576 match_pos->lnum = pos.lnum;
9577 match_pos->col = pos.col + 1;
9578 }
9579 /* "/$" will put the cursor after the end of the line, may need to
9580 * correct that here */
9581 check_cursor();
9582 }
9583
9584 /* If 'n' flag is used: restore cursor position. */
9585 if (flags & SP_NOMOVE)
9586 curwin->w_cursor = save_cursor;
9587 else
9588 curwin->w_set_curswant = TRUE;
9589theend:
9590 p_ws = save_p_ws;
9591
9592 return retval;
9593}
9594
9595#ifdef FEAT_FLOAT
9596
9597/*
9598 * round() is not in C90, use ceil() or floor() instead.
9599 */
9600 float_T
9601vim_round(float_T f)
9602{
9603 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9604}
9605
9606/*
9607 * "round({float})" function
9608 */
9609 static void
9610f_round(typval_T *argvars, typval_T *rettv)
9611{
9612 float_T f = 0.0;
9613
9614 rettv->v_type = VAR_FLOAT;
9615 if (get_float_arg(argvars, &f) == OK)
9616 rettv->vval.v_float = vim_round(f);
9617 else
9618 rettv->vval.v_float = 0.0;
9619}
9620#endif
9621
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009622#ifdef FEAT_RUBY
9623/*
9624 * "rubyeval()" function
9625 */
9626 static void
9627f_rubyeval(typval_T *argvars, typval_T *rettv)
9628{
9629 char_u *str;
9630 char_u buf[NUMBUFLEN];
9631
9632 str = tv_get_string_buf(&argvars[0], buf);
9633 do_rubyeval(str, rettv);
9634}
9635#endif
9636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009637/*
9638 * "screenattr()" function
9639 */
9640 static void
9641f_screenattr(typval_T *argvars, typval_T *rettv)
9642{
9643 int row;
9644 int col;
9645 int c;
9646
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009647 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9648 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009649 if (row < 0 || row >= screen_Rows
9650 || col < 0 || col >= screen_Columns)
9651 c = -1;
9652 else
9653 c = ScreenAttrs[LineOffset[row] + col];
9654 rettv->vval.v_number = c;
9655}
9656
9657/*
9658 * "screenchar()" function
9659 */
9660 static void
9661f_screenchar(typval_T *argvars, typval_T *rettv)
9662{
9663 int row;
9664 int col;
9665 int off;
9666 int c;
9667
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009668 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9669 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009670 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 c = -1;
9672 else
9673 {
9674 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009675 if (enc_utf8 && ScreenLinesUC[off] != 0)
9676 c = ScreenLinesUC[off];
9677 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009678 c = ScreenLines[off];
9679 }
9680 rettv->vval.v_number = c;
9681}
9682
9683/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009684 * "screenchars()" function
9685 */
9686 static void
9687f_screenchars(typval_T *argvars, typval_T *rettv)
9688{
9689 int row;
9690 int col;
9691 int off;
9692 int c;
9693 int i;
9694
9695 if (rettv_list_alloc(rettv) == FAIL)
9696 return;
9697 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9698 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9699 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9700 return;
9701
9702 off = LineOffset[row] + col;
9703 if (enc_utf8 && ScreenLinesUC[off] != 0)
9704 c = ScreenLinesUC[off];
9705 else
9706 c = ScreenLines[off];
9707 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9708
9709 if (enc_utf8)
9710
9711 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9712 list_append_number(rettv->vval.v_list,
9713 (varnumber_T)ScreenLinesC[i][off]);
9714}
9715
9716/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009717 * "screencol()" function
9718 *
9719 * First column is 1 to be consistent with virtcol().
9720 */
9721 static void
9722f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9723{
9724 rettv->vval.v_number = screen_screencol() + 1;
9725}
9726
9727/*
9728 * "screenrow()" function
9729 */
9730 static void
9731f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9732{
9733 rettv->vval.v_number = screen_screenrow() + 1;
9734}
9735
9736/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009737 * "screenstring()" function
9738 */
9739 static void
9740f_screenstring(typval_T *argvars, typval_T *rettv)
9741{
9742 int row;
9743 int col;
9744 int off;
9745 int c;
9746 int i;
9747 char_u buf[MB_MAXBYTES + 1];
9748 int buflen = 0;
9749
9750 rettv->vval.v_string = NULL;
9751 rettv->v_type = VAR_STRING;
9752
9753 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9754 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9755 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9756 return;
9757
9758 off = LineOffset[row] + col;
9759 if (enc_utf8 && ScreenLinesUC[off] != 0)
9760 c = ScreenLinesUC[off];
9761 else
9762 c = ScreenLines[off];
9763 buflen += mb_char2bytes(c, buf);
9764
9765 if (enc_utf8)
9766 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9767 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9768
9769 buf[buflen] = NUL;
9770 rettv->vval.v_string = vim_strsave(buf);
9771}
9772
9773/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009774 * "search()" function
9775 */
9776 static void
9777f_search(typval_T *argvars, typval_T *rettv)
9778{
9779 int flags = 0;
9780
9781 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9782}
9783
9784/*
9785 * "searchdecl()" function
9786 */
9787 static void
9788f_searchdecl(typval_T *argvars, typval_T *rettv)
9789{
9790 int locally = 1;
9791 int thisblock = 0;
9792 int error = FALSE;
9793 char_u *name;
9794
9795 rettv->vval.v_number = 1; /* default: FAIL */
9796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009797 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798 if (argvars[1].v_type != VAR_UNKNOWN)
9799 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009800 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009801 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009802 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009803 }
9804 if (!error && name != NULL)
9805 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9806 locally, thisblock, SEARCH_KEEP) == FAIL;
9807}
9808
9809/*
9810 * Used by searchpair() and searchpairpos()
9811 */
9812 static int
9813searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9814{
9815 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009816 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009817 int save_p_ws = p_ws;
9818 int dir;
9819 int flags = 0;
9820 char_u nbuf1[NUMBUFLEN];
9821 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009822 int retval = 0; /* default: FAIL */
9823 long lnum_stop = 0;
9824 long time_limit = 0;
9825
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009826 /* Get the three pattern arguments: start, middle, end. Will result in an
9827 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009828 spat = tv_get_string_chk(&argvars[0]);
9829 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9830 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009831 if (spat == NULL || mpat == NULL || epat == NULL)
9832 goto theend; /* type error */
9833
9834 /* Handle the optional fourth argument: flags */
9835 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9836 if (dir == 0)
9837 goto theend;
9838
9839 /* Don't accept SP_END or SP_SUBPAT.
9840 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9841 */
9842 if ((flags & (SP_END | SP_SUBPAT)) != 0
9843 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9844 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009845 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009846 goto theend;
9847 }
9848
9849 /* Using 'r' implies 'W', otherwise it doesn't work. */
9850 if (flags & SP_REPEAT)
9851 p_ws = FALSE;
9852
9853 /* Optional fifth argument: skip expression */
9854 if (argvars[3].v_type == VAR_UNKNOWN
9855 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009856 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009857 else
9858 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009859 skip = &argvars[4];
9860 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9861 && skip->v_type != VAR_STRING)
9862 {
9863 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009864 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009865 goto theend;
9866 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009867 if (argvars[5].v_type != VAR_UNKNOWN)
9868 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009869 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009870 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009871 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009872 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009873 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009874 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009875#ifdef FEAT_RELTIME
9876 if (argvars[6].v_type != VAR_UNKNOWN)
9877 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009878 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009879 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009880 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009881 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009882 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009883 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009884 }
9885#endif
9886 }
9887 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009888
9889 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9890 match_pos, lnum_stop, time_limit);
9891
9892theend:
9893 p_ws = save_p_ws;
9894
9895 return retval;
9896}
9897
9898/*
9899 * "searchpair()" function
9900 */
9901 static void
9902f_searchpair(typval_T *argvars, typval_T *rettv)
9903{
9904 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9905}
9906
9907/*
9908 * "searchpairpos()" function
9909 */
9910 static void
9911f_searchpairpos(typval_T *argvars, typval_T *rettv)
9912{
9913 pos_T match_pos;
9914 int lnum = 0;
9915 int col = 0;
9916
9917 if (rettv_list_alloc(rettv) == FAIL)
9918 return;
9919
9920 if (searchpair_cmn(argvars, &match_pos) > 0)
9921 {
9922 lnum = match_pos.lnum;
9923 col = match_pos.col;
9924 }
9925
9926 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9927 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9928}
9929
9930/*
9931 * Search for a start/middle/end thing.
9932 * Used by searchpair(), see its documentation for the details.
9933 * Returns 0 or -1 for no match,
9934 */
9935 long
9936do_searchpair(
9937 char_u *spat, /* start pattern */
9938 char_u *mpat, /* middle pattern */
9939 char_u *epat, /* end pattern */
9940 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009941 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009942 int flags, /* SP_SETPCMARK and other SP_ values */
9943 pos_T *match_pos,
9944 linenr_T lnum_stop, /* stop at this line if not zero */
9945 long time_limit UNUSED) /* stop after this many msec */
9946{
9947 char_u *save_cpo;
9948 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9949 long retval = 0;
9950 pos_T pos;
9951 pos_T firstpos;
9952 pos_T foundpos;
9953 pos_T save_cursor;
9954 pos_T save_pos;
9955 int n;
9956 int r;
9957 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009958 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009959 int err;
9960 int options = SEARCH_KEEP;
9961 proftime_T tm;
9962
9963 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9964 save_cpo = p_cpo;
9965 p_cpo = empty_option;
9966
9967#ifdef FEAT_RELTIME
9968 /* Set the time limit, if there is one. */
9969 profile_setlimit(time_limit, &tm);
9970#endif
9971
9972 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9973 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009974 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9975 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009976 if (pat2 == NULL || pat3 == NULL)
9977 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009978 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009979 if (*mpat == NUL)
9980 STRCPY(pat3, pat2);
9981 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009982 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009983 spat, epat, mpat);
9984 if (flags & SP_START)
9985 options |= SEARCH_START;
9986
Bram Moolenaar48570482017-10-30 21:48:41 +01009987 if (skip != NULL)
9988 {
9989 /* Empty string means to not use the skip expression. */
9990 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9991 use_skip = skip->vval.v_string != NULL
9992 && *skip->vval.v_string != NUL;
9993 }
9994
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009995 save_cursor = curwin->w_cursor;
9996 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009997 CLEAR_POS(&firstpos);
9998 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009999 pat = pat3;
10000 for (;;)
10001 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010002 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010003 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010004 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010005 /* didn't find it or found the first match again: FAIL */
10006 break;
10007
10008 if (firstpos.lnum == 0)
10009 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010010 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010011 {
10012 /* Found the same position again. Can happen with a pattern that
10013 * has "\zs" at the end and searching backwards. Advance one
10014 * character and try again. */
10015 if (dir == BACKWARD)
10016 decl(&pos);
10017 else
10018 incl(&pos);
10019 }
10020 foundpos = pos;
10021
10022 /* clear the start flag to avoid getting stuck here */
10023 options &= ~SEARCH_START;
10024
10025 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010026 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010027 {
10028 save_pos = curwin->w_cursor;
10029 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010030 err = FALSE;
10031 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010032 curwin->w_cursor = save_pos;
10033 if (err)
10034 {
10035 /* Evaluating {skip} caused an error, break here. */
10036 curwin->w_cursor = save_cursor;
10037 retval = -1;
10038 break;
10039 }
10040 if (r)
10041 continue;
10042 }
10043
10044 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10045 {
10046 /* Found end when searching backwards or start when searching
10047 * forward: nested pair. */
10048 ++nest;
10049 pat = pat2; /* nested, don't search for middle */
10050 }
10051 else
10052 {
10053 /* Found end when searching forward or start when searching
10054 * backward: end of (nested) pair; or found middle in outer pair. */
10055 if (--nest == 1)
10056 pat = pat3; /* outer level, search for middle */
10057 }
10058
10059 if (nest == 0)
10060 {
10061 /* Found the match: return matchcount or line number. */
10062 if (flags & SP_RETCOUNT)
10063 ++retval;
10064 else
10065 retval = pos.lnum;
10066 if (flags & SP_SETPCMARK)
10067 setpcmark();
10068 curwin->w_cursor = pos;
10069 if (!(flags & SP_REPEAT))
10070 break;
10071 nest = 1; /* search for next unmatched */
10072 }
10073 }
10074
10075 if (match_pos != NULL)
10076 {
10077 /* Store the match cursor position */
10078 match_pos->lnum = curwin->w_cursor.lnum;
10079 match_pos->col = curwin->w_cursor.col + 1;
10080 }
10081
10082 /* If 'n' flag is used or search failed: restore cursor position. */
10083 if ((flags & SP_NOMOVE) || retval == 0)
10084 curwin->w_cursor = save_cursor;
10085
10086theend:
10087 vim_free(pat2);
10088 vim_free(pat3);
10089 if (p_cpo == empty_option)
10090 p_cpo = save_cpo;
10091 else
10092 /* Darn, evaluating the {skip} expression changed the value. */
10093 free_string_option(save_cpo);
10094
10095 return retval;
10096}
10097
10098/*
10099 * "searchpos()" function
10100 */
10101 static void
10102f_searchpos(typval_T *argvars, typval_T *rettv)
10103{
10104 pos_T match_pos;
10105 int lnum = 0;
10106 int col = 0;
10107 int n;
10108 int flags = 0;
10109
10110 if (rettv_list_alloc(rettv) == FAIL)
10111 return;
10112
10113 n = search_cmn(argvars, &match_pos, &flags);
10114 if (n > 0)
10115 {
10116 lnum = match_pos.lnum;
10117 col = match_pos.col;
10118 }
10119
10120 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10121 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10122 if (flags & SP_SUBPAT)
10123 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10124}
10125
10126 static void
10127f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10128{
10129#ifdef FEAT_CLIENTSERVER
10130 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010131 char_u *server = tv_get_string_chk(&argvars[0]);
10132 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010133
10134 rettv->vval.v_number = -1;
10135 if (server == NULL || reply == NULL)
10136 return;
10137 if (check_restricted() || check_secure())
10138 return;
10139# ifdef FEAT_X11
10140 if (check_connection() == FAIL)
10141 return;
10142# endif
10143
10144 if (serverSendReply(server, reply) < 0)
10145 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010146 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010147 return;
10148 }
10149 rettv->vval.v_number = 0;
10150#else
10151 rettv->vval.v_number = -1;
10152#endif
10153}
10154
10155 static void
10156f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10157{
10158 char_u *r = NULL;
10159
10160#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010161# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010162 r = serverGetVimNames();
10163# else
10164 make_connection();
10165 if (X_DISPLAY != NULL)
10166 r = serverGetVimNames(X_DISPLAY);
10167# endif
10168#endif
10169 rettv->v_type = VAR_STRING;
10170 rettv->vval.v_string = r;
10171}
10172
10173/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010174 * "setbufline()" function
10175 */
10176 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010177f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010178{
10179 linenr_T lnum;
10180 buf_T *buf;
10181
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010182 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010183 if (buf == NULL)
10184 rettv->vval.v_number = 1; /* FAIL */
10185 else
10186 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010187 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010188 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010189 }
10190}
10191
10192/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010193 * "setbufvar()" function
10194 */
10195 static void
10196f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10197{
10198 buf_T *buf;
10199 char_u *varname, *bufvarname;
10200 typval_T *varp;
10201 char_u nbuf[NUMBUFLEN];
10202
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010203 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010204 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010205 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10206 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010207 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010208 varp = &argvars[2];
10209
10210 if (buf != NULL && varname != NULL && varp != NULL)
10211 {
10212 if (*varname == '&')
10213 {
10214 long numval;
10215 char_u *strval;
10216 int error = FALSE;
10217 aco_save_T aco;
10218
10219 /* set curbuf to be our buf, temporarily */
10220 aucmd_prepbuf(&aco, buf);
10221
10222 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010223 numval = (long)tv_get_number_chk(varp, &error);
10224 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010225 if (!error && strval != NULL)
10226 set_option_value(varname, numval, strval, OPT_LOCAL);
10227
10228 /* reset notion of buffer */
10229 aucmd_restbuf(&aco);
10230 }
10231 else
10232 {
10233 buf_T *save_curbuf = curbuf;
10234
Bram Moolenaar964b3742019-05-24 18:54:09 +020010235 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010236 if (bufvarname != NULL)
10237 {
10238 curbuf = buf;
10239 STRCPY(bufvarname, "b:");
10240 STRCPY(bufvarname + 2, varname);
10241 set_var(bufvarname, varp, TRUE);
10242 vim_free(bufvarname);
10243 curbuf = save_curbuf;
10244 }
10245 }
10246 }
10247}
10248
10249 static void
10250f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10251{
10252 dict_T *d;
10253 dictitem_T *di;
10254 char_u *csearch;
10255
10256 if (argvars[0].v_type != VAR_DICT)
10257 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010258 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259 return;
10260 }
10261
10262 if ((d = argvars[0].vval.v_dict) != NULL)
10263 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010264 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010265 if (csearch != NULL)
10266 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010267 if (enc_utf8)
10268 {
10269 int pcc[MAX_MCO];
10270 int c = utfc_ptr2char(csearch, pcc);
10271
10272 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10273 }
10274 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 set_last_csearch(PTR2CHAR(csearch),
10276 csearch, MB_PTR2LEN(csearch));
10277 }
10278
10279 di = dict_find(d, (char_u *)"forward", -1);
10280 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010281 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010282 ? FORWARD : BACKWARD);
10283
10284 di = dict_find(d, (char_u *)"until", -1);
10285 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010286 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010287 }
10288}
10289
10290/*
10291 * "setcmdpos()" function
10292 */
10293 static void
10294f_setcmdpos(typval_T *argvars, typval_T *rettv)
10295{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010296 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010297
10298 if (pos >= 0)
10299 rettv->vval.v_number = set_cmdline_pos(pos);
10300}
10301
10302/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010303 * "setenv()" function
10304 */
10305 static void
10306f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10307{
10308 char_u namebuf[NUMBUFLEN];
10309 char_u valbuf[NUMBUFLEN];
10310 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10311
10312 if (argvars[1].v_type == VAR_SPECIAL
10313 && argvars[1].vval.v_number == VVAL_NULL)
10314 vim_unsetenv(name);
10315 else
10316 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10317}
10318
10319/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010320 * "setfperm({fname}, {mode})" function
10321 */
10322 static void
10323f_setfperm(typval_T *argvars, typval_T *rettv)
10324{
10325 char_u *fname;
10326 char_u modebuf[NUMBUFLEN];
10327 char_u *mode_str;
10328 int i;
10329 int mask;
10330 int mode = 0;
10331
10332 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010333 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010334 if (fname == NULL)
10335 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010336 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010337 if (mode_str == NULL)
10338 return;
10339 if (STRLEN(mode_str) != 9)
10340 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010341 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010342 return;
10343 }
10344
10345 mask = 1;
10346 for (i = 8; i >= 0; --i)
10347 {
10348 if (mode_str[i] != '-')
10349 mode |= mask;
10350 mask = mask << 1;
10351 }
10352 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10353}
10354
10355/*
10356 * "setline()" function
10357 */
10358 static void
10359f_setline(typval_T *argvars, typval_T *rettv)
10360{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010361 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010362
Bram Moolenaarca851592018-06-06 21:04:07 +020010363 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010364}
10365
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010366/*
10367 * Used by "setqflist()" and "setloclist()" functions
10368 */
10369 static void
10370set_qf_ll_list(
10371 win_T *wp UNUSED,
10372 typval_T *list_arg UNUSED,
10373 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010374 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010375 typval_T *rettv)
10376{
10377#ifdef FEAT_QUICKFIX
10378 static char *e_invact = N_("E927: Invalid action: '%s'");
10379 char_u *act;
10380 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010381 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010382#endif
10383
10384 rettv->vval.v_number = -1;
10385
10386#ifdef FEAT_QUICKFIX
10387 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010388 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010389 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010390 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010391 else
10392 {
10393 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010394 dict_T *d = NULL;
10395 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010396
10397 if (action_arg->v_type == VAR_STRING)
10398 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010399 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400 if (act == NULL)
10401 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010402 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10403 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010404 action = *act;
10405 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010406 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010407 }
10408 else if (action_arg->v_type == VAR_UNKNOWN)
10409 action = ' ';
10410 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010411 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010412
Bram Moolenaard823fa92016-08-12 16:29:27 +020010413 if (action_arg->v_type != VAR_UNKNOWN
10414 && what_arg->v_type != VAR_UNKNOWN)
10415 {
10416 if (what_arg->v_type == VAR_DICT)
10417 d = what_arg->vval.v_dict;
10418 else
10419 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010420 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010421 valid_dict = FALSE;
10422 }
10423 }
10424
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010425 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010426 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010427 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10428 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010429 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010430 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010431 }
10432#endif
10433}
10434
10435/*
10436 * "setloclist()" function
10437 */
10438 static void
10439f_setloclist(typval_T *argvars, typval_T *rettv)
10440{
10441 win_T *win;
10442
10443 rettv->vval.v_number = -1;
10444
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010445 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010446 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010447 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010448}
10449
10450/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010451 * "setpos()" function
10452 */
10453 static void
10454f_setpos(typval_T *argvars, typval_T *rettv)
10455{
10456 pos_T pos;
10457 int fnum;
10458 char_u *name;
10459 colnr_T curswant = -1;
10460
10461 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010462 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010463 if (name != NULL)
10464 {
10465 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10466 {
10467 if (--pos.col < 0)
10468 pos.col = 0;
10469 if (name[0] == '.' && name[1] == NUL)
10470 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010471 /* set cursor; "fnum" is ignored */
10472 curwin->w_cursor = pos;
10473 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010474 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010475 curwin->w_curswant = curswant - 1;
10476 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010477 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010478 check_cursor();
10479 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010480 }
10481 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10482 {
10483 /* set mark */
10484 if (setmark_pos(name[1], &pos, fnum) == OK)
10485 rettv->vval.v_number = 0;
10486 }
10487 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010488 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010489 }
10490 }
10491}
10492
10493/*
10494 * "setqflist()" function
10495 */
10496 static void
10497f_setqflist(typval_T *argvars, typval_T *rettv)
10498{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010499 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010500}
10501
10502/*
10503 * "setreg()" function
10504 */
10505 static void
10506f_setreg(typval_T *argvars, typval_T *rettv)
10507{
10508 int regname;
10509 char_u *strregname;
10510 char_u *stropt;
10511 char_u *strval;
10512 int append;
10513 char_u yank_type;
10514 long block_len;
10515
10516 block_len = -1;
10517 yank_type = MAUTO;
10518 append = FALSE;
10519
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010520 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010521 rettv->vval.v_number = 1; /* FAIL is default */
10522
10523 if (strregname == NULL)
10524 return; /* type error; errmsg already given */
10525 regname = *strregname;
10526 if (regname == 0 || regname == '@')
10527 regname = '"';
10528
10529 if (argvars[2].v_type != VAR_UNKNOWN)
10530 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010531 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010532 if (stropt == NULL)
10533 return; /* type error */
10534 for (; *stropt != NUL; ++stropt)
10535 switch (*stropt)
10536 {
10537 case 'a': case 'A': /* append */
10538 append = TRUE;
10539 break;
10540 case 'v': case 'c': /* character-wise selection */
10541 yank_type = MCHAR;
10542 break;
10543 case 'V': case 'l': /* line-wise selection */
10544 yank_type = MLINE;
10545 break;
10546 case 'b': case Ctrl_V: /* block-wise selection */
10547 yank_type = MBLOCK;
10548 if (VIM_ISDIGIT(stropt[1]))
10549 {
10550 ++stropt;
10551 block_len = getdigits(&stropt) - 1;
10552 --stropt;
10553 }
10554 break;
10555 }
10556 }
10557
10558 if (argvars[1].v_type == VAR_LIST)
10559 {
10560 char_u **lstval;
10561 char_u **allocval;
10562 char_u buf[NUMBUFLEN];
10563 char_u **curval;
10564 char_u **curallocval;
10565 list_T *ll = argvars[1].vval.v_list;
10566 listitem_T *li;
10567 int len;
10568
10569 /* If the list is NULL handle like an empty list. */
10570 len = ll == NULL ? 0 : ll->lv_len;
10571
10572 /* First half: use for pointers to result lines; second half: use for
10573 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010574 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010575 if (lstval == NULL)
10576 return;
10577 curval = lstval;
10578 allocval = lstval + len + 2;
10579 curallocval = allocval;
10580
10581 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10582 li = li->li_next)
10583 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010584 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010585 if (strval == NULL)
10586 goto free_lstval;
10587 if (strval == buf)
10588 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010589 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590 * overwrite the string. */
10591 strval = vim_strsave(buf);
10592 if (strval == NULL)
10593 goto free_lstval;
10594 *curallocval++ = strval;
10595 }
10596 *curval++ = strval;
10597 }
10598 *curval++ = NULL;
10599
10600 write_reg_contents_lst(regname, lstval, -1,
10601 append, yank_type, block_len);
10602free_lstval:
10603 while (curallocval > allocval)
10604 vim_free(*--curallocval);
10605 vim_free(lstval);
10606 }
10607 else
10608 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010609 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010610 if (strval == NULL)
10611 return;
10612 write_reg_contents_ex(regname, strval, -1,
10613 append, yank_type, block_len);
10614 }
10615 rettv->vval.v_number = 0;
10616}
10617
10618/*
10619 * "settabvar()" function
10620 */
10621 static void
10622f_settabvar(typval_T *argvars, typval_T *rettv)
10623{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010624 tabpage_T *save_curtab;
10625 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010626 char_u *varname, *tabvarname;
10627 typval_T *varp;
10628
10629 rettv->vval.v_number = 0;
10630
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010631 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010632 return;
10633
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010634 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10635 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010636 varp = &argvars[2];
10637
Bram Moolenaar4033c552017-09-16 20:54:51 +020010638 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010639 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010640 save_curtab = curtab;
10641 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010642
Bram Moolenaar964b3742019-05-24 18:54:09 +020010643 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 if (tabvarname != NULL)
10645 {
10646 STRCPY(tabvarname, "t:");
10647 STRCPY(tabvarname + 2, varname);
10648 set_var(tabvarname, varp, TRUE);
10649 vim_free(tabvarname);
10650 }
10651
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010652 /* Restore current tabpage */
10653 if (valid_tabpage(save_curtab))
10654 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010655 }
10656}
10657
10658/*
10659 * "settabwinvar()" function
10660 */
10661 static void
10662f_settabwinvar(typval_T *argvars, typval_T *rettv)
10663{
10664 setwinvar(argvars, rettv, 1);
10665}
10666
10667/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010668 * "settagstack()" function
10669 */
10670 static void
10671f_settagstack(typval_T *argvars, typval_T *rettv)
10672{
10673 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10674 win_T *wp;
10675 dict_T *d;
10676 int action = 'r';
10677
10678 rettv->vval.v_number = -1;
10679
10680 // first argument: window number or id
10681 wp = find_win_by_nr_or_id(&argvars[0]);
10682 if (wp == NULL)
10683 return;
10684
10685 // second argument: dict with items to set in the tag stack
10686 if (argvars[1].v_type != VAR_DICT)
10687 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010688 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010689 return;
10690 }
10691 d = argvars[1].vval.v_dict;
10692 if (d == NULL)
10693 return;
10694
10695 // third argument: action - 'a' for append and 'r' for replace.
10696 // default is to replace the stack.
10697 if (argvars[2].v_type == VAR_UNKNOWN)
10698 action = 'r';
10699 else if (argvars[2].v_type == VAR_STRING)
10700 {
10701 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010702 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010703 if (actstr == NULL)
10704 return;
10705 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10706 action = *actstr;
10707 else
10708 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010709 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010710 return;
10711 }
10712 }
10713 else
10714 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010715 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010716 return;
10717 }
10718
10719 if (set_tagstack(wp, d, action) == OK)
10720 rettv->vval.v_number = 0;
10721}
10722
10723/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 * "setwinvar()" function
10725 */
10726 static void
10727f_setwinvar(typval_T *argvars, typval_T *rettv)
10728{
10729 setwinvar(argvars, rettv, 0);
10730}
10731
10732#ifdef FEAT_CRYPT
10733/*
10734 * "sha256({string})" function
10735 */
10736 static void
10737f_sha256(typval_T *argvars, typval_T *rettv)
10738{
10739 char_u *p;
10740
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010741 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010742 rettv->vval.v_string = vim_strsave(
10743 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10744 rettv->v_type = VAR_STRING;
10745}
10746#endif /* FEAT_CRYPT */
10747
10748/*
10749 * "shellescape({string})" function
10750 */
10751 static void
10752f_shellescape(typval_T *argvars, typval_T *rettv)
10753{
Bram Moolenaar20615522017-06-05 18:46:26 +020010754 int do_special = non_zero_arg(&argvars[1]);
10755
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010756 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010757 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010758 rettv->v_type = VAR_STRING;
10759}
10760
10761/*
10762 * shiftwidth() function
10763 */
10764 static void
10765f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10766{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010767 rettv->vval.v_number = 0;
10768
10769 if (argvars[0].v_type != VAR_UNKNOWN)
10770 {
10771 long col;
10772
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010773 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010774 if (col < 0)
10775 return; // type error; errmsg already given
10776#ifdef FEAT_VARTABS
10777 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10778 return;
10779#endif
10780 }
10781
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 rettv->vval.v_number = get_sw_value(curbuf);
10783}
10784
10785/*
10786 * "simplify()" function
10787 */
10788 static void
10789f_simplify(typval_T *argvars, typval_T *rettv)
10790{
10791 char_u *p;
10792
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010793 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010794 rettv->vval.v_string = vim_strsave(p);
10795 simplify_filename(rettv->vval.v_string); /* simplify in place */
10796 rettv->v_type = VAR_STRING;
10797}
10798
10799#ifdef FEAT_FLOAT
10800/*
10801 * "sin()" function
10802 */
10803 static void
10804f_sin(typval_T *argvars, typval_T *rettv)
10805{
10806 float_T f = 0.0;
10807
10808 rettv->v_type = VAR_FLOAT;
10809 if (get_float_arg(argvars, &f) == OK)
10810 rettv->vval.v_float = sin(f);
10811 else
10812 rettv->vval.v_float = 0.0;
10813}
10814
10815/*
10816 * "sinh()" function
10817 */
10818 static void
10819f_sinh(typval_T *argvars, typval_T *rettv)
10820{
10821 float_T f = 0.0;
10822
10823 rettv->v_type = VAR_FLOAT;
10824 if (get_float_arg(argvars, &f) == OK)
10825 rettv->vval.v_float = sinh(f);
10826 else
10827 rettv->vval.v_float = 0.0;
10828}
10829#endif
10830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010831/*
10832 * "soundfold({word})" function
10833 */
10834 static void
10835f_soundfold(typval_T *argvars, typval_T *rettv)
10836{
10837 char_u *s;
10838
10839 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010840 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010841#ifdef FEAT_SPELL
10842 rettv->vval.v_string = eval_soundfold(s);
10843#else
10844 rettv->vval.v_string = vim_strsave(s);
10845#endif
10846}
10847
10848/*
10849 * "spellbadword()" function
10850 */
10851 static void
10852f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10853{
10854 char_u *word = (char_u *)"";
10855 hlf_T attr = HLF_COUNT;
10856 int len = 0;
10857
10858 if (rettv_list_alloc(rettv) == FAIL)
10859 return;
10860
10861#ifdef FEAT_SPELL
10862 if (argvars[0].v_type == VAR_UNKNOWN)
10863 {
10864 /* Find the start and length of the badly spelled word. */
10865 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10866 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010867 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010868 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010869 curwin->w_set_curswant = TRUE;
10870 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010871 }
10872 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10873 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010874 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010875 int capcol = -1;
10876
10877 if (str != NULL)
10878 {
10879 /* Check the argument for spelling. */
10880 while (*str != NUL)
10881 {
10882 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10883 if (attr != HLF_COUNT)
10884 {
10885 word = str;
10886 break;
10887 }
10888 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010889 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010890 }
10891 }
10892 }
10893#endif
10894
10895 list_append_string(rettv->vval.v_list, word, len);
10896 list_append_string(rettv->vval.v_list, (char_u *)(
10897 attr == HLF_SPB ? "bad" :
10898 attr == HLF_SPR ? "rare" :
10899 attr == HLF_SPL ? "local" :
10900 attr == HLF_SPC ? "caps" :
10901 ""), -1);
10902}
10903
10904/*
10905 * "spellsuggest()" function
10906 */
10907 static void
10908f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10909{
10910#ifdef FEAT_SPELL
10911 char_u *str;
10912 int typeerr = FALSE;
10913 int maxcount;
10914 garray_T ga;
10915 int i;
10916 listitem_T *li;
10917 int need_capital = FALSE;
10918#endif
10919
10920 if (rettv_list_alloc(rettv) == FAIL)
10921 return;
10922
10923#ifdef FEAT_SPELL
10924 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10925 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010926 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010927 if (argvars[1].v_type != VAR_UNKNOWN)
10928 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010929 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010930 if (maxcount <= 0)
10931 return;
10932 if (argvars[2].v_type != VAR_UNKNOWN)
10933 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010934 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010935 if (typeerr)
10936 return;
10937 }
10938 }
10939 else
10940 maxcount = 25;
10941
10942 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10943
10944 for (i = 0; i < ga.ga_len; ++i)
10945 {
10946 str = ((char_u **)ga.ga_data)[i];
10947
10948 li = listitem_alloc();
10949 if (li == NULL)
10950 vim_free(str);
10951 else
10952 {
10953 li->li_tv.v_type = VAR_STRING;
10954 li->li_tv.v_lock = 0;
10955 li->li_tv.vval.v_string = str;
10956 list_append(rettv->vval.v_list, li);
10957 }
10958 }
10959 ga_clear(&ga);
10960 }
10961#endif
10962}
10963
10964 static void
10965f_split(typval_T *argvars, typval_T *rettv)
10966{
10967 char_u *str;
10968 char_u *end;
10969 char_u *pat = NULL;
10970 regmatch_T regmatch;
10971 char_u patbuf[NUMBUFLEN];
10972 char_u *save_cpo;
10973 int match;
10974 colnr_T col = 0;
10975 int keepempty = FALSE;
10976 int typeerr = FALSE;
10977
10978 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10979 save_cpo = p_cpo;
10980 p_cpo = (char_u *)"";
10981
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010982 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010983 if (argvars[1].v_type != VAR_UNKNOWN)
10984 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010985 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010986 if (pat == NULL)
10987 typeerr = TRUE;
10988 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010989 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010990 }
10991 if (pat == NULL || *pat == NUL)
10992 pat = (char_u *)"[\\x01- ]\\+";
10993
10994 if (rettv_list_alloc(rettv) == FAIL)
10995 return;
10996 if (typeerr)
10997 return;
10998
10999 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11000 if (regmatch.regprog != NULL)
11001 {
11002 regmatch.rm_ic = FALSE;
11003 while (*str != NUL || keepempty)
11004 {
11005 if (*str == NUL)
11006 match = FALSE; /* empty item at the end */
11007 else
11008 match = vim_regexec_nl(&regmatch, str, col);
11009 if (match)
11010 end = regmatch.startp[0];
11011 else
11012 end = str + STRLEN(str);
11013 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11014 && *str != NUL && match && end < regmatch.endp[0]))
11015 {
11016 if (list_append_string(rettv->vval.v_list, str,
11017 (int)(end - str)) == FAIL)
11018 break;
11019 }
11020 if (!match)
11021 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010011022 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011023 if (regmatch.endp[0] > str)
11024 col = 0;
11025 else
Bram Moolenaar13505972019-01-24 15:04:48 +010011026 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011027 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011028 str = regmatch.endp[0];
11029 }
11030
11031 vim_regfree(regmatch.regprog);
11032 }
11033
11034 p_cpo = save_cpo;
11035}
11036
11037#ifdef FEAT_FLOAT
11038/*
11039 * "sqrt()" function
11040 */
11041 static void
11042f_sqrt(typval_T *argvars, typval_T *rettv)
11043{
11044 float_T f = 0.0;
11045
11046 rettv->v_type = VAR_FLOAT;
11047 if (get_float_arg(argvars, &f) == OK)
11048 rettv->vval.v_float = sqrt(f);
11049 else
11050 rettv->vval.v_float = 0.0;
11051}
11052
11053/*
11054 * "str2float()" function
11055 */
11056 static void
11057f_str2float(typval_T *argvars, typval_T *rettv)
11058{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011059 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011060 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011061
Bram Moolenaar08243d22017-01-10 16:12:29 +010011062 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 p = skipwhite(p + 1);
11064 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011065 if (isneg)
11066 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011067 rettv->v_type = VAR_FLOAT;
11068}
11069#endif
11070
11071/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020011072 * "str2list()" function
11073 */
11074 static void
11075f_str2list(typval_T *argvars, typval_T *rettv)
11076{
11077 char_u *p;
11078 int utf8 = FALSE;
11079
11080 if (rettv_list_alloc(rettv) == FAIL)
11081 return;
11082
11083 if (argvars[1].v_type != VAR_UNKNOWN)
11084 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
11085
11086 p = tv_get_string(&argvars[0]);
11087
11088 if (has_mbyte || utf8)
11089 {
11090 int (*ptr2len)(char_u *);
11091 int (*ptr2char)(char_u *);
11092
11093 if (utf8 || enc_utf8)
11094 {
11095 ptr2len = utf_ptr2len;
11096 ptr2char = utf_ptr2char;
11097 }
11098 else
11099 {
11100 ptr2len = mb_ptr2len;
11101 ptr2char = mb_ptr2char;
11102 }
11103
11104 for ( ; *p != NUL; p += (*ptr2len)(p))
11105 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
11106 }
11107 else
11108 for ( ; *p != NUL; ++p)
11109 list_append_number(rettv->vval.v_list, *p);
11110}
11111
11112/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011113 * "str2nr()" function
11114 */
11115 static void
11116f_str2nr(typval_T *argvars, typval_T *rettv)
11117{
11118 int base = 10;
11119 char_u *p;
11120 varnumber_T n;
11121 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011122 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011123
11124 if (argvars[1].v_type != VAR_UNKNOWN)
11125 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011126 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011127 if (base != 2 && base != 8 && base != 10 && base != 16)
11128 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011129 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011130 return;
11131 }
11132 }
11133
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011134 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011135 isneg = (*p == '-');
11136 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011137 p = skipwhite(p + 1);
11138 switch (base)
11139 {
11140 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11141 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11142 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11143 default: what = 0;
11144 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020011145 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
11146 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010011147 if (isneg)
11148 rettv->vval.v_number = -n;
11149 else
11150 rettv->vval.v_number = n;
11151
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152}
11153
11154#ifdef HAVE_STRFTIME
11155/*
11156 * "strftime({format}[, {time}])" function
11157 */
11158 static void
11159f_strftime(typval_T *argvars, typval_T *rettv)
11160{
11161 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020011162 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011163 struct tm *curtime;
11164 time_t seconds;
11165 char_u *p;
11166
11167 rettv->v_type = VAR_STRING;
11168
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011169 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011170 if (argvars[1].v_type == VAR_UNKNOWN)
11171 seconds = time(NULL);
11172 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011173 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020011174 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011175 /* MSVC returns NULL for an invalid value of seconds. */
11176 if (curtime == NULL)
11177 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11178 else
11179 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011180 vimconv_T conv;
11181 char_u *enc;
11182
11183 conv.vc_type = CONV_NONE;
11184 enc = enc_locale();
11185 convert_setup(&conv, p_enc, enc);
11186 if (conv.vc_type != CONV_NONE)
11187 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011188 if (p != NULL)
11189 (void)strftime((char *)result_buf, sizeof(result_buf),
11190 (char *)p, curtime);
11191 else
11192 result_buf[0] = NUL;
11193
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011194 if (conv.vc_type != CONV_NONE)
11195 vim_free(p);
11196 convert_setup(&conv, enc, p_enc);
11197 if (conv.vc_type != CONV_NONE)
11198 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11199 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011200 rettv->vval.v_string = vim_strsave(result_buf);
11201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011202 /* Release conversion descriptors */
11203 convert_setup(&conv, NULL, NULL);
11204 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205 }
11206}
11207#endif
11208
11209/*
11210 * "strgetchar()" function
11211 */
11212 static void
11213f_strgetchar(typval_T *argvars, typval_T *rettv)
11214{
11215 char_u *str;
11216 int len;
11217 int error = FALSE;
11218 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011219 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011220
11221 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011222 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011223 if (str == NULL)
11224 return;
11225 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011226 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011227 if (error)
11228 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011229
Bram Moolenaar13505972019-01-24 15:04:48 +010011230 while (charidx >= 0 && byteidx < len)
11231 {
11232 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011233 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011234 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11235 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011237 --charidx;
11238 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011239 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240}
11241
11242/*
11243 * "stridx()" function
11244 */
11245 static void
11246f_stridx(typval_T *argvars, typval_T *rettv)
11247{
11248 char_u buf[NUMBUFLEN];
11249 char_u *needle;
11250 char_u *haystack;
11251 char_u *save_haystack;
11252 char_u *pos;
11253 int start_idx;
11254
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011255 needle = tv_get_string_chk(&argvars[1]);
11256 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011257 rettv->vval.v_number = -1;
11258 if (needle == NULL || haystack == NULL)
11259 return; /* type error; errmsg already given */
11260
11261 if (argvars[2].v_type != VAR_UNKNOWN)
11262 {
11263 int error = FALSE;
11264
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011265 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011266 if (error || start_idx >= (int)STRLEN(haystack))
11267 return;
11268 if (start_idx >= 0)
11269 haystack += start_idx;
11270 }
11271
11272 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11273 if (pos != NULL)
11274 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11275}
11276
11277/*
11278 * "string()" function
11279 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011280 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011281f_string(typval_T *argvars, typval_T *rettv)
11282{
11283 char_u *tofree;
11284 char_u numbuf[NUMBUFLEN];
11285
11286 rettv->v_type = VAR_STRING;
11287 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11288 get_copyID());
11289 /* Make a copy if we have a value but it's not in allocated memory. */
11290 if (rettv->vval.v_string != NULL && tofree == NULL)
11291 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11292}
11293
11294/*
11295 * "strlen()" function
11296 */
11297 static void
11298f_strlen(typval_T *argvars, typval_T *rettv)
11299{
11300 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011301 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011302}
11303
11304/*
11305 * "strchars()" function
11306 */
11307 static void
11308f_strchars(typval_T *argvars, typval_T *rettv)
11309{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011310 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011311 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011312 varnumber_T len = 0;
11313 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011314
11315 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011316 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011317 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011318 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011319 else
11320 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011321 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11322 while (*s != NUL)
11323 {
11324 func_mb_ptr2char_adv(&s);
11325 ++len;
11326 }
11327 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011328 }
11329}
11330
11331/*
11332 * "strdisplaywidth()" function
11333 */
11334 static void
11335f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11336{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011337 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011338 int col = 0;
11339
11340 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011341 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011342
11343 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11344}
11345
11346/*
11347 * "strwidth()" function
11348 */
11349 static void
11350f_strwidth(typval_T *argvars, typval_T *rettv)
11351{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011352 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011353
Bram Moolenaar13505972019-01-24 15:04:48 +010011354 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011355}
11356
11357/*
11358 * "strcharpart()" function
11359 */
11360 static void
11361f_strcharpart(typval_T *argvars, typval_T *rettv)
11362{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011363 char_u *p;
11364 int nchar;
11365 int nbyte = 0;
11366 int charlen;
11367 int len = 0;
11368 int slen;
11369 int error = FALSE;
11370
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011371 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011372 slen = (int)STRLEN(p);
11373
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011374 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011375 if (!error)
11376 {
11377 if (nchar > 0)
11378 while (nchar > 0 && nbyte < slen)
11379 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011380 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011381 --nchar;
11382 }
11383 else
11384 nbyte = nchar;
11385 if (argvars[2].v_type != VAR_UNKNOWN)
11386 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011387 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011388 while (charlen > 0 && nbyte + len < slen)
11389 {
11390 int off = nbyte + len;
11391
11392 if (off < 0)
11393 len += 1;
11394 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011395 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011396 --charlen;
11397 }
11398 }
11399 else
11400 len = slen - nbyte; /* default: all bytes that are available. */
11401 }
11402
11403 /*
11404 * Only return the overlap between the specified part and the actual
11405 * string.
11406 */
11407 if (nbyte < 0)
11408 {
11409 len += nbyte;
11410 nbyte = 0;
11411 }
11412 else if (nbyte > slen)
11413 nbyte = slen;
11414 if (len < 0)
11415 len = 0;
11416 else if (nbyte + len > slen)
11417 len = slen - nbyte;
11418
11419 rettv->v_type = VAR_STRING;
11420 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011421}
11422
11423/*
11424 * "strpart()" function
11425 */
11426 static void
11427f_strpart(typval_T *argvars, typval_T *rettv)
11428{
11429 char_u *p;
11430 int n;
11431 int len;
11432 int slen;
11433 int error = FALSE;
11434
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011435 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011436 slen = (int)STRLEN(p);
11437
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011438 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011439 if (error)
11440 len = 0;
11441 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011442 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011443 else
11444 len = slen - n; /* default len: all bytes that are available. */
11445
11446 /*
11447 * Only return the overlap between the specified part and the actual
11448 * string.
11449 */
11450 if (n < 0)
11451 {
11452 len += n;
11453 n = 0;
11454 }
11455 else if (n > slen)
11456 n = slen;
11457 if (len < 0)
11458 len = 0;
11459 else if (n + len > slen)
11460 len = slen - n;
11461
11462 rettv->v_type = VAR_STRING;
11463 rettv->vval.v_string = vim_strnsave(p + n, len);
11464}
11465
11466/*
11467 * "strridx()" function
11468 */
11469 static void
11470f_strridx(typval_T *argvars, typval_T *rettv)
11471{
11472 char_u buf[NUMBUFLEN];
11473 char_u *needle;
11474 char_u *haystack;
11475 char_u *rest;
11476 char_u *lastmatch = NULL;
11477 int haystack_len, end_idx;
11478
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011479 needle = tv_get_string_chk(&argvars[1]);
11480 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011481
11482 rettv->vval.v_number = -1;
11483 if (needle == NULL || haystack == NULL)
11484 return; /* type error; errmsg already given */
11485
11486 haystack_len = (int)STRLEN(haystack);
11487 if (argvars[2].v_type != VAR_UNKNOWN)
11488 {
11489 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011490 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011491 if (end_idx < 0)
11492 return; /* can never find a match */
11493 }
11494 else
11495 end_idx = haystack_len;
11496
11497 if (*needle == NUL)
11498 {
11499 /* Empty string matches past the end. */
11500 lastmatch = haystack + end_idx;
11501 }
11502 else
11503 {
11504 for (rest = haystack; *rest != '\0'; ++rest)
11505 {
11506 rest = (char_u *)strstr((char *)rest, (char *)needle);
11507 if (rest == NULL || rest > haystack + end_idx)
11508 break;
11509 lastmatch = rest;
11510 }
11511 }
11512
11513 if (lastmatch == NULL)
11514 rettv->vval.v_number = -1;
11515 else
11516 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11517}
11518
11519/*
11520 * "strtrans()" function
11521 */
11522 static void
11523f_strtrans(typval_T *argvars, typval_T *rettv)
11524{
11525 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011526 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011527}
11528
11529/*
11530 * "submatch()" function
11531 */
11532 static void
11533f_submatch(typval_T *argvars, typval_T *rettv)
11534{
11535 int error = FALSE;
11536 int no;
11537 int retList = 0;
11538
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011539 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011540 if (error)
11541 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011542 if (no < 0 || no >= NSUBEXP)
11543 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011544 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011545 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011546 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011547 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011548 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011549 if (error)
11550 return;
11551
11552 if (retList == 0)
11553 {
11554 rettv->v_type = VAR_STRING;
11555 rettv->vval.v_string = reg_submatch(no);
11556 }
11557 else
11558 {
11559 rettv->v_type = VAR_LIST;
11560 rettv->vval.v_list = reg_submatch_list(no);
11561 }
11562}
11563
11564/*
11565 * "substitute()" function
11566 */
11567 static void
11568f_substitute(typval_T *argvars, typval_T *rettv)
11569{
11570 char_u patbuf[NUMBUFLEN];
11571 char_u subbuf[NUMBUFLEN];
11572 char_u flagsbuf[NUMBUFLEN];
11573
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011574 char_u *str = tv_get_string_chk(&argvars[0]);
11575 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011576 char_u *sub = NULL;
11577 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011578 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011579
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011580 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11581 expr = &argvars[2];
11582 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011583 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011584
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011585 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011586 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11587 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011588 rettv->vval.v_string = NULL;
11589 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011590 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011591}
11592
11593/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011594 * "swapinfo(swap_filename)" function
11595 */
11596 static void
11597f_swapinfo(typval_T *argvars, typval_T *rettv)
11598{
11599 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011600 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011601}
11602
11603/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011604 * "swapname(expr)" function
11605 */
11606 static void
11607f_swapname(typval_T *argvars, typval_T *rettv)
11608{
11609 buf_T *buf;
11610
11611 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011612 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011613 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11614 || buf->b_ml.ml_mfp->mf_fname == NULL)
11615 rettv->vval.v_string = NULL;
11616 else
11617 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11618}
11619
11620/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011621 * "synID(lnum, col, trans)" function
11622 */
11623 static void
11624f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11625{
11626 int id = 0;
11627#ifdef FEAT_SYN_HL
11628 linenr_T lnum;
11629 colnr_T col;
11630 int trans;
11631 int transerr = FALSE;
11632
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011633 lnum = tv_get_lnum(argvars); /* -1 on type error */
11634 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11635 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011636
11637 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11638 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11639 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11640#endif
11641
11642 rettv->vval.v_number = id;
11643}
11644
11645/*
11646 * "synIDattr(id, what [, mode])" function
11647 */
11648 static void
11649f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11650{
11651 char_u *p = NULL;
11652#ifdef FEAT_SYN_HL
11653 int id;
11654 char_u *what;
11655 char_u *mode;
11656 char_u modebuf[NUMBUFLEN];
11657 int modec;
11658
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011659 id = (int)tv_get_number(&argvars[0]);
11660 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011661 if (argvars[2].v_type != VAR_UNKNOWN)
11662 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011663 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011664 modec = TOLOWER_ASC(mode[0]);
11665 if (modec != 't' && modec != 'c' && modec != 'g')
11666 modec = 0; /* replace invalid with current */
11667 }
11668 else
11669 {
11670#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11671 if (USE_24BIT)
11672 modec = 'g';
11673 else
11674#endif
11675 if (t_colors > 1)
11676 modec = 'c';
11677 else
11678 modec = 't';
11679 }
11680
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011681 switch (TOLOWER_ASC(what[0]))
11682 {
11683 case 'b':
11684 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11685 p = highlight_color(id, what, modec);
11686 else /* bold */
11687 p = highlight_has_attr(id, HL_BOLD, modec);
11688 break;
11689
11690 case 'f': /* fg[#] or font */
11691 p = highlight_color(id, what, modec);
11692 break;
11693
11694 case 'i':
11695 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11696 p = highlight_has_attr(id, HL_INVERSE, modec);
11697 else /* italic */
11698 p = highlight_has_attr(id, HL_ITALIC, modec);
11699 break;
11700
11701 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011702 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011703 break;
11704
11705 case 'r': /* reverse */
11706 p = highlight_has_attr(id, HL_INVERSE, modec);
11707 break;
11708
11709 case 's':
11710 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11711 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011712 /* strikeout */
11713 else if (TOLOWER_ASC(what[1]) == 't' &&
11714 TOLOWER_ASC(what[2]) == 'r')
11715 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011716 else /* standout */
11717 p = highlight_has_attr(id, HL_STANDOUT, modec);
11718 break;
11719
11720 case 'u':
11721 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11722 /* underline */
11723 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11724 else
11725 /* undercurl */
11726 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11727 break;
11728 }
11729
11730 if (p != NULL)
11731 p = vim_strsave(p);
11732#endif
11733 rettv->v_type = VAR_STRING;
11734 rettv->vval.v_string = p;
11735}
11736
11737/*
11738 * "synIDtrans(id)" function
11739 */
11740 static void
11741f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11742{
11743 int id;
11744
11745#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011746 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011747
11748 if (id > 0)
11749 id = syn_get_final_id(id);
11750 else
11751#endif
11752 id = 0;
11753
11754 rettv->vval.v_number = id;
11755}
11756
11757/*
11758 * "synconcealed(lnum, col)" function
11759 */
11760 static void
11761f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11762{
11763#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11764 linenr_T lnum;
11765 colnr_T col;
11766 int syntax_flags = 0;
11767 int cchar;
11768 int matchid = 0;
11769 char_u str[NUMBUFLEN];
11770#endif
11771
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011772 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011773
11774#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011775 lnum = tv_get_lnum(argvars); /* -1 on type error */
11776 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011777
11778 vim_memset(str, NUL, sizeof(str));
11779
11780 if (rettv_list_alloc(rettv) != FAIL)
11781 {
11782 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11783 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11784 && curwin->w_p_cole > 0)
11785 {
11786 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11787 syntax_flags = get_syntax_info(&matchid);
11788
11789 /* get the conceal character */
11790 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11791 {
11792 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011793 if (cchar == NUL && curwin->w_p_cole == 1)
11794 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011795 if (cchar != NUL)
11796 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011797 if (has_mbyte)
11798 (*mb_char2bytes)(cchar, str);
11799 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011800 str[0] = cchar;
11801 }
11802 }
11803 }
11804
11805 list_append_number(rettv->vval.v_list,
11806 (syntax_flags & HL_CONCEAL) != 0);
11807 /* -1 to auto-determine strlen */
11808 list_append_string(rettv->vval.v_list, str, -1);
11809 list_append_number(rettv->vval.v_list, matchid);
11810 }
11811#endif
11812}
11813
11814/*
11815 * "synstack(lnum, col)" function
11816 */
11817 static void
11818f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11819{
11820#ifdef FEAT_SYN_HL
11821 linenr_T lnum;
11822 colnr_T col;
11823 int i;
11824 int id;
11825#endif
11826
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011827 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011828
11829#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011830 lnum = tv_get_lnum(argvars); /* -1 on type error */
11831 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011832
11833 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11834 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11835 && rettv_list_alloc(rettv) != FAIL)
11836 {
11837 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11838 for (i = 0; ; ++i)
11839 {
11840 id = syn_get_stack_item(i);
11841 if (id < 0)
11842 break;
11843 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11844 break;
11845 }
11846 }
11847#endif
11848}
11849
11850 static void
11851get_cmd_output_as_rettv(
11852 typval_T *argvars,
11853 typval_T *rettv,
11854 int retlist)
11855{
11856 char_u *res = NULL;
11857 char_u *p;
11858 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011859 int err = FALSE;
11860 FILE *fd;
11861 list_T *list = NULL;
11862 int flags = SHELL_SILENT;
11863
11864 rettv->v_type = VAR_STRING;
11865 rettv->vval.v_string = NULL;
11866 if (check_restricted() || check_secure())
11867 goto errret;
11868
11869 if (argvars[1].v_type != VAR_UNKNOWN)
11870 {
11871 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011872 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011873 * command.
11874 */
11875 if ((infile = vim_tempname('i', TRUE)) == NULL)
11876 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011877 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011878 goto errret;
11879 }
11880
11881 fd = mch_fopen((char *)infile, WRITEBIN);
11882 if (fd == NULL)
11883 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011884 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011885 goto errret;
11886 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011887 if (argvars[1].v_type == VAR_NUMBER)
11888 {
11889 linenr_T lnum;
11890 buf_T *buf;
11891
11892 buf = buflist_findnr(argvars[1].vval.v_number);
11893 if (buf == NULL)
11894 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011895 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011896 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011897 goto errret;
11898 }
11899
11900 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11901 {
11902 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11903 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11904 {
11905 err = TRUE;
11906 break;
11907 }
11908 if (putc(NL, fd) == EOF)
11909 {
11910 err = TRUE;
11911 break;
11912 }
11913 }
11914 }
11915 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011916 {
11917 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11918 err = TRUE;
11919 }
11920 else
11921 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011922 size_t len;
11923 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011924
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011925 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011926 if (p == NULL)
11927 {
11928 fclose(fd);
11929 goto errret; /* type error; errmsg already given */
11930 }
11931 len = STRLEN(p);
11932 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11933 err = TRUE;
11934 }
11935 if (fclose(fd) != 0)
11936 err = TRUE;
11937 if (err)
11938 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011939 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011940 goto errret;
11941 }
11942 }
11943
11944 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11945 * echoes typeahead, that messes up the display. */
11946 if (!msg_silent)
11947 flags += SHELL_COOKED;
11948
11949 if (retlist)
11950 {
11951 int len;
11952 listitem_T *li;
11953 char_u *s = NULL;
11954 char_u *start;
11955 char_u *end;
11956 int i;
11957
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011958 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011959 if (res == NULL)
11960 goto errret;
11961
11962 list = list_alloc();
11963 if (list == NULL)
11964 goto errret;
11965
11966 for (i = 0; i < len; ++i)
11967 {
11968 start = res + i;
11969 while (i < len && res[i] != NL)
11970 ++i;
11971 end = res + i;
11972
Bram Moolenaar964b3742019-05-24 18:54:09 +020011973 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011974 if (s == NULL)
11975 goto errret;
11976
11977 for (p = s; start < end; ++p, ++start)
11978 *p = *start == NUL ? NL : *start;
11979 *p = NUL;
11980
11981 li = listitem_alloc();
11982 if (li == NULL)
11983 {
11984 vim_free(s);
11985 goto errret;
11986 }
11987 li->li_tv.v_type = VAR_STRING;
11988 li->li_tv.v_lock = 0;
11989 li->li_tv.vval.v_string = s;
11990 list_append(list, li);
11991 }
11992
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011993 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011994 list = NULL;
11995 }
11996 else
11997 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011998 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011999#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012000 /* translate <CR><NL> into <NL> */
12001 if (res != NULL)
12002 {
12003 char_u *s, *d;
12004
12005 d = res;
12006 for (s = res; *s; ++s)
12007 {
12008 if (s[0] == CAR && s[1] == NL)
12009 ++s;
12010 *d++ = *s;
12011 }
12012 *d = NUL;
12013 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012014#endif
12015 rettv->vval.v_string = res;
12016 res = NULL;
12017 }
12018
12019errret:
12020 if (infile != NULL)
12021 {
12022 mch_remove(infile);
12023 vim_free(infile);
12024 }
12025 if (res != NULL)
12026 vim_free(res);
12027 if (list != NULL)
12028 list_free(list);
12029}
12030
12031/*
12032 * "system()" function
12033 */
12034 static void
12035f_system(typval_T *argvars, typval_T *rettv)
12036{
12037 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12038}
12039
12040/*
12041 * "systemlist()" function
12042 */
12043 static void
12044f_systemlist(typval_T *argvars, typval_T *rettv)
12045{
12046 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12047}
12048
12049/*
12050 * "tabpagebuflist()" function
12051 */
12052 static void
12053f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12054{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012055 tabpage_T *tp;
12056 win_T *wp = NULL;
12057
12058 if (argvars[0].v_type == VAR_UNKNOWN)
12059 wp = firstwin;
12060 else
12061 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012062 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012063 if (tp != NULL)
12064 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12065 }
12066 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12067 {
12068 for (; wp != NULL; wp = wp->w_next)
12069 if (list_append_number(rettv->vval.v_list,
12070 wp->w_buffer->b_fnum) == FAIL)
12071 break;
12072 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012073}
12074
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012075/*
12076 * "tabpagenr()" function
12077 */
12078 static void
12079f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12080{
12081 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012082 char_u *arg;
12083
12084 if (argvars[0].v_type != VAR_UNKNOWN)
12085 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012086 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012087 nr = 0;
12088 if (arg != NULL)
12089 {
12090 if (STRCMP(arg, "$") == 0)
12091 nr = tabpage_index(NULL) - 1;
12092 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012093 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012094 }
12095 }
12096 else
12097 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012098 rettv->vval.v_number = nr;
12099}
12100
12101
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012102/*
12103 * Common code for tabpagewinnr() and winnr().
12104 */
12105 static int
12106get_winnr(tabpage_T *tp, typval_T *argvar)
12107{
12108 win_T *twin;
12109 int nr = 1;
12110 win_T *wp;
12111 char_u *arg;
12112
12113 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12114 if (argvar->v_type != VAR_UNKNOWN)
12115 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012116 int invalid_arg = FALSE;
12117
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012118 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012119 if (arg == NULL)
12120 nr = 0; /* type error; errmsg already given */
12121 else if (STRCMP(arg, "$") == 0)
12122 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12123 else if (STRCMP(arg, "#") == 0)
12124 {
12125 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12126 if (twin == NULL)
12127 nr = 0;
12128 }
12129 else
12130 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012131 long count;
12132 char_u *endp;
12133
12134 // Extract the window count (if specified). e.g. winnr('3j')
12135 count = strtol((char *)arg, (char **)&endp, 10);
12136 if (count <= 0)
12137 count = 1; // if count is not specified, default to 1
12138 if (endp != NULL && *endp != '\0')
12139 {
12140 if (STRCMP(endp, "j") == 0)
12141 twin = win_vert_neighbor(tp, twin, FALSE, count);
12142 else if (STRCMP(endp, "k") == 0)
12143 twin = win_vert_neighbor(tp, twin, TRUE, count);
12144 else if (STRCMP(endp, "h") == 0)
12145 twin = win_horz_neighbor(tp, twin, TRUE, count);
12146 else if (STRCMP(endp, "l") == 0)
12147 twin = win_horz_neighbor(tp, twin, FALSE, count);
12148 else
12149 invalid_arg = TRUE;
12150 }
12151 else
12152 invalid_arg = TRUE;
12153 }
12154
12155 if (invalid_arg)
12156 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012157 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012158 nr = 0;
12159 }
12160 }
12161
12162 if (nr > 0)
12163 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12164 wp != twin; wp = wp->w_next)
12165 {
12166 if (wp == NULL)
12167 {
12168 /* didn't find it in this tabpage */
12169 nr = 0;
12170 break;
12171 }
12172 ++nr;
12173 }
12174 return nr;
12175}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012176
12177/*
12178 * "tabpagewinnr()" function
12179 */
12180 static void
12181f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12182{
12183 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012184 tabpage_T *tp;
12185
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012186 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012187 if (tp == NULL)
12188 nr = 0;
12189 else
12190 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012191 rettv->vval.v_number = nr;
12192}
12193
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012194/*
12195 * "tagfiles()" function
12196 */
12197 static void
12198f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12199{
12200 char_u *fname;
12201 tagname_T tn;
12202 int first;
12203
12204 if (rettv_list_alloc(rettv) == FAIL)
12205 return;
12206 fname = alloc(MAXPATHL);
12207 if (fname == NULL)
12208 return;
12209
12210 for (first = TRUE; ; first = FALSE)
12211 if (get_tagfname(&tn, first, fname) == FAIL
12212 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12213 break;
12214 tagname_free(&tn);
12215 vim_free(fname);
12216}
12217
12218/*
12219 * "taglist()" function
12220 */
12221 static void
12222f_taglist(typval_T *argvars, typval_T *rettv)
12223{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012224 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012225 char_u *tag_pattern;
12226
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012227 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012228
12229 rettv->vval.v_number = FALSE;
12230 if (*tag_pattern == NUL)
12231 return;
12232
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012233 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012234 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012235 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012236 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012237}
12238
12239/*
12240 * "tempname()" function
12241 */
12242 static void
12243f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12244{
12245 static int x = 'A';
12246
12247 rettv->v_type = VAR_STRING;
12248 rettv->vval.v_string = vim_tempname(x, FALSE);
12249
12250 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12251 * names. Skip 'I' and 'O', they are used for shell redirection. */
12252 do
12253 {
12254 if (x == 'Z')
12255 x = '0';
12256 else if (x == '9')
12257 x = 'A';
12258 else
12259 {
12260#ifdef EBCDIC
12261 if (x == 'I')
12262 x = 'J';
12263 else if (x == 'R')
12264 x = 'S';
12265 else
12266#endif
12267 ++x;
12268 }
12269 } while (x == 'I' || x == 'O');
12270}
12271
12272#ifdef FEAT_FLOAT
12273/*
12274 * "tan()" function
12275 */
12276 static void
12277f_tan(typval_T *argvars, typval_T *rettv)
12278{
12279 float_T f = 0.0;
12280
12281 rettv->v_type = VAR_FLOAT;
12282 if (get_float_arg(argvars, &f) == OK)
12283 rettv->vval.v_float = tan(f);
12284 else
12285 rettv->vval.v_float = 0.0;
12286}
12287
12288/*
12289 * "tanh()" function
12290 */
12291 static void
12292f_tanh(typval_T *argvars, typval_T *rettv)
12293{
12294 float_T f = 0.0;
12295
12296 rettv->v_type = VAR_FLOAT;
12297 if (get_float_arg(argvars, &f) == OK)
12298 rettv->vval.v_float = tanh(f);
12299 else
12300 rettv->vval.v_float = 0.0;
12301}
12302#endif
12303
12304/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012305 * Get a callback from "arg". It can be a Funcref or a function name.
12306 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012307 * "cb_name" is not allocated.
12308 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012309 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012310 callback_T
12311get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012312{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012313 callback_T res;
12314
12315 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012316 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12317 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012318 res.cb_partial = arg->vval.v_partial;
12319 ++res.cb_partial->pt_refcount;
12320 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012321 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012322 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012323 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012324 res.cb_partial = NULL;
12325 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12326 {
12327 // Note that we don't make a copy of the string.
12328 res.cb_name = arg->vval.v_string;
12329 func_ref(res.cb_name);
12330 }
12331 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12332 {
12333 res.cb_name = (char_u *)"";
12334 }
12335 else
12336 {
12337 emsg(_("E921: Invalid callback argument"));
12338 res.cb_name = NULL;
12339 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012340 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012341 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012342}
12343
12344/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012345 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012346 */
12347 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012348put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012349{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012350 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012351 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012352 tv->v_type = VAR_PARTIAL;
12353 tv->vval.v_partial = cb->cb_partial;
12354 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012355 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012356 else
12357 {
12358 tv->v_type = VAR_FUNC;
12359 tv->vval.v_string = vim_strsave(cb->cb_name);
12360 func_ref(cb->cb_name);
12361 }
12362}
12363
12364/*
12365 * Make a copy of "src" into "dest", allocating the function name if needed,
12366 * without incrementing the refcount.
12367 */
12368 void
12369set_callback(callback_T *dest, callback_T *src)
12370{
12371 if (src->cb_partial == NULL)
12372 {
12373 // just a function name, make a copy
12374 dest->cb_name = vim_strsave(src->cb_name);
12375 dest->cb_free_name = TRUE;
12376 }
12377 else
12378 {
12379 // cb_name is a pointer into cb_partial
12380 dest->cb_name = src->cb_name;
12381 dest->cb_free_name = FALSE;
12382 }
12383 dest->cb_partial = src->cb_partial;
12384}
12385
12386/*
12387 * Unref/free "callback" returned by get_callback() or set_callback().
12388 */
12389 void
12390free_callback(callback_T *callback)
12391{
12392 if (callback->cb_partial != NULL)
12393 {
12394 partial_unref(callback->cb_partial);
12395 callback->cb_partial = NULL;
12396 }
12397 else if (callback->cb_name != NULL)
12398 func_unref(callback->cb_name);
12399 if (callback->cb_free_name)
12400 {
12401 vim_free(callback->cb_name);
12402 callback->cb_free_name = FALSE;
12403 }
12404 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012405}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012406
12407#ifdef FEAT_TIMERS
12408/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012409 * "timer_info([timer])" function
12410 */
12411 static void
12412f_timer_info(typval_T *argvars, typval_T *rettv)
12413{
12414 timer_T *timer = NULL;
12415
12416 if (rettv_list_alloc(rettv) != OK)
12417 return;
12418 if (argvars[0].v_type != VAR_UNKNOWN)
12419 {
12420 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012421 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012422 else
12423 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012424 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012425 if (timer != NULL)
12426 add_timer_info(rettv, timer);
12427 }
12428 }
12429 else
12430 add_timer_info_all(rettv);
12431}
12432
12433/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012434 * "timer_pause(timer, paused)" function
12435 */
12436 static void
12437f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12438{
12439 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012440 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012441
12442 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012443 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012444 else
12445 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012446 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012447 if (timer != NULL)
12448 timer->tr_paused = paused;
12449 }
12450}
12451
12452/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012453 * "timer_start(time, callback [, options])" function
12454 */
12455 static void
12456f_timer_start(typval_T *argvars, typval_T *rettv)
12457{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012458 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012459 timer_T *timer;
12460 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012461 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012462 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012463
Bram Moolenaar75537a92016-09-05 22:45:28 +020012464 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012465 if (check_secure())
12466 return;
12467 if (argvars[2].v_type != VAR_UNKNOWN)
12468 {
12469 if (argvars[2].v_type != VAR_DICT
12470 || (dict = argvars[2].vval.v_dict) == NULL)
12471 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012472 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012473 return;
12474 }
12475 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012476 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012477 }
12478
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012479 callback = get_callback(&argvars[1]);
12480 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012481 return;
12482
12483 timer = create_timer(msec, repeat);
12484 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012485 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012486 else
12487 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012488 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012489 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012490 }
12491}
12492
12493/*
12494 * "timer_stop(timer)" function
12495 */
12496 static void
12497f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12498{
12499 timer_T *timer;
12500
12501 if (argvars[0].v_type != VAR_NUMBER)
12502 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012503 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012504 return;
12505 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012506 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012507 if (timer != NULL)
12508 stop_timer(timer);
12509}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012510
12511/*
12512 * "timer_stopall()" function
12513 */
12514 static void
12515f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12516{
12517 stop_all_timers();
12518}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012519#endif
12520
12521/*
12522 * "tolower(string)" function
12523 */
12524 static void
12525f_tolower(typval_T *argvars, typval_T *rettv)
12526{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012527 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012528 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012529}
12530
12531/*
12532 * "toupper(string)" function
12533 */
12534 static void
12535f_toupper(typval_T *argvars, typval_T *rettv)
12536{
12537 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012538 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012539}
12540
12541/*
12542 * "tr(string, fromstr, tostr)" function
12543 */
12544 static void
12545f_tr(typval_T *argvars, typval_T *rettv)
12546{
12547 char_u *in_str;
12548 char_u *fromstr;
12549 char_u *tostr;
12550 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012551 int inlen;
12552 int fromlen;
12553 int tolen;
12554 int idx;
12555 char_u *cpstr;
12556 int cplen;
12557 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558 char_u buf[NUMBUFLEN];
12559 char_u buf2[NUMBUFLEN];
12560 garray_T ga;
12561
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012562 in_str = tv_get_string(&argvars[0]);
12563 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12564 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012565
12566 /* Default return value: empty string. */
12567 rettv->v_type = VAR_STRING;
12568 rettv->vval.v_string = NULL;
12569 if (fromstr == NULL || tostr == NULL)
12570 return; /* type error; errmsg already given */
12571 ga_init2(&ga, (int)sizeof(char), 80);
12572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012573 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012574 /* not multi-byte: fromstr and tostr must be the same length */
12575 if (STRLEN(fromstr) != STRLEN(tostr))
12576 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012577error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012578 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012579 ga_clear(&ga);
12580 return;
12581 }
12582
12583 /* fromstr and tostr have to contain the same number of chars */
12584 while (*in_str != NUL)
12585 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012586 if (has_mbyte)
12587 {
12588 inlen = (*mb_ptr2len)(in_str);
12589 cpstr = in_str;
12590 cplen = inlen;
12591 idx = 0;
12592 for (p = fromstr; *p != NUL; p += fromlen)
12593 {
12594 fromlen = (*mb_ptr2len)(p);
12595 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12596 {
12597 for (p = tostr; *p != NUL; p += tolen)
12598 {
12599 tolen = (*mb_ptr2len)(p);
12600 if (idx-- == 0)
12601 {
12602 cplen = tolen;
12603 cpstr = p;
12604 break;
12605 }
12606 }
12607 if (*p == NUL) /* tostr is shorter than fromstr */
12608 goto error;
12609 break;
12610 }
12611 ++idx;
12612 }
12613
12614 if (first && cpstr == in_str)
12615 {
12616 /* Check that fromstr and tostr have the same number of
12617 * (multi-byte) characters. Done only once when a character
12618 * of in_str doesn't appear in fromstr. */
12619 first = FALSE;
12620 for (p = tostr; *p != NUL; p += tolen)
12621 {
12622 tolen = (*mb_ptr2len)(p);
12623 --idx;
12624 }
12625 if (idx != 0)
12626 goto error;
12627 }
12628
12629 (void)ga_grow(&ga, cplen);
12630 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12631 ga.ga_len += cplen;
12632
12633 in_str += inlen;
12634 }
12635 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012636 {
12637 /* When not using multi-byte chars we can do it faster. */
12638 p = vim_strchr(fromstr, *in_str);
12639 if (p != NULL)
12640 ga_append(&ga, tostr[p - fromstr]);
12641 else
12642 ga_append(&ga, *in_str);
12643 ++in_str;
12644 }
12645 }
12646
12647 /* add a terminating NUL */
12648 (void)ga_grow(&ga, 1);
12649 ga_append(&ga, NUL);
12650
12651 rettv->vval.v_string = ga.ga_data;
12652}
12653
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012654/*
12655 * "trim({expr})" function
12656 */
12657 static void
12658f_trim(typval_T *argvars, typval_T *rettv)
12659{
12660 char_u buf1[NUMBUFLEN];
12661 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012662 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012663 char_u *mask = NULL;
12664 char_u *tail;
12665 char_u *prev;
12666 char_u *p;
12667 int c1;
12668
12669 rettv->v_type = VAR_STRING;
12670 if (head == NULL)
12671 {
12672 rettv->vval.v_string = NULL;
12673 return;
12674 }
12675
12676 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012677 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012678
12679 while (*head != NUL)
12680 {
12681 c1 = PTR2CHAR(head);
12682 if (mask == NULL)
12683 {
12684 if (c1 > ' ' && c1 != 0xa0)
12685 break;
12686 }
12687 else
12688 {
12689 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12690 if (c1 == PTR2CHAR(p))
12691 break;
12692 if (*p == NUL)
12693 break;
12694 }
12695 MB_PTR_ADV(head);
12696 }
12697
12698 for (tail = head + STRLEN(head); tail > head; tail = prev)
12699 {
12700 prev = tail;
12701 MB_PTR_BACK(head, prev);
12702 c1 = PTR2CHAR(prev);
12703 if (mask == NULL)
12704 {
12705 if (c1 > ' ' && c1 != 0xa0)
12706 break;
12707 }
12708 else
12709 {
12710 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12711 if (c1 == PTR2CHAR(p))
12712 break;
12713 if (*p == NUL)
12714 break;
12715 }
12716 }
12717 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12718}
12719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012720#ifdef FEAT_FLOAT
12721/*
12722 * "trunc({float})" function
12723 */
12724 static void
12725f_trunc(typval_T *argvars, typval_T *rettv)
12726{
12727 float_T f = 0.0;
12728
12729 rettv->v_type = VAR_FLOAT;
12730 if (get_float_arg(argvars, &f) == OK)
12731 /* trunc() is not in C90, use floor() or ceil() instead. */
12732 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12733 else
12734 rettv->vval.v_float = 0.0;
12735}
12736#endif
12737
12738/*
12739 * "type(expr)" function
12740 */
12741 static void
12742f_type(typval_T *argvars, typval_T *rettv)
12743{
12744 int n = -1;
12745
12746 switch (argvars[0].v_type)
12747 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012748 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12749 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012750 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012751 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12752 case VAR_LIST: n = VAR_TYPE_LIST; break;
12753 case VAR_DICT: n = VAR_TYPE_DICT; break;
12754 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012755 case VAR_SPECIAL:
12756 if (argvars[0].vval.v_number == VVAL_FALSE
12757 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012758 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012759 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012760 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012762 case VAR_JOB: n = VAR_TYPE_JOB; break;
12763 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012764 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012765 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012766 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012767 n = -1;
12768 break;
12769 }
12770 rettv->vval.v_number = n;
12771}
12772
12773/*
12774 * "undofile(name)" function
12775 */
12776 static void
12777f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12778{
12779 rettv->v_type = VAR_STRING;
12780#ifdef FEAT_PERSISTENT_UNDO
12781 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012782 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012783
12784 if (*fname == NUL)
12785 {
12786 /* If there is no file name there will be no undo file. */
12787 rettv->vval.v_string = NULL;
12788 }
12789 else
12790 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012791 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012792
12793 if (ffname != NULL)
12794 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12795 vim_free(ffname);
12796 }
12797 }
12798#else
12799 rettv->vval.v_string = NULL;
12800#endif
12801}
12802
12803/*
12804 * "undotree()" function
12805 */
12806 static void
12807f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12808{
12809 if (rettv_dict_alloc(rettv) == OK)
12810 {
12811 dict_T *dict = rettv->vval.v_dict;
12812 list_T *list;
12813
Bram Moolenaare0be1672018-07-08 16:50:37 +020012814 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12815 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12816 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12817 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12818 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12819 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012820
12821 list = list_alloc();
12822 if (list != NULL)
12823 {
12824 u_eval_tree(curbuf->b_u_oldhead, list);
12825 dict_add_list(dict, "entries", list);
12826 }
12827 }
12828}
12829
12830/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012831 * "virtcol(string)" function
12832 */
12833 static void
12834f_virtcol(typval_T *argvars, typval_T *rettv)
12835{
12836 colnr_T vcol = 0;
12837 pos_T *fp;
12838 int fnum = curbuf->b_fnum;
12839
12840 fp = var2fpos(&argvars[0], FALSE, &fnum);
12841 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12842 && fnum == curbuf->b_fnum)
12843 {
12844 getvvcol(curwin, fp, NULL, NULL, &vcol);
12845 ++vcol;
12846 }
12847
12848 rettv->vval.v_number = vcol;
12849}
12850
12851/*
12852 * "visualmode()" function
12853 */
12854 static void
12855f_visualmode(typval_T *argvars, typval_T *rettv)
12856{
12857 char_u str[2];
12858
12859 rettv->v_type = VAR_STRING;
12860 str[0] = curbuf->b_visual_mode_eval;
12861 str[1] = NUL;
12862 rettv->vval.v_string = vim_strsave(str);
12863
12864 /* A non-zero number or non-empty string argument: reset mode. */
12865 if (non_zero_arg(&argvars[0]))
12866 curbuf->b_visual_mode_eval = NUL;
12867}
12868
12869/*
12870 * "wildmenumode()" function
12871 */
12872 static void
12873f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12874{
12875#ifdef FEAT_WILDMENU
12876 if (wild_menu_showing)
12877 rettv->vval.v_number = 1;
12878#endif
12879}
12880
12881/*
12882 * "winbufnr(nr)" function
12883 */
12884 static void
12885f_winbufnr(typval_T *argvars, typval_T *rettv)
12886{
12887 win_T *wp;
12888
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012889 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012890 if (wp == NULL)
12891 rettv->vval.v_number = -1;
12892 else
12893 rettv->vval.v_number = wp->w_buffer->b_fnum;
12894}
12895
12896/*
12897 * "wincol()" function
12898 */
12899 static void
12900f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12901{
12902 validate_cursor();
12903 rettv->vval.v_number = curwin->w_wcol + 1;
12904}
12905
12906/*
12907 * "winheight(nr)" function
12908 */
12909 static void
12910f_winheight(typval_T *argvars, typval_T *rettv)
12911{
12912 win_T *wp;
12913
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012914 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012915 if (wp == NULL)
12916 rettv->vval.v_number = -1;
12917 else
12918 rettv->vval.v_number = wp->w_height;
12919}
12920
12921/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012922 * "winlayout()" function
12923 */
12924 static void
12925f_winlayout(typval_T *argvars, typval_T *rettv)
12926{
12927 tabpage_T *tp;
12928
12929 if (rettv_list_alloc(rettv) != OK)
12930 return;
12931
12932 if (argvars[0].v_type == VAR_UNKNOWN)
12933 tp = curtab;
12934 else
12935 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012936 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012937 if (tp == NULL)
12938 return;
12939 }
12940
12941 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12942}
12943
12944/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012945 * "winline()" function
12946 */
12947 static void
12948f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12949{
12950 validate_cursor();
12951 rettv->vval.v_number = curwin->w_wrow + 1;
12952}
12953
12954/*
12955 * "winnr()" function
12956 */
12957 static void
12958f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12959{
12960 int nr = 1;
12961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012962 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012963 rettv->vval.v_number = nr;
12964}
12965
12966/*
12967 * "winrestcmd()" function
12968 */
12969 static void
12970f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12971{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012972 win_T *wp;
12973 int winnr = 1;
12974 garray_T ga;
12975 char_u buf[50];
12976
12977 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012978 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012979 {
12980 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12981 ga_concat(&ga, buf);
12982 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12983 ga_concat(&ga, buf);
12984 ++winnr;
12985 }
12986 ga_append(&ga, NUL);
12987
12988 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012989 rettv->v_type = VAR_STRING;
12990}
12991
12992/*
12993 * "winrestview()" function
12994 */
12995 static void
12996f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12997{
12998 dict_T *dict;
12999
13000 if (argvars[0].v_type != VAR_DICT
13001 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013002 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013003 else
13004 {
13005 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013006 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013007 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013008 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013009 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013010 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013011 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13012 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010013013 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013014 curwin->w_set_curswant = FALSE;
13015 }
13016
13017 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013018 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013019#ifdef FEAT_DIFF
13020 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013021 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013022#endif
13023 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013024 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013025 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013026 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013027
13028 check_cursor();
13029 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013030 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013031 changed_window_setting();
13032
13033 if (curwin->w_topline <= 0)
13034 curwin->w_topline = 1;
13035 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13036 curwin->w_topline = curbuf->b_ml.ml_line_count;
13037#ifdef FEAT_DIFF
13038 check_topfill(curwin, TRUE);
13039#endif
13040 }
13041}
13042
13043/*
13044 * "winsaveview()" function
13045 */
13046 static void
13047f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13048{
13049 dict_T *dict;
13050
13051 if (rettv_dict_alloc(rettv) == FAIL)
13052 return;
13053 dict = rettv->vval.v_dict;
13054
Bram Moolenaare0be1672018-07-08 16:50:37 +020013055 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13056 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020013057 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013059 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013060
Bram Moolenaare0be1672018-07-08 16:50:37 +020013061 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013062#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013063 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013064#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013065 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13066 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013067}
13068
13069/*
13070 * "winwidth(nr)" function
13071 */
13072 static void
13073f_winwidth(typval_T *argvars, typval_T *rettv)
13074{
13075 win_T *wp;
13076
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013077 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013078 if (wp == NULL)
13079 rettv->vval.v_number = -1;
13080 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013081 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013082}
13083
13084/*
13085 * "wordcount()" function
13086 */
13087 static void
13088f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13089{
13090 if (rettv_dict_alloc(rettv) == FAIL)
13091 return;
13092 cursor_pos_info(rettv->vval.v_dict);
13093}
13094
13095/*
13096 * "writefile()" function
13097 */
13098 static void
13099f_writefile(typval_T *argvars, typval_T *rettv)
13100{
13101 int binary = FALSE;
13102 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013103#ifdef HAVE_FSYNC
13104 int do_fsync = p_fs;
13105#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013106 char_u *fname;
13107 FILE *fd;
13108 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013109 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013110 list_T *list = NULL;
13111 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013113 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010013114 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013115 return;
13116
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013117 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013118 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013119 list = argvars[0].vval.v_list;
13120 if (list == NULL)
13121 return;
13122 for (li = list->lv_first; li != NULL; li = li->li_next)
13123 if (tv_get_string_chk(&li->li_tv) == NULL)
13124 return;
13125 }
13126 else if (argvars[0].v_type == VAR_BLOB)
13127 {
13128 blob = argvars[0].vval.v_blob;
13129 if (blob == NULL)
13130 return;
13131 }
13132 else
13133 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013134 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013135 return;
13136 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013137
13138 if (argvars[2].v_type != VAR_UNKNOWN)
13139 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013140 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013141
13142 if (arg2 == NULL)
13143 return;
13144 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013145 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013146 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013147 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013148#ifdef HAVE_FSYNC
13149 if (vim_strchr(arg2, 's') != NULL)
13150 do_fsync = TRUE;
13151 else if (vim_strchr(arg2, 'S') != NULL)
13152 do_fsync = FALSE;
13153#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013154 }
13155
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013156 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013157 if (fname == NULL)
13158 return;
13159
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013160 /* Always open the file in binary mode, library functions have a mind of
13161 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013162 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13163 append ? APPENDBIN : WRITEBIN)) == NULL)
13164 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013165 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013166 ret = -1;
13167 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013168 else if (blob)
13169 {
13170 if (write_blob(fd, blob) == FAIL)
13171 ret = -1;
13172#ifdef HAVE_FSYNC
13173 else if (do_fsync)
13174 // Ignore the error, the user wouldn't know what to do about it.
13175 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010013176 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013177#endif
13178 fclose(fd);
13179 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013180 else
13181 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013182 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013183 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013184#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013185 else if (do_fsync)
13186 /* Ignore the error, the user wouldn't know what to do about it.
13187 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010013188 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013189#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013190 fclose(fd);
13191 }
13192
13193 rettv->vval.v_number = ret;
13194}
13195
13196/*
13197 * "xor(expr, expr)" function
13198 */
13199 static void
13200f_xor(typval_T *argvars, typval_T *rettv)
13201{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013202 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13203 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013204}
13205
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013206#endif /* FEAT_EVAL */