blob: 890b86f7c112e47230e601d1f20a2953fa9b8199 [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 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200415typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200417 char *f_name; // function name
418 char f_min_argc; // minimal number of arguments
419 char f_max_argc; // maximal number of arguments
420 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200422 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200423} funcentry_T;
424
425static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426{
427#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200428 {"abs", 1, 1, 0, f_abs},
429 {"acos", 1, 1, 0, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200431 {"add", 2, 2, 0, f_add},
432 {"and", 2, 2, 0, f_and},
433 {"append", 2, 2, 0, f_append},
434 {"appendbufline", 3, 3, 0, f_appendbufline},
435 {"argc", 0, 1, 0, f_argc},
436 {"argidx", 0, 0, 0, f_argidx},
437 {"arglistid", 0, 2, 0, f_arglistid},
438 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200440 {"asin", 1, 1, 0, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200441#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200442 {"assert_beeps", 1, 2, 0, f_assert_beeps},
443 {"assert_equal", 2, 3, 0, f_assert_equal},
444 {"assert_equalfile", 2, 2, 0, f_assert_equalfile},
445 {"assert_exception", 1, 2, 0, f_assert_exception},
446 {"assert_fails", 1, 3, 0, f_assert_fails},
447 {"assert_false", 1, 2, 0, f_assert_false},
448 {"assert_inrange", 3, 4, 0, f_assert_inrange},
449 {"assert_match", 2, 3, 0, f_assert_match},
450 {"assert_notequal", 2, 3, 0, f_assert_notequal},
451 {"assert_notmatch", 2, 3, 0, f_assert_notmatch},
452 {"assert_report", 1, 1, 0, f_assert_report},
453 {"assert_true", 1, 2, 0, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200454#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200455 {"atan", 1, 1, 0, f_atan},
456 {"atan2", 2, 2, 0, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100458#ifdef FEAT_BEVAL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200459 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
460 {"balloon_show", 1, 1, 0, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100461# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200462 {"balloon_split", 1, 1, 0, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100463# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100464#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200465 {"browse", 4, 4, 0, f_browse},
466 {"browsedir", 2, 2, 0, f_browsedir},
467 {"bufadd", 1, 1, 0, f_bufadd},
468 {"bufexists", 1, 1, 0, f_bufexists},
469 {"buffer_exists", 1, 1, 0, f_bufexists}, // obsolete
470 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
471 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
472 {"buflisted", 1, 1, 0, f_buflisted},
473 {"bufload", 1, 1, 0, f_bufload},
474 {"bufloaded", 1, 1, 0, f_bufloaded},
475 {"bufname", 1, 1, 0, f_bufname},
476 {"bufnr", 1, 2, 0, f_bufnr},
477 {"bufwinid", 1, 1, 0, f_bufwinid},
478 {"bufwinnr", 1, 1, 0, f_bufwinnr},
479 {"byte2line", 1, 1, 0, f_byte2line},
480 {"byteidx", 2, 2, 0, f_byteidx},
481 {"byteidxcomp", 2, 2, 0, f_byteidxcomp},
482 {"call", 2, 3, 0, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200483#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200484 {"ceil", 1, 1, 0, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200485#endif
486#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200487 {"ch_canread", 1, 1, 0, f_ch_canread},
488 {"ch_close", 1, 1, 0, f_ch_close},
489 {"ch_close_in", 1, 1, 0, f_ch_close_in},
490 {"ch_evalexpr", 2, 3, 0, f_ch_evalexpr},
491 {"ch_evalraw", 2, 3, 0, f_ch_evalraw},
492 {"ch_getbufnr", 2, 2, 0, f_ch_getbufnr},
493 {"ch_getjob", 1, 1, 0, f_ch_getjob},
494 {"ch_info", 1, 1, 0, f_ch_info},
495 {"ch_log", 1, 2, 0, f_ch_log},
496 {"ch_logfile", 1, 2, 0, f_ch_logfile},
497 {"ch_open", 1, 2, 0, f_ch_open},
498 {"ch_read", 1, 2, 0, f_ch_read},
499 {"ch_readblob", 1, 2, 0, f_ch_readblob},
500 {"ch_readraw", 1, 2, 0, f_ch_readraw},
501 {"ch_sendexpr", 2, 3, 0, f_ch_sendexpr},
502 {"ch_sendraw", 2, 3, 0, f_ch_sendraw},
503 {"ch_setoptions", 2, 2, 0, f_ch_setoptions},
504 {"ch_status", 1, 2, 0, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200505#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200506 {"changenr", 0, 0, 0, f_changenr},
507 {"char2nr", 1, 2, 0, f_char2nr},
508 {"chdir", 1, 1, 0, f_chdir},
509 {"cindent", 1, 1, 0, f_cindent},
510 {"clearmatches", 0, 1, 0, f_clearmatches},
511 {"col", 1, 1, 0, f_col},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200512#if defined(FEAT_INS_EXPAND)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200513 {"complete", 2, 2, 0, f_complete},
514 {"complete_add", 1, 1, 0, f_complete_add},
515 {"complete_check", 0, 0, 0, f_complete_check},
516 {"complete_info", 0, 1, 0, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200518 {"confirm", 1, 4, 0, f_confirm},
519 {"copy", 1, 1, 0, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200521 {"cos", 1, 1, 0, f_cos},
522 {"cosh", 1, 1, 0, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200523#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200524 {"count", 2, 4, 0, f_count},
525 {"cscope_connection",0,3, 0, f_cscope_connection},
526 {"cursor", 1, 3, 0, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100527#ifdef MSWIN
Bram Moolenaar25e42232019-08-04 15:04:10 +0200528 {"debugbreak", 1, 1, 0, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200529#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200530 {"deepcopy", 1, 2, 0, f_deepcopy},
531 {"delete", 1, 2, 0, f_delete},
532 {"deletebufline", 2, 3, 0, f_deletebufline},
533 {"did_filetype", 0, 0, 0, f_did_filetype},
534 {"diff_filler", 1, 1, 0, f_diff_filler},
535 {"diff_hlID", 2, 2, 0, f_diff_hlID},
536 {"empty", 1, 1, 0, f_empty},
537 {"environ", 0, 0, 0, f_environ},
538 {"escape", 2, 2, 0, f_escape},
539 {"eval", 1, 1, 0, f_eval},
540 {"eventhandler", 0, 0, 0, f_eventhandler},
541 {"executable", 1, 1, 0, f_executable},
542 {"execute", 1, 2, 0, f_execute},
543 {"exepath", 1, 1, 0, f_exepath},
544 {"exists", 1, 1, 0, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200545#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200546 {"exp", 1, 1, 0, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200548 {"expand", 1, 3, 0, f_expand},
549 {"expandcmd", 1, 1, 0, f_expandcmd},
550 {"extend", 2, 3, 0, f_extend},
551 {"feedkeys", 1, 2, 0, f_feedkeys},
552 {"file_readable", 1, 1, 0, f_filereadable}, // obsolete
553 {"filereadable", 1, 1, 0, f_filereadable},
554 {"filewritable", 1, 1, 0, f_filewritable},
555 {"filter", 2, 2, 0, f_filter},
556 {"finddir", 1, 3, 0, f_finddir},
557 {"findfile", 1, 3, 0, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200559 {"float2nr", 1, 1, 0, f_float2nr},
560 {"floor", 1, 1, 0, f_floor},
561 {"fmod", 2, 2, 0, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200562#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200563 {"fnameescape", 1, 1, 0, f_fnameescape},
564 {"fnamemodify", 2, 2, 0, f_fnamemodify},
565 {"foldclosed", 1, 1, 0, f_foldclosed},
566 {"foldclosedend", 1, 1, 0, f_foldclosedend},
567 {"foldlevel", 1, 1, 0, f_foldlevel},
568 {"foldtext", 0, 0, 0, f_foldtext},
569 {"foldtextresult", 1, 1, 0, f_foldtextresult},
570 {"foreground", 0, 0, 0, f_foreground},
571 {"funcref", 1, 3, 0, f_funcref},
572 {"function", 1, 3, 0, f_function},
573 {"garbagecollect", 0, 1, 0, f_garbagecollect},
574 {"get", 2, 3, 0, f_get},
575 {"getbufinfo", 0, 1, 0, f_getbufinfo},
576 {"getbufline", 2, 3, 0, f_getbufline},
577 {"getbufvar", 2, 3, 0, f_getbufvar},
578 {"getchangelist", 1, 1, 0, f_getchangelist},
579 {"getchar", 0, 1, 0, f_getchar},
580 {"getcharmod", 0, 0, 0, f_getcharmod},
581 {"getcharsearch", 0, 0, 0, f_getcharsearch},
582 {"getcmdline", 0, 0, 0, f_getcmdline},
583 {"getcmdpos", 0, 0, 0, f_getcmdpos},
584 {"getcmdtype", 0, 0, 0, f_getcmdtype},
585 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586#if defined(FEAT_CMDL_COMPL)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200587 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200589 {"getcurpos", 0, 0, 0, f_getcurpos},
590 {"getcwd", 0, 2, 0, f_getcwd},
591 {"getenv", 1, 1, 0, f_getenv},
592 {"getfontname", 0, 1, 0, f_getfontname},
593 {"getfperm", 1, 1, 0, f_getfperm},
594 {"getfsize", 1, 1, 0, f_getfsize},
595 {"getftime", 1, 1, 0, f_getftime},
596 {"getftype", 1, 1, 0, f_getftype},
597 {"getjumplist", 0, 2, 0, f_getjumplist},
598 {"getline", 1, 2, 0, f_getline},
599 {"getloclist", 1, 2, 0, f_getloclist},
600 {"getmatches", 0, 1, 0, f_getmatches},
601 {"getpid", 0, 0, 0, f_getpid},
602 {"getpos", 1, 1, 0, f_getpos},
603 {"getqflist", 0, 1, 0, f_getqflist},
604 {"getreg", 0, 3, 0, f_getreg},
605 {"getregtype", 0, 1, 0, f_getregtype},
606 {"gettabinfo", 0, 1, 0, f_gettabinfo},
607 {"gettabvar", 2, 3, 0, f_gettabvar},
608 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
609 {"gettagstack", 0, 1, 0, f_gettagstack},
610 {"getwininfo", 0, 1, 0, f_getwininfo},
611 {"getwinpos", 0, 1, 0, f_getwinpos},
612 {"getwinposx", 0, 0, 0, f_getwinposx},
613 {"getwinposy", 0, 0, 0, f_getwinposy},
614 {"getwinvar", 2, 3, 0, f_getwinvar},
615 {"glob", 1, 4, 0, f_glob},
616 {"glob2regpat", 1, 1, 0, f_glob2regpat},
617 {"globpath", 2, 5, 0, f_globpath},
618 {"has", 1, 1, 0, f_has},
619 {"has_key", 2, 2, 0, f_has_key},
620 {"haslocaldir", 0, 2, 0, f_haslocaldir},
621 {"hasmapto", 1, 3, 0, f_hasmapto},
622 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
623 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
624 {"histadd", 2, 2, 0, f_histadd},
625 {"histdel", 1, 2, 0, f_histdel},
626 {"histget", 1, 2, 0, f_histget},
627 {"histnr", 1, 1, 0, f_histnr},
628 {"hlID", 1, 1, 0, f_hlID},
629 {"hlexists", 1, 1, 0, f_hlexists},
630 {"hostname", 0, 0, 0, f_hostname},
631 {"iconv", 3, 3, 0, f_iconv},
632 {"indent", 1, 1, 0, f_indent},
633 {"index", 2, 4, 0, f_index},
634 {"input", 1, 3, 0, f_input},
635 {"inputdialog", 1, 3, 0, f_inputdialog},
636 {"inputlist", 1, 1, 0, f_inputlist},
637 {"inputrestore", 0, 0, 0, f_inputrestore},
638 {"inputsave", 0, 0, 0, f_inputsave},
639 {"inputsecret", 1, 2, 0, f_inputsecret},
640 {"insert", 2, 3, 0, f_insert},
641 {"invert", 1, 1, 0, f_invert},
642 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200643#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200644 {"isinf", 1, 1, 0, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200645#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200646 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200647#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200648 {"isnan", 1, 1, 0, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200650 {"items", 1, 1, 0, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200652 {"job_getchannel", 1, 1, 0, f_job_getchannel},
653 {"job_info", 0, 1, 0, f_job_info},
654 {"job_setoptions", 2, 2, 0, f_job_setoptions},
655 {"job_start", 1, 2, 0, f_job_start},
656 {"job_status", 1, 1, 0, f_job_status},
657 {"job_stop", 1, 2, 0, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200659 {"join", 1, 2, 0, f_join},
660 {"js_decode", 1, 1, 0, f_js_decode},
661 {"js_encode", 1, 1, 0, f_js_encode},
662 {"json_decode", 1, 1, 0, f_json_decode},
663 {"json_encode", 1, 1, 0, f_json_encode},
664 {"keys", 1, 1, 0, f_keys},
665 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
666 {"len", 1, 1, 0, f_len},
667 {"libcall", 3, 3, 0, f_libcall},
668 {"libcallnr", 3, 3, 0, f_libcallnr},
669 {"line", 1, 1, 0, f_line},
670 {"line2byte", 1, 1, 0, f_line2byte},
671 {"lispindent", 1, 1, 0, f_lispindent},
672 {"list2str", 1, 2, 0, f_list2str},
673 {"listener_add", 1, 2, 0, f_listener_add},
674 {"listener_flush", 0, 1, 0, f_listener_flush},
675 {"listener_remove", 1, 1, 0, f_listener_remove},
676 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200677#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200678 {"log", 1, 1, 0, f_log},
679 {"log10", 1, 1, 0, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680#endif
681#ifdef FEAT_LUA
Bram Moolenaar25e42232019-08-04 15:04:10 +0200682 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200683#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200684 {"map", 2, 2, 0, f_map},
685 {"maparg", 1, 4, 0, f_maparg},
686 {"mapcheck", 1, 3, 0, f_mapcheck},
687 {"match", 2, 4, 0, f_match},
688 {"matchadd", 2, 5, 0, f_matchadd},
689 {"matchaddpos", 2, 5, 0, f_matchaddpos},
690 {"matcharg", 1, 1, 0, f_matcharg},
691 {"matchdelete", 1, 2, 0, f_matchdelete},
692 {"matchend", 2, 4, 0, f_matchend},
693 {"matchlist", 2, 4, 0, f_matchlist},
694 {"matchstr", 2, 4, 0, f_matchstr},
695 {"matchstrpos", 2, 4, 0, f_matchstrpos},
696 {"max", 1, 1, 0, f_max},
697 {"min", 1, 1, 0, f_min},
698 {"mkdir", 1, 3, 0, f_mkdir},
699 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200700#ifdef FEAT_MZSCHEME
Bram Moolenaar25e42232019-08-04 15:04:10 +0200701 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200702#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200703 {"nextnonblank", 1, 1, 0, f_nextnonblank},
704 {"nr2char", 1, 2, 0, f_nr2char},
705 {"or", 2, 2, 0, f_or},
706 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200707#ifdef FEAT_PERL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200708 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200710#ifdef FEAT_TEXT_PROP
Bram Moolenaar25e42232019-08-04 15:04:10 +0200711 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
712 {"popup_beval", 2, 2, 0, f_popup_beval},
713 {"popup_clear", 0, 0, 0, f_popup_clear},
714 {"popup_close", 1, 2, 0, f_popup_close},
715 {"popup_create", 2, 2, 0, f_popup_create},
716 {"popup_dialog", 2, 2, 0, f_popup_dialog},
717 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
718 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
719 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
720 {"popup_getpos", 1, 1, 0, f_popup_getpos},
721 {"popup_getpreview", 0, 0, 0, f_popup_getpreview},
722 {"popup_hide", 1, 1, 0, f_popup_hide},
723 {"popup_locate", 2, 2, 0, f_popup_locate},
724 {"popup_menu", 2, 2, 0, f_popup_menu},
725 {"popup_move", 2, 2, 0, f_popup_move},
726 {"popup_notification", 2, 2, 0, f_popup_notification},
727 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
728 {"popup_settext", 2, 2, 0, f_popup_settext},
729 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200730#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200731#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200732 {"pow", 2, 2, 0, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200734 {"prevnonblank", 1, 1, 0, f_prevnonblank},
735 {"printf", 1, 19, 0, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200736#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200737 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
738 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
739 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200740#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100741#ifdef FEAT_TEXT_PROP
Bram Moolenaar25e42232019-08-04 15:04:10 +0200742 {"prop_add", 3, 3, 0, f_prop_add},
743 {"prop_clear", 1, 3, 0, f_prop_clear},
744 {"prop_list", 1, 2, 0, f_prop_list},
745 {"prop_remove", 1, 3, 0, f_prop_remove},
746 {"prop_type_add", 2, 2, 0, f_prop_type_add},
747 {"prop_type_change", 2, 2, 0, f_prop_type_change},
748 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
749 {"prop_type_get", 1, 2, 0, f_prop_type_get},
750 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100751#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200752 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200753#ifdef FEAT_PYTHON3
Bram Moolenaar25e42232019-08-04 15:04:10 +0200754 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755#endif
756#ifdef FEAT_PYTHON
Bram Moolenaar25e42232019-08-04 15:04:10 +0200757 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100759#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200760 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100761#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200762 {"range", 1, 3, 0, f_range},
763 {"readdir", 1, 2, 0, f_readdir},
764 {"readfile", 1, 3, 0, f_readfile},
765 {"reg_executing", 0, 0, 0, f_reg_executing},
766 {"reg_recording", 0, 0, 0, f_reg_recording},
767 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200769 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200770#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200771 {"reltimestr", 1, 1, 0, f_reltimestr},
772 {"remote_expr", 2, 4, 0, f_remote_expr},
773 {"remote_foreground", 1, 1, 0, f_remote_foreground},
774 {"remote_peek", 1, 2, 0, f_remote_peek},
775 {"remote_read", 1, 2, 0, f_remote_read},
776 {"remote_send", 2, 3, 0, f_remote_send},
777 {"remote_startserver", 1, 1, 0, f_remote_startserver},
778 {"remove", 2, 3, 0, f_remove},
779 {"rename", 2, 2, 0, f_rename},
780 {"repeat", 2, 2, 0, f_repeat},
781 {"resolve", 1, 1, 0, f_resolve},
782 {"reverse", 1, 1, 0, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200784 {"round", 1, 1, 0, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200785#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100786#ifdef FEAT_RUBY
Bram Moolenaar25e42232019-08-04 15:04:10 +0200787 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100788#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200789 {"screenattr", 2, 2, 0, f_screenattr},
790 {"screenchar", 2, 2, 0, f_screenchar},
791 {"screenchars", 2, 2, 0, f_screenchars},
792 {"screencol", 0, 0, 0, f_screencol},
793 {"screenpos", 3, 3, 0, f_screenpos},
794 {"screenrow", 0, 0, 0, f_screenrow},
795 {"screenstring", 2, 2, 0, f_screenstring},
796 {"search", 1, 4, 0, f_search},
797 {"searchdecl", 1, 3, 0, f_searchdecl},
798 {"searchpair", 3, 7, 0, f_searchpair},
799 {"searchpairpos", 3, 7, 0, f_searchpairpos},
800 {"searchpos", 1, 4, 0, f_searchpos},
801 {"server2client", 2, 2, 0, f_server2client},
802 {"serverlist", 0, 0, 0, f_serverlist},
803 {"setbufline", 3, 3, 0, f_setbufline},
804 {"setbufvar", 3, 3, 0, f_setbufvar},
805 {"setcharsearch", 1, 1, 0, f_setcharsearch},
806 {"setcmdpos", 1, 1, 0, f_setcmdpos},
807 {"setenv", 2, 2, 0, f_setenv},
808 {"setfperm", 2, 2, 0, f_setfperm},
809 {"setline", 2, 2, 0, f_setline},
810 {"setloclist", 2, 4, 0, f_setloclist},
811 {"setmatches", 1, 2, 0, f_setmatches},
812 {"setpos", 2, 2, 0, f_setpos},
813 {"setqflist", 1, 3, 0, f_setqflist},
814 {"setreg", 2, 3, 0, f_setreg},
815 {"settabvar", 3, 3, 0, f_settabvar},
816 {"settabwinvar", 4, 4, 0, f_settabwinvar},
817 {"settagstack", 2, 3, 0, f_settagstack},
818 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819#ifdef FEAT_CRYPT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200820 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200822 {"shellescape", 1, 2, 0, f_shellescape},
823 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100824#ifdef FEAT_SIGNS
Bram Moolenaar25e42232019-08-04 15:04:10 +0200825 {"sign_define", 1, 2, 0, f_sign_define},
826 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
827 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
828 {"sign_jump", 3, 3, 0, f_sign_jump},
829 {"sign_place", 4, 5, 0, f_sign_place},
830 {"sign_placelist", 1, 1, 0, f_sign_placelist},
831 {"sign_undefine", 0, 1, 0, f_sign_undefine},
832 {"sign_unplace", 1, 2, 0, f_sign_unplace},
833 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100834#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200835 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200837 {"sin", 1, 1, 0, f_sin},
838 {"sinh", 1, 1, 0, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200840 {"sort", 1, 3, 0, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200841#ifdef FEAT_SOUND
Bram Moolenaar25e42232019-08-04 15:04:10 +0200842 {"sound_clear", 0, 0, 0, f_sound_clear},
843 {"sound_playevent", 1, 2, 0, f_sound_playevent},
844 {"sound_playfile", 1, 2, 0, f_sound_playfile},
845 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200846#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200847 {"soundfold", 1, 1, 0, f_soundfold},
848 {"spellbadword", 0, 1, 0, f_spellbadword},
849 {"spellsuggest", 1, 3, 0, f_spellsuggest},
850 {"split", 1, 3, 0, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200852 {"sqrt", 1, 1, 0, f_sqrt},
853 {"str2float", 1, 1, 0, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200854#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200855 {"str2list", 1, 2, 0, f_str2list},
856 {"str2nr", 1, 2, 0, f_str2nr},
857 {"strcharpart", 2, 3, 0, f_strcharpart},
858 {"strchars", 1, 2, 0, f_strchars},
859 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860#ifdef HAVE_STRFTIME
Bram Moolenaar25e42232019-08-04 15:04:10 +0200861 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200862#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200863 {"strgetchar", 2, 2, 0, f_strgetchar},
864 {"stridx", 2, 3, 0, f_stridx},
865 {"string", 1, 1, 0, f_string},
866 {"strlen", 1, 1, 0, f_strlen},
867 {"strpart", 2, 3, 0, f_strpart},
868 {"strridx", 2, 3, 0, f_strridx},
869 {"strtrans", 1, 1, 0, f_strtrans},
870 {"strwidth", 1, 1, 0, f_strwidth},
871 {"submatch", 1, 2, 0, f_submatch},
872 {"substitute", 4, 4, 0, f_substitute},
873 {"swapinfo", 1, 1, 0, f_swapinfo},
874 {"swapname", 1, 1, 0, f_swapname},
875 {"synID", 3, 3, 0, f_synID},
876 {"synIDattr", 2, 3, 0, f_synIDattr},
877 {"synIDtrans", 1, 1, 0, f_synIDtrans},
878 {"synconcealed", 2, 2, 0, f_synconcealed},
879 {"synstack", 2, 2, 0, f_synstack},
880 {"system", 1, 2, 0, f_system},
881 {"systemlist", 1, 2, 0, f_systemlist},
882 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
883 {"tabpagenr", 0, 1, 0, f_tabpagenr},
884 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
885 {"tagfiles", 0, 0, 0, f_tagfiles},
886 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200888 {"tan", 1, 1, 0, f_tan},
889 {"tanh", 1, 1, 0, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200891 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200892#ifdef FEAT_TERMINAL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200893 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
894 {"term_dumpload", 1, 2, 0, f_term_dumpload},
895 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
896 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200897# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200898 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200899# endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200900 {"term_getattr", 2, 2, 0, f_term_getattr},
901 {"term_getcursor", 1, 1, 0, f_term_getcursor},
902 {"term_getjob", 1, 1, 0, f_term_getjob},
903 {"term_getline", 2, 2, 0, f_term_getline},
904 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
905 {"term_getsize", 1, 1, 0, f_term_getsize},
906 {"term_getstatus", 1, 1, 0, f_term_getstatus},
907 {"term_gettitle", 1, 1, 0, f_term_gettitle},
908 {"term_gettty", 1, 2, 0, f_term_gettty},
909 {"term_list", 0, 0, 0, f_term_list},
910 {"term_scrape", 2, 2, 0, f_term_scrape},
911 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200912# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200913 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200914# endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200915 {"term_setkill", 2, 2, 0, f_term_setkill},
916 {"term_setrestore", 2, 2, 0, f_term_setrestore},
917 {"term_setsize", 3, 3, 0, f_term_setsize},
918 {"term_start", 1, 2, 0, f_term_start},
919 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200920#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200921 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
922 {"test_autochdir", 0, 0, 0, f_test_autochdir},
923 {"test_feedinput", 1, 1, 0, f_test_feedinput},
924 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
925 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
926 {"test_getvalue", 1, 1, 0, f_test_getvalue},
927 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
928 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200930 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200932 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200933#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar25e42232019-08-04 15:04:10 +0200934 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200936 {"test_null_list", 0, 0, 0, f_test_null_list},
937 {"test_null_partial", 0, 0, 0, f_test_null_partial},
938 {"test_null_string", 0, 0, 0, f_test_null_string},
939 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
940 {"test_override", 2, 2, 0, f_test_override},
941 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200942#ifdef FEAT_GUI
Bram Moolenaar25e42232019-08-04 15:04:10 +0200943 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200944#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200945#ifdef FEAT_MOUSE
Bram Moolenaar25e42232019-08-04 15:04:10 +0200946 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200947#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200948 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949#ifdef FEAT_TIMERS
Bram Moolenaar25e42232019-08-04 15:04:10 +0200950 {"timer_info", 0, 1, 0, f_timer_info},
951 {"timer_pause", 2, 2, 0, f_timer_pause},
952 {"timer_start", 2, 3, 0, f_timer_start},
953 {"timer_stop", 1, 1, 0, f_timer_stop},
954 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200956 {"tolower", 1, 1, 0, f_tolower},
957 {"toupper", 1, 1, 0, f_toupper},
958 {"tr", 3, 3, 0, f_tr},
959 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200960#ifdef FEAT_FLOAT
Bram Moolenaar25e42232019-08-04 15:04:10 +0200961 {"trunc", 1, 1, 0, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962#endif
Bram Moolenaar25e42232019-08-04 15:04:10 +0200963 {"type", 1, 1, 0, f_type},
964 {"undofile", 1, 1, 0, f_undofile},
965 {"undotree", 0, 0, 0, f_undotree},
966 {"uniq", 1, 3, 0, f_uniq},
967 {"values", 1, 1, 0, f_values},
968 {"virtcol", 1, 1, 0, f_virtcol},
969 {"visualmode", 0, 1, 0, f_visualmode},
970 {"wildmenumode", 0, 0, 0, f_wildmenumode},
971 {"win_execute", 2, 3, 0, f_win_execute},
972 {"win_findbuf", 1, 1, 0, f_win_findbuf},
973 {"win_getid", 0, 2, 0, f_win_getid},
974 {"win_gotoid", 1, 1, 0, f_win_gotoid},
975 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
976 {"win_id2win", 1, 1, 0, f_win_id2win},
977 {"win_screenpos", 1, 1, 0, f_win_screenpos},
978 {"winbufnr", 1, 1, 0, f_winbufnr},
979 {"wincol", 0, 0, 0, f_wincol},
980 {"winheight", 1, 1, 0, f_winheight},
981 {"winlayout", 0, 1, 0, f_winlayout},
982 {"winline", 0, 0, 0, f_winline},
983 {"winnr", 0, 1, 0, f_winnr},
984 {"winrestcmd", 0, 0, 0, f_winrestcmd},
985 {"winrestview", 1, 1, 0, f_winrestview},
986 {"winsaveview", 0, 0, 0, f_winsaveview},
987 {"winwidth", 1, 1, 0, f_winwidth},
988 {"wordcount", 0, 0, 0, f_wordcount},
989 {"writefile", 2, 3, 0, f_writefile},
990 {"xor", 2, 2, 0, f_xor},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200991};
992
Bram Moolenaar25e42232019-08-04 15:04:10 +0200993// values for f_argtype
994#define FEARG_LAST 1 // base is the last argument
995#define FEARG_2 2 // base is the second argument
996
Bram Moolenaarac92e252019-08-03 21:58:38 +0200997/*
Bram Moolenaara74e4942019-08-04 17:35:53 +0200998 * Methods that call the internal function with the base as one of the
999 * arguments.
Bram Moolenaarac92e252019-08-03 21:58:38 +02001000 */
1001static funcentry_T base_methods[] =
1002{
Bram Moolenaar25e42232019-08-04 15:04:10 +02001003 {"add", 1, 1, 0, f_add},
1004 {"append", 1, 1, FEARG_LAST, f_append},
1005 {"appendbufline", 2, 2, FEARG_LAST, f_appendbufline},
1006 {"assert_equal", 1, 2, FEARG_2, f_assert_equal},
1007 {"assert_notequal", 1, 2, FEARG_2, f_assert_notequal},
1008 {"copy", 0, 0, 0, f_copy},
1009 {"count", 1, 3, 0, f_count},
1010 {"empty", 0, 0, 0, f_empty},
1011 {"eval", 0, 0, 0, f_eval},
1012 {"extend", 1, 2, 0, f_extend},
1013 {"filter", 1, 1, 0, f_filter},
1014 {"get", 1, 2, 0, f_get},
Bram Moolenaara74e4942019-08-04 17:35:53 +02001015 {"has_key", 1, 1, 0, f_has_key},
Bram Moolenaar25e42232019-08-04 15:04:10 +02001016 {"index", 1, 3, 0, f_index},
1017 {"insert", 1, 2, 0, f_insert},
1018 {"items", 0, 0, 0, f_items},
1019 {"join", 0, 1, 0, f_join},
1020 {"keys", 0, 0, 0, f_keys},
1021 {"len", 0, 0, 0, f_len},
1022 {"map", 1, 1, 0, f_map},
1023 {"max", 0, 0, 0, f_max},
1024 {"min", 0, 0, 0, f_min},
1025 {"remove", 1, 2, 0, f_remove},
1026 {"repeat", 1, 1, 0, f_repeat},
1027 {"reverse", 0, 0, 0, f_reverse},
1028 {"sort", 0, 2, 0, f_sort},
Bram Moolenaara74e4942019-08-04 17:35:53 +02001029 {"split", 0, 2, 0, f_split},
1030 {"str2list", 0, 1, 0, f_str2list},
Bram Moolenaar25e42232019-08-04 15:04:10 +02001031 {"string", 0, 0, 0, f_string},
Bram Moolenaara74e4942019-08-04 17:35:53 +02001032 {"strlen", 0, 0, 0, f_strlen},
1033 {"strtrans", 0, 0, 0, f_strtrans},
1034 {"strwidth", 0, 0, 0, f_strwidth},
1035 {"substitute", 3, 3, 0, f_substitute},
1036 {"synIDattr", 1, 2, 0, f_synIDattr},
1037 {"synIDtrans", 0, 0, 0, f_synIDtrans},
1038 {"system", 0, 1, 0, f_system},
1039 {"systemlist", 0, 2, 0, f_systemlist},
Bram Moolenaar25e42232019-08-04 15:04:10 +02001040 {"type", 0, 0, 0, f_type},
1041 {"uniq", 0, 2, 0, f_uniq},
1042 {"values", 0, 0, 0, f_values},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001043};
1044
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001045#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1046
1047/*
1048 * Function given to ExpandGeneric() to obtain the list of internal
1049 * or user defined function names.
1050 */
1051 char_u *
1052get_function_name(expand_T *xp, int idx)
1053{
1054 static int intidx = -1;
1055 char_u *name;
1056
1057 if (idx == 0)
1058 intidx = -1;
1059 if (intidx < 0)
1060 {
1061 name = get_user_func_name(xp, idx);
1062 if (name != NULL)
1063 return name;
1064 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001065 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001066 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001067 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001068 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001069 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070 STRCAT(IObuff, ")");
1071 return IObuff;
1072 }
1073
1074 return NULL;
1075}
1076
1077/*
1078 * Function given to ExpandGeneric() to obtain the list of internal or
1079 * user defined variable or function names.
1080 */
1081 char_u *
1082get_expr_name(expand_T *xp, int idx)
1083{
1084 static int intidx = -1;
1085 char_u *name;
1086
1087 if (idx == 0)
1088 intidx = -1;
1089 if (intidx < 0)
1090 {
1091 name = get_function_name(xp, idx);
1092 if (name != NULL)
1093 return name;
1094 }
1095 return get_user_var_name(xp, ++intidx);
1096}
1097
1098#endif /* FEAT_CMDL_COMPL */
1099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001100/*
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101 * Find internal function in table "functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001102 * Return index, or -1 if not found
1103 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001104 static int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001105find_internal_func(
Bram Moolenaarac92e252019-08-03 21:58:38 +02001106 char_u *name, // name of the function
1107 funcentry_T *functions) // functions table to use
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001108{
1109 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001110 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001111 int cmp;
1112 int x;
1113
Bram Moolenaarac92e252019-08-03 21:58:38 +02001114 if (functions == global_functions)
1115 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
1116 else
1117 last = (int)(sizeof(base_methods) / sizeof(funcentry_T)) - 1;
1118
1119 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001120 while (first <= last)
1121 {
1122 x = first + ((unsigned)(last - first) >> 1);
1123 cmp = STRCMP(name, functions[x].f_name);
1124 if (cmp < 0)
1125 last = x - 1;
1126 else if (cmp > 0)
1127 first = x + 1;
1128 else
1129 return x;
1130 }
1131 return -1;
1132}
1133
1134 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001135has_internal_func(char_u *name)
1136{
1137 return find_internal_func(name, global_functions) >= 0;
1138}
1139
1140 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001141call_internal_func(
1142 char_u *name,
1143 int argcount,
1144 typval_T *argvars,
1145 typval_T *rettv)
1146{
1147 int i;
1148
Bram Moolenaarac92e252019-08-03 21:58:38 +02001149 i = find_internal_func(name, global_functions);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001150 if (i < 0)
1151 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001152 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001153 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001154 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001155 return ERROR_TOOMANY;
1156 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001157 global_functions[i].f_func(argvars, rettv);
1158 return ERROR_NONE;
1159}
1160
1161/*
1162 * Invoke a method for base->method().
1163 */
1164 int
1165call_internal_method(
1166 char_u *name,
1167 int argcount,
1168 typval_T *argvars,
1169 typval_T *rettv,
1170 typval_T *basetv)
1171{
1172 int i;
1173 int fi;
1174 typval_T argv[MAX_FUNC_ARGS + 1];
1175
1176 fi = find_internal_func(name, base_methods);
1177 if (fi < 0)
1178 return ERROR_UNKNOWN;
1179 if (argcount < base_methods[fi].f_min_argc)
1180 return ERROR_TOOFEW;
1181 if (argcount > base_methods[fi].f_max_argc)
1182 return ERROR_TOOMANY;
1183
Bram Moolenaar25e42232019-08-04 15:04:10 +02001184 if (base_methods[fi].f_argtype == FEARG_LAST)
1185 {
1186 // base value goes last
1187 for (i = 0; i < argcount; ++i)
1188 argv[i] = argvars[i];
1189 argv[argcount] = *basetv;
1190 }
1191 else if (base_methods[fi].f_argtype == FEARG_2)
1192 {
1193 // base value goes second
1194 argv[0] = argvars[0];
1195 argv[1] = *basetv;
1196 for (i = 1; i < argcount; ++i)
1197 argv[i + 1] = argvars[i];
1198 }
1199 else
1200 {
1201 argv[0] = *basetv;
1202 for (i = 0; i < argcount; ++i)
1203 argv[i + 1] = argvars[i];
1204 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001205 argv[argcount + 1].v_type = VAR_UNKNOWN;
1206
1207 base_methods[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001208 return ERROR_NONE;
1209}
1210
1211/*
1212 * Return TRUE for a non-zero Number and a non-empty String.
1213 */
1214 static int
1215non_zero_arg(typval_T *argvars)
1216{
1217 return ((argvars[0].v_type == VAR_NUMBER
1218 && argvars[0].vval.v_number != 0)
1219 || (argvars[0].v_type == VAR_SPECIAL
1220 && argvars[0].vval.v_number == VVAL_TRUE)
1221 || (argvars[0].v_type == VAR_STRING
1222 && argvars[0].vval.v_string != NULL
1223 && *argvars[0].vval.v_string != NUL));
1224}
1225
1226/*
1227 * Get the lnum from the first argument.
1228 * Also accepts ".", "$", etc., but that only works for the current buffer.
1229 * Returns -1 on error.
1230 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001231 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001232tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001233{
1234 typval_T rettv;
1235 linenr_T lnum;
1236
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001237 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001238 if (lnum == 0) /* no valid number, try using line() */
1239 {
1240 rettv.v_type = VAR_NUMBER;
1241 f_line(argvars, &rettv);
1242 lnum = (linenr_T)rettv.vval.v_number;
1243 clear_tv(&rettv);
1244 }
1245 return lnum;
1246}
1247
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001248/*
1249 * Get the lnum from the first argument.
1250 * Also accepts "$", then "buf" is used.
1251 * Returns 0 on error.
1252 */
1253 static linenr_T
1254tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1255{
1256 if (argvars[0].v_type == VAR_STRING
1257 && argvars[0].vval.v_string != NULL
1258 && argvars[0].vval.v_string[0] == '$'
1259 && buf != NULL)
1260 return buf->b_ml.ml_line_count;
1261 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1262}
1263
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001264#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001265/*
1266 * Get the float value of "argvars[0]" into "f".
1267 * Returns FAIL when the argument is not a Number or Float.
1268 */
1269 static int
1270get_float_arg(typval_T *argvars, float_T *f)
1271{
1272 if (argvars[0].v_type == VAR_FLOAT)
1273 {
1274 *f = argvars[0].vval.v_float;
1275 return OK;
1276 }
1277 if (argvars[0].v_type == VAR_NUMBER)
1278 {
1279 *f = (float_T)argvars[0].vval.v_number;
1280 return OK;
1281 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001282 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001283 return FAIL;
1284}
1285
1286/*
1287 * "abs(expr)" function
1288 */
1289 static void
1290f_abs(typval_T *argvars, typval_T *rettv)
1291{
1292 if (argvars[0].v_type == VAR_FLOAT)
1293 {
1294 rettv->v_type = VAR_FLOAT;
1295 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1296 }
1297 else
1298 {
1299 varnumber_T n;
1300 int error = FALSE;
1301
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001302 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001303 if (error)
1304 rettv->vval.v_number = -1;
1305 else if (n > 0)
1306 rettv->vval.v_number = n;
1307 else
1308 rettv->vval.v_number = -n;
1309 }
1310}
1311
1312/*
1313 * "acos()" function
1314 */
1315 static void
1316f_acos(typval_T *argvars, typval_T *rettv)
1317{
1318 float_T f = 0.0;
1319
1320 rettv->v_type = VAR_FLOAT;
1321 if (get_float_arg(argvars, &f) == OK)
1322 rettv->vval.v_float = acos(f);
1323 else
1324 rettv->vval.v_float = 0.0;
1325}
1326#endif
1327
1328/*
1329 * "add(list, item)" function
1330 */
1331 static void
1332f_add(typval_T *argvars, typval_T *rettv)
1333{
1334 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001335 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001336
1337 rettv->vval.v_number = 1; /* Default: Failed */
1338 if (argvars[0].v_type == VAR_LIST)
1339 {
1340 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001341 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001342 (char_u *)N_("add() argument"), TRUE)
1343 && list_append_tv(l, &argvars[1]) == OK)
1344 copy_tv(&argvars[0], rettv);
1345 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001346 else if (argvars[0].v_type == VAR_BLOB)
1347 {
1348 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001349 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001350 (char_u *)N_("add() argument"), TRUE))
1351 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001352 int error = FALSE;
1353 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1354
1355 if (!error)
1356 {
1357 ga_append(&b->bv_ga, (int)n);
1358 copy_tv(&argvars[0], rettv);
1359 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001360 }
1361 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001363 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364}
1365
1366/*
1367 * "and(expr, expr)" function
1368 */
1369 static void
1370f_and(typval_T *argvars, typval_T *rettv)
1371{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001372 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1373 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001374}
1375
1376/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001377 * If there is a window for "curbuf", make it the current window.
1378 */
1379 static void
1380find_win_for_curbuf(void)
1381{
1382 wininfo_T *wip;
1383
1384 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1385 {
1386 if (wip->wi_win != NULL)
1387 {
1388 curwin = wip->wi_win;
1389 break;
1390 }
1391 }
1392}
1393
1394/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001395 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001396 */
1397 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001398set_buffer_lines(
1399 buf_T *buf,
1400 linenr_T lnum_arg,
1401 int append,
1402 typval_T *lines,
1403 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001404{
Bram Moolenaarca851592018-06-06 21:04:07 +02001405 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1406 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001407 list_T *l = NULL;
1408 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001409 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001410 linenr_T append_lnum;
1411 buf_T *curbuf_save = NULL;
1412 win_T *curwin_save = NULL;
1413 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001414
Bram Moolenaarca851592018-06-06 21:04:07 +02001415 /* When using the current buffer ml_mfp will be set if needed. Useful when
1416 * setline() is used on startup. For other buffers the buffer must be
1417 * loaded. */
1418 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001419 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001420 rettv->vval.v_number = 1; /* FAIL */
1421 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001422 }
1423
Bram Moolenaarca851592018-06-06 21:04:07 +02001424 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001425 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001426 curbuf_save = curbuf;
1427 curwin_save = curwin;
1428 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001429 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001430 }
1431
1432 if (append)
1433 // appendbufline() uses the line number below which we insert
1434 append_lnum = lnum - 1;
1435 else
1436 // setbufline() uses the line number above which we insert, we only
1437 // append if it's below the last line
1438 append_lnum = curbuf->b_ml.ml_line_count;
1439
1440 if (lines->v_type == VAR_LIST)
1441 {
1442 l = lines->vval.v_list;
1443 li = l->lv_first;
1444 }
1445 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001446 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001447
1448 /* default result is zero == OK */
1449 for (;;)
1450 {
1451 if (l != NULL)
1452 {
1453 /* list argument, get next string */
1454 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001455 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001456 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001457 li = li->li_next;
1458 }
1459
Bram Moolenaarca851592018-06-06 21:04:07 +02001460 rettv->vval.v_number = 1; /* FAIL */
1461 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1462 break;
1463
1464 /* When coming here from Insert mode, sync undo, so that this can be
1465 * undone separately from what was previously inserted. */
1466 if (u_sync_once == 2)
1467 {
1468 u_sync_once = 1; /* notify that u_sync() was called */
1469 u_sync(TRUE);
1470 }
1471
1472 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1473 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001474 // Existing line, replace it.
1475 // Removes any existing text properties.
1476 if (u_savesub(lnum) == OK && ml_replace_len(
1477 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001478 {
1479 changed_bytes(lnum, 0);
1480 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1481 check_cursor_col();
1482 rettv->vval.v_number = 0; /* OK */
1483 }
1484 }
1485 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1486 {
1487 /* append the line */
1488 ++added;
1489 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1490 rettv->vval.v_number = 0; /* OK */
1491 }
1492
1493 if (l == NULL) /* only one string argument */
1494 break;
1495 ++lnum;
1496 }
1497
1498 if (added > 0)
1499 {
1500 win_T *wp;
1501 tabpage_T *tp;
1502
1503 appended_lines_mark(append_lnum, added);
1504 FOR_ALL_TAB_WINDOWS(tp, wp)
1505 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1506 wp->w_cursor.lnum += added;
1507 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001508 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001509 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001510
1511 if (!is_curbuf)
1512 {
1513 curbuf = curbuf_save;
1514 curwin = curwin_save;
1515 }
1516}
1517
1518/*
1519 * "append(lnum, string/list)" function
1520 */
1521 static void
1522f_append(typval_T *argvars, typval_T *rettv)
1523{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001524 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001525
1526 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1527}
1528
1529/*
1530 * "appendbufline(buf, lnum, string/list)" function
1531 */
1532 static void
1533f_appendbufline(typval_T *argvars, typval_T *rettv)
1534{
1535 linenr_T lnum;
1536 buf_T *buf;
1537
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001538 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001539 if (buf == NULL)
1540 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001541 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001543 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001544 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1545 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546}
1547
1548/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001549 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550 */
1551 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001552f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001553{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001554 win_T *wp;
1555
1556 if (argvars[0].v_type == VAR_UNKNOWN)
1557 // use the current window
1558 rettv->vval.v_number = ARGCOUNT;
1559 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001560 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001561 // use the global argument list
1562 rettv->vval.v_number = GARGCOUNT;
1563 else
1564 {
1565 // use the argument list of the specified window
1566 wp = find_win_by_nr_or_id(&argvars[0]);
1567 if (wp != NULL)
1568 rettv->vval.v_number = WARGCOUNT(wp);
1569 else
1570 rettv->vval.v_number = -1;
1571 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572}
1573
1574/*
1575 * "argidx()" function
1576 */
1577 static void
1578f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1579{
1580 rettv->vval.v_number = curwin->w_arg_idx;
1581}
1582
1583/*
1584 * "arglistid()" function
1585 */
1586 static void
1587f_arglistid(typval_T *argvars, typval_T *rettv)
1588{
1589 win_T *wp;
1590
1591 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001592 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001593 if (wp != NULL)
1594 rettv->vval.v_number = wp->w_alist->id;
1595}
1596
1597/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001598 * Get the argument list for a given window
1599 */
1600 static void
1601get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1602{
1603 int idx;
1604
1605 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1606 for (idx = 0; idx < argcount; ++idx)
1607 list_append_string(rettv->vval.v_list,
1608 alist_name(&arglist[idx]), -1);
1609}
1610
1611/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612 * "argv(nr)" function
1613 */
1614 static void
1615f_argv(typval_T *argvars, typval_T *rettv)
1616{
1617 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001618 aentry_T *arglist = NULL;
1619 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620
1621 if (argvars[0].v_type != VAR_UNKNOWN)
1622 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001623 if (argvars[1].v_type == VAR_UNKNOWN)
1624 {
1625 arglist = ARGLIST;
1626 argcount = ARGCOUNT;
1627 }
1628 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001629 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001630 {
1631 arglist = GARGLIST;
1632 argcount = GARGCOUNT;
1633 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001635 {
1636 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1637
1638 if (wp != NULL)
1639 {
1640 /* Use the argument list of the specified window */
1641 arglist = WARGLIST(wp);
1642 argcount = WARGCOUNT(wp);
1643 }
1644 }
1645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001647 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001648 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001649 if (arglist != NULL && idx >= 0 && idx < argcount)
1650 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1651 else if (idx == -1)
1652 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001653 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001654 else
1655 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001656}
1657
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001658#ifdef FEAT_FLOAT
1659/*
1660 * "asin()" function
1661 */
1662 static void
1663f_asin(typval_T *argvars, typval_T *rettv)
1664{
1665 float_T f = 0.0;
1666
1667 rettv->v_type = VAR_FLOAT;
1668 if (get_float_arg(argvars, &f) == OK)
1669 rettv->vval.v_float = asin(f);
1670 else
1671 rettv->vval.v_float = 0.0;
1672}
1673
1674/*
1675 * "atan()" function
1676 */
1677 static void
1678f_atan(typval_T *argvars, typval_T *rettv)
1679{
1680 float_T f = 0.0;
1681
1682 rettv->v_type = VAR_FLOAT;
1683 if (get_float_arg(argvars, &f) == OK)
1684 rettv->vval.v_float = atan(f);
1685 else
1686 rettv->vval.v_float = 0.0;
1687}
1688
1689/*
1690 * "atan2()" function
1691 */
1692 static void
1693f_atan2(typval_T *argvars, typval_T *rettv)
1694{
1695 float_T fx = 0.0, fy = 0.0;
1696
1697 rettv->v_type = VAR_FLOAT;
1698 if (get_float_arg(argvars, &fx) == OK
1699 && get_float_arg(&argvars[1], &fy) == OK)
1700 rettv->vval.v_float = atan2(fx, fy);
1701 else
1702 rettv->vval.v_float = 0.0;
1703}
1704#endif
1705
1706/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001707 * "balloon_show()" function
1708 */
1709#ifdef FEAT_BEVAL
1710 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001711f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1712{
1713 rettv->v_type = VAR_STRING;
1714 if (balloonEval != NULL)
1715 {
1716 if (balloonEval->msg == NULL)
1717 rettv->vval.v_string = NULL;
1718 else
1719 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1720 }
1721}
1722
1723 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001724f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1725{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001726 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001727 {
1728 if (argvars[0].v_type == VAR_LIST
1729# ifdef FEAT_GUI
1730 && !gui.in_use
1731# endif
1732 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001733 {
1734 list_T *l = argvars[0].vval.v_list;
1735
1736 // empty list removes the balloon
1737 post_balloon(balloonEval, NULL,
1738 l == NULL || l->lv_len == 0 ? NULL : l);
1739 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001740 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001741 {
1742 char_u *mesg = tv_get_string_chk(&argvars[0]);
1743
1744 if (mesg != NULL)
1745 // empty string removes the balloon
1746 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1747 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001748 }
1749}
1750
Bram Moolenaar669a8282017-11-19 20:13:05 +01001751# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001752 static void
1753f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1754{
1755 if (rettv_list_alloc(rettv) == OK)
1756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001757 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001758
1759 if (msg != NULL)
1760 {
1761 pumitem_T *array;
1762 int size = split_message(msg, &array);
1763 int i;
1764
1765 /* Skip the first and last item, they are always empty. */
1766 for (i = 1; i < size - 1; ++i)
1767 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001768 while (size > 0)
1769 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001770 vim_free(array);
1771 }
1772 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001773}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001774# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001775#endif
1776
1777/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001778 * "browse(save, title, initdir, default)" function
1779 */
1780 static void
1781f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1782{
1783#ifdef FEAT_BROWSE
1784 int save;
1785 char_u *title;
1786 char_u *initdir;
1787 char_u *defname;
1788 char_u buf[NUMBUFLEN];
1789 char_u buf2[NUMBUFLEN];
1790 int error = FALSE;
1791
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001792 save = (int)tv_get_number_chk(&argvars[0], &error);
1793 title = tv_get_string_chk(&argvars[1]);
1794 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1795 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001796
1797 if (error || title == NULL || initdir == NULL || defname == NULL)
1798 rettv->vval.v_string = NULL;
1799 else
1800 rettv->vval.v_string =
1801 do_browse(save ? BROWSE_SAVE : 0,
1802 title, defname, NULL, initdir, NULL, curbuf);
1803#else
1804 rettv->vval.v_string = NULL;
1805#endif
1806 rettv->v_type = VAR_STRING;
1807}
1808
1809/*
1810 * "browsedir(title, initdir)" function
1811 */
1812 static void
1813f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1814{
1815#ifdef FEAT_BROWSE
1816 char_u *title;
1817 char_u *initdir;
1818 char_u buf[NUMBUFLEN];
1819
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001820 title = tv_get_string_chk(&argvars[0]);
1821 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822
1823 if (title == NULL || initdir == NULL)
1824 rettv->vval.v_string = NULL;
1825 else
1826 rettv->vval.v_string = do_browse(BROWSE_DIR,
1827 title, NULL, NULL, initdir, NULL, curbuf);
1828#else
1829 rettv->vval.v_string = NULL;
1830#endif
1831 rettv->v_type = VAR_STRING;
1832}
1833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834/*
1835 * Find a buffer by number or exact name.
1836 */
1837 static buf_T *
1838find_buffer(typval_T *avar)
1839{
1840 buf_T *buf = NULL;
1841
1842 if (avar->v_type == VAR_NUMBER)
1843 buf = buflist_findnr((int)avar->vval.v_number);
1844 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1845 {
1846 buf = buflist_findname_exp(avar->vval.v_string);
1847 if (buf == NULL)
1848 {
1849 /* No full path name match, try a match with a URL or a "nofile"
1850 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001851 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001852 if (buf->b_fname != NULL
1853 && (path_with_url(buf->b_fname)
1854#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001855 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001856#endif
1857 )
1858 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1859 break;
1860 }
1861 }
1862 return buf;
1863}
1864
1865/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001866 * "bufadd(expr)" function
1867 */
1868 static void
1869f_bufadd(typval_T *argvars, typval_T *rettv)
1870{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001871 char_u *name = tv_get_string(&argvars[0]);
1872
1873 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001874}
1875
1876/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001877 * "bufexists(expr)" function
1878 */
1879 static void
1880f_bufexists(typval_T *argvars, typval_T *rettv)
1881{
1882 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1883}
1884
1885/*
1886 * "buflisted(expr)" function
1887 */
1888 static void
1889f_buflisted(typval_T *argvars, typval_T *rettv)
1890{
1891 buf_T *buf;
1892
1893 buf = find_buffer(&argvars[0]);
1894 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1895}
1896
1897/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001898 * "bufload(expr)" function
1899 */
1900 static void
1901f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1902{
1903 buf_T *buf = get_buf_arg(&argvars[0]);
1904
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001905 if (buf != NULL)
1906 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001907}
1908
1909/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001910 * "bufloaded(expr)" function
1911 */
1912 static void
1913f_bufloaded(typval_T *argvars, typval_T *rettv)
1914{
1915 buf_T *buf;
1916
1917 buf = find_buffer(&argvars[0]);
1918 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1919}
1920
1921 buf_T *
1922buflist_find_by_name(char_u *name, int curtab_only)
1923{
1924 int save_magic;
1925 char_u *save_cpo;
1926 buf_T *buf;
1927
1928 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1929 save_magic = p_magic;
1930 p_magic = TRUE;
1931 save_cpo = p_cpo;
1932 p_cpo = (char_u *)"";
1933
1934 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1935 TRUE, FALSE, curtab_only));
1936
1937 p_magic = save_magic;
1938 p_cpo = save_cpo;
1939 return buf;
1940}
1941
1942/*
1943 * Get buffer by number or pattern.
1944 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001945 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001946tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001947{
1948 char_u *name = tv->vval.v_string;
1949 buf_T *buf;
1950
1951 if (tv->v_type == VAR_NUMBER)
1952 return buflist_findnr((int)tv->vval.v_number);
1953 if (tv->v_type != VAR_STRING)
1954 return NULL;
1955 if (name == NULL || *name == NUL)
1956 return curbuf;
1957 if (name[0] == '$' && name[1] == NUL)
1958 return lastbuf;
1959
1960 buf = buflist_find_by_name(name, curtab_only);
1961
1962 /* If not found, try expanding the name, like done for bufexists(). */
1963 if (buf == NULL)
1964 buf = find_buffer(tv);
1965
1966 return buf;
1967}
1968
1969/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001970 * Get the buffer from "arg" and give an error and return NULL if it is not
1971 * valid.
1972 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001973 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001974get_buf_arg(typval_T *arg)
1975{
1976 buf_T *buf;
1977
1978 ++emsg_off;
1979 buf = tv_get_buf(arg, FALSE);
1980 --emsg_off;
1981 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001982 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001983 return buf;
1984}
1985
1986/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 * "bufname(expr)" function
1988 */
1989 static void
1990f_bufname(typval_T *argvars, typval_T *rettv)
1991{
1992 buf_T *buf;
1993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001994 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001996 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001997 rettv->v_type = VAR_STRING;
1998 if (buf != NULL && buf->b_fname != NULL)
1999 rettv->vval.v_string = vim_strsave(buf->b_fname);
2000 else
2001 rettv->vval.v_string = NULL;
2002 --emsg_off;
2003}
2004
2005/*
2006 * "bufnr(expr)" function
2007 */
2008 static void
2009f_bufnr(typval_T *argvars, typval_T *rettv)
2010{
2011 buf_T *buf;
2012 int error = FALSE;
2013 char_u *name;
2014
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002015 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002017 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 --emsg_off;
2019
2020 /* If the buffer isn't found and the second argument is not zero create a
2021 * new buffer. */
2022 if (buf == NULL
2023 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002024 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002025 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002026 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002027 && !error)
2028 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2029
2030 if (buf != NULL)
2031 rettv->vval.v_number = buf->b_fnum;
2032 else
2033 rettv->vval.v_number = -1;
2034}
2035
2036 static void
2037buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2038{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 win_T *wp;
2040 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002041 buf_T *buf;
2042
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002043 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002044 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002045 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002046 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002047 {
2048 ++winnr;
2049 if (wp->w_buffer == buf)
2050 break;
2051 }
2052 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002053 --emsg_off;
2054}
2055
2056/*
2057 * "bufwinid(nr)" function
2058 */
2059 static void
2060f_bufwinid(typval_T *argvars, typval_T *rettv)
2061{
2062 buf_win_common(argvars, rettv, FALSE);
2063}
2064
2065/*
2066 * "bufwinnr(nr)" function
2067 */
2068 static void
2069f_bufwinnr(typval_T *argvars, typval_T *rettv)
2070{
2071 buf_win_common(argvars, rettv, TRUE);
2072}
2073
2074/*
2075 * "byte2line(byte)" function
2076 */
2077 static void
2078f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2079{
2080#ifndef FEAT_BYTEOFF
2081 rettv->vval.v_number = -1;
2082#else
2083 long boff = 0;
2084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002085 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086 if (boff < 0)
2087 rettv->vval.v_number = -1;
2088 else
2089 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2090 (linenr_T)0, &boff);
2091#endif
2092}
2093
2094 static void
2095byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2096{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 char_u *str;
2099 varnumber_T idx;
2100
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002101 str = tv_get_string_chk(&argvars[0]);
2102 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103 rettv->vval.v_number = -1;
2104 if (str == NULL || idx < 0)
2105 return;
2106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002107 t = str;
2108 for ( ; idx > 0; idx--)
2109 {
2110 if (*t == NUL) /* EOL reached */
2111 return;
2112 if (enc_utf8 && comp)
2113 t += utf_ptr2len(t);
2114 else
2115 t += (*mb_ptr2len)(t);
2116 }
2117 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002118}
2119
2120/*
2121 * "byteidx()" function
2122 */
2123 static void
2124f_byteidx(typval_T *argvars, typval_T *rettv)
2125{
2126 byteidx(argvars, rettv, FALSE);
2127}
2128
2129/*
2130 * "byteidxcomp()" function
2131 */
2132 static void
2133f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2134{
2135 byteidx(argvars, rettv, TRUE);
2136}
2137
2138/*
2139 * "call(func, arglist [, dict])" function
2140 */
2141 static void
2142f_call(typval_T *argvars, typval_T *rettv)
2143{
2144 char_u *func;
2145 partial_T *partial = NULL;
2146 dict_T *selfdict = NULL;
2147
2148 if (argvars[1].v_type != VAR_LIST)
2149 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002150 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151 return;
2152 }
2153 if (argvars[1].vval.v_list == NULL)
2154 return;
2155
2156 if (argvars[0].v_type == VAR_FUNC)
2157 func = argvars[0].vval.v_string;
2158 else if (argvars[0].v_type == VAR_PARTIAL)
2159 {
2160 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002161 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 }
2163 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002164 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002165 if (*func == NUL)
2166 return; /* type error or empty name */
2167
2168 if (argvars[2].v_type != VAR_UNKNOWN)
2169 {
2170 if (argvars[2].v_type != VAR_DICT)
2171 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002172 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 return;
2174 }
2175 selfdict = argvars[2].vval.v_dict;
2176 }
2177
2178 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2179}
2180
2181#ifdef FEAT_FLOAT
2182/*
2183 * "ceil({float})" function
2184 */
2185 static void
2186f_ceil(typval_T *argvars, typval_T *rettv)
2187{
2188 float_T f = 0.0;
2189
2190 rettv->v_type = VAR_FLOAT;
2191 if (get_float_arg(argvars, &f) == OK)
2192 rettv->vval.v_float = ceil(f);
2193 else
2194 rettv->vval.v_float = 0.0;
2195}
2196#endif
2197
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002198/*
2199 * "changenr()" function
2200 */
2201 static void
2202f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2203{
2204 rettv->vval.v_number = curbuf->b_u_seq_cur;
2205}
2206
2207/*
2208 * "char2nr(string)" function
2209 */
2210 static void
2211f_char2nr(typval_T *argvars, typval_T *rettv)
2212{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213 if (has_mbyte)
2214 {
2215 int utf8 = 0;
2216
2217 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002218 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002219
2220 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002221 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002222 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002223 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002224 }
2225 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002226 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002227}
2228
2229/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002230 * "chdir(dir)" function
2231 */
2232 static void
2233f_chdir(typval_T *argvars, typval_T *rettv)
2234{
2235 char_u *cwd;
2236 cdscope_T scope = CDSCOPE_GLOBAL;
2237
2238 rettv->v_type = VAR_STRING;
2239 rettv->vval.v_string = NULL;
2240
2241 if (argvars[0].v_type != VAR_STRING)
2242 return;
2243
2244 // Return the current directory
2245 cwd = alloc(MAXPATHL);
2246 if (cwd != NULL)
2247 {
2248 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2249 {
2250#ifdef BACKSLASH_IN_FILENAME
2251 slash_adjust(cwd);
2252#endif
2253 rettv->vval.v_string = vim_strsave(cwd);
2254 }
2255 vim_free(cwd);
2256 }
2257
2258 if (curwin->w_localdir != NULL)
2259 scope = CDSCOPE_WINDOW;
2260 else if (curtab->tp_localdir != NULL)
2261 scope = CDSCOPE_TABPAGE;
2262
2263 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2264 // Directory change failed
2265 VIM_CLEAR(rettv->vval.v_string);
2266}
2267
2268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 * "cindent(lnum)" function
2270 */
2271 static void
2272f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2273{
2274#ifdef FEAT_CINDENT
2275 pos_T pos;
2276 linenr_T lnum;
2277
2278 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002279 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2281 {
2282 curwin->w_cursor.lnum = lnum;
2283 rettv->vval.v_number = get_c_indent();
2284 curwin->w_cursor = pos;
2285 }
2286 else
2287#endif
2288 rettv->vval.v_number = -1;
2289}
2290
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002291 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002292get_optional_window(typval_T *argvars, int idx)
2293{
2294 win_T *win = curwin;
2295
2296 if (argvars[idx].v_type != VAR_UNKNOWN)
2297 {
2298 win = find_win_by_nr_or_id(&argvars[idx]);
2299 if (win == NULL)
2300 {
2301 emsg(_(e_invalwindow));
2302 return NULL;
2303 }
2304 }
2305 return win;
2306}
2307
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002309 * "col(string)" function
2310 */
2311 static void
2312f_col(typval_T *argvars, typval_T *rettv)
2313{
2314 colnr_T col = 0;
2315 pos_T *fp;
2316 int fnum = curbuf->b_fnum;
2317
2318 fp = var2fpos(&argvars[0], FALSE, &fnum);
2319 if (fp != NULL && fnum == curbuf->b_fnum)
2320 {
2321 if (fp->col == MAXCOL)
2322 {
2323 /* '> can be MAXCOL, get the length of the line then */
2324 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2325 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2326 else
2327 col = MAXCOL;
2328 }
2329 else
2330 {
2331 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002332 /* col(".") when the cursor is on the NUL at the end of the line
2333 * because of "coladd" can be seen as an extra column. */
2334 if (virtual_active() && fp == &curwin->w_cursor)
2335 {
2336 char_u *p = ml_get_cursor();
2337
2338 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2339 curwin->w_virtcol - curwin->w_cursor.coladd))
2340 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002341 int l;
2342
2343 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2344 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 }
2346 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 }
2348 }
2349 rettv->vval.v_number = col;
2350}
2351
2352#if defined(FEAT_INS_EXPAND)
2353/*
2354 * "complete()" function
2355 */
2356 static void
2357f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2358{
2359 int startcol;
2360
2361 if ((State & INSERT) == 0)
2362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002363 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 return;
2365 }
2366
2367 /* Check for undo allowed here, because if something was already inserted
2368 * the line was already saved for undo and this check isn't done. */
2369 if (!undo_allowed())
2370 return;
2371
2372 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2373 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002374 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002375 return;
2376 }
2377
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002378 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002379 if (startcol <= 0)
2380 return;
2381
2382 set_completion(startcol - 1, argvars[1].vval.v_list);
2383}
2384
2385/*
2386 * "complete_add()" function
2387 */
2388 static void
2389f_complete_add(typval_T *argvars, typval_T *rettv)
2390{
2391 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2392}
2393
2394/*
2395 * "complete_check()" function
2396 */
2397 static void
2398f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2399{
2400 int saved = RedrawingDisabled;
2401
2402 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002403 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002404 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405 RedrawingDisabled = saved;
2406}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002407
2408/*
2409 * "complete_info()" function
2410 */
2411 static void
2412f_complete_info(typval_T *argvars, typval_T *rettv)
2413{
2414 list_T *what_list = NULL;
2415
2416 if (rettv_dict_alloc(rettv) != OK)
2417 return;
2418
2419 if (argvars[0].v_type != VAR_UNKNOWN)
2420 {
2421 if (argvars[0].v_type != VAR_LIST)
2422 {
2423 emsg(_(e_listreq));
2424 return;
2425 }
2426 what_list = argvars[0].vval.v_list;
2427 }
2428 get_complete_info(what_list, rettv->vval.v_dict);
2429}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002430#endif
2431
2432/*
2433 * "confirm(message, buttons[, default [, type]])" function
2434 */
2435 static void
2436f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2437{
2438#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2439 char_u *message;
2440 char_u *buttons = NULL;
2441 char_u buf[NUMBUFLEN];
2442 char_u buf2[NUMBUFLEN];
2443 int def = 1;
2444 int type = VIM_GENERIC;
2445 char_u *typestr;
2446 int error = FALSE;
2447
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002448 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002449 if (message == NULL)
2450 error = TRUE;
2451 if (argvars[1].v_type != VAR_UNKNOWN)
2452 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002453 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454 if (buttons == NULL)
2455 error = TRUE;
2456 if (argvars[2].v_type != VAR_UNKNOWN)
2457 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002458 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 if (argvars[3].v_type != VAR_UNKNOWN)
2460 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002461 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462 if (typestr == NULL)
2463 error = TRUE;
2464 else
2465 {
2466 switch (TOUPPER_ASC(*typestr))
2467 {
2468 case 'E': type = VIM_ERROR; break;
2469 case 'Q': type = VIM_QUESTION; break;
2470 case 'I': type = VIM_INFO; break;
2471 case 'W': type = VIM_WARNING; break;
2472 case 'G': type = VIM_GENERIC; break;
2473 }
2474 }
2475 }
2476 }
2477 }
2478
2479 if (buttons == NULL || *buttons == NUL)
2480 buttons = (char_u *)_("&Ok");
2481
2482 if (!error)
2483 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2484 def, NULL, FALSE);
2485#endif
2486}
2487
2488/*
2489 * "copy()" function
2490 */
2491 static void
2492f_copy(typval_T *argvars, typval_T *rettv)
2493{
2494 item_copy(&argvars[0], rettv, FALSE, 0);
2495}
2496
2497#ifdef FEAT_FLOAT
2498/*
2499 * "cos()" function
2500 */
2501 static void
2502f_cos(typval_T *argvars, typval_T *rettv)
2503{
2504 float_T f = 0.0;
2505
2506 rettv->v_type = VAR_FLOAT;
2507 if (get_float_arg(argvars, &f) == OK)
2508 rettv->vval.v_float = cos(f);
2509 else
2510 rettv->vval.v_float = 0.0;
2511}
2512
2513/*
2514 * "cosh()" function
2515 */
2516 static void
2517f_cosh(typval_T *argvars, typval_T *rettv)
2518{
2519 float_T f = 0.0;
2520
2521 rettv->v_type = VAR_FLOAT;
2522 if (get_float_arg(argvars, &f) == OK)
2523 rettv->vval.v_float = cosh(f);
2524 else
2525 rettv->vval.v_float = 0.0;
2526}
2527#endif
2528
2529/*
2530 * "count()" function
2531 */
2532 static void
2533f_count(typval_T *argvars, typval_T *rettv)
2534{
2535 long n = 0;
2536 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002537 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002538
Bram Moolenaar9966b212017-07-28 16:46:57 +02002539 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002540 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002541
2542 if (argvars[0].v_type == VAR_STRING)
2543 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002544 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002545 char_u *p = argvars[0].vval.v_string;
2546 char_u *next;
2547
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002548 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002549 {
2550 if (ic)
2551 {
2552 size_t len = STRLEN(expr);
2553
2554 while (*p != NUL)
2555 {
2556 if (MB_STRNICMP(p, expr, len) == 0)
2557 {
2558 ++n;
2559 p += len;
2560 }
2561 else
2562 MB_PTR_ADV(p);
2563 }
2564 }
2565 else
2566 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2567 != NULL)
2568 {
2569 ++n;
2570 p = next + STRLEN(expr);
2571 }
2572 }
2573
2574 }
2575 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576 {
2577 listitem_T *li;
2578 list_T *l;
2579 long idx;
2580
2581 if ((l = argvars[0].vval.v_list) != NULL)
2582 {
2583 li = l->lv_first;
2584 if (argvars[2].v_type != VAR_UNKNOWN)
2585 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586 if (argvars[3].v_type != VAR_UNKNOWN)
2587 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002588 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002589 if (!error)
2590 {
2591 li = list_find(l, idx);
2592 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002593 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 }
2595 }
2596 if (error)
2597 li = NULL;
2598 }
2599
2600 for ( ; li != NULL; li = li->li_next)
2601 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2602 ++n;
2603 }
2604 }
2605 else if (argvars[0].v_type == VAR_DICT)
2606 {
2607 int todo;
2608 dict_T *d;
2609 hashitem_T *hi;
2610
2611 if ((d = argvars[0].vval.v_dict) != NULL)
2612 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613 if (argvars[2].v_type != VAR_UNKNOWN)
2614 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002616 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002617 }
2618
2619 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2620 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2621 {
2622 if (!HASHITEM_EMPTY(hi))
2623 {
2624 --todo;
2625 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2626 ++n;
2627 }
2628 }
2629 }
2630 }
2631 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002632 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633 rettv->vval.v_number = n;
2634}
2635
2636/*
2637 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2638 *
2639 * Checks the existence of a cscope connection.
2640 */
2641 static void
2642f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2643{
2644#ifdef FEAT_CSCOPE
2645 int num = 0;
2646 char_u *dbpath = NULL;
2647 char_u *prepend = NULL;
2648 char_u buf[NUMBUFLEN];
2649
2650 if (argvars[0].v_type != VAR_UNKNOWN
2651 && argvars[1].v_type != VAR_UNKNOWN)
2652 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002653 num = (int)tv_get_number(&argvars[0]);
2654 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002656 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002657 }
2658
2659 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2660#endif
2661}
2662
2663/*
2664 * "cursor(lnum, col)" function, or
2665 * "cursor(list)"
2666 *
2667 * Moves the cursor to the specified line and column.
2668 * Returns 0 when the position could be set, -1 otherwise.
2669 */
2670 static void
2671f_cursor(typval_T *argvars, typval_T *rettv)
2672{
2673 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 int set_curswant = TRUE;
2676
2677 rettv->vval.v_number = -1;
2678 if (argvars[1].v_type == VAR_UNKNOWN)
2679 {
2680 pos_T pos;
2681 colnr_T curswant = -1;
2682
2683 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2684 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002685 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002686 return;
2687 }
2688 line = pos.lnum;
2689 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 if (curswant >= 0)
2692 {
2693 curwin->w_curswant = curswant - 1;
2694 set_curswant = FALSE;
2695 }
2696 }
2697 else
2698 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002699 line = tv_get_lnum(argvars);
2700 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002702 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002704 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705 return; /* type error; errmsg already given */
2706 if (line > 0)
2707 curwin->w_cursor.lnum = line;
2708 if (col > 0)
2709 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002710 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711
2712 /* Make sure the cursor is in a valid position. */
2713 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 /* Correct cursor for multi-byte character. */
2715 if (has_mbyte)
2716 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002717
2718 curwin->w_set_curswant = set_curswant;
2719 rettv->vval.v_number = 0;
2720}
2721
Bram Moolenaar4f974752019-02-17 17:44:42 +01002722#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002723/*
2724 * "debugbreak()" function
2725 */
2726 static void
2727f_debugbreak(typval_T *argvars, typval_T *rettv)
2728{
2729 int pid;
2730
2731 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002732 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002733 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002734 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002735 else
2736 {
2737 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2738
2739 if (hProcess != NULL)
2740 {
2741 DebugBreakProcess(hProcess);
2742 CloseHandle(hProcess);
2743 rettv->vval.v_number = OK;
2744 }
2745 }
2746}
2747#endif
2748
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749/*
2750 * "deepcopy()" function
2751 */
2752 static void
2753f_deepcopy(typval_T *argvars, typval_T *rettv)
2754{
2755 int noref = 0;
2756 int copyID;
2757
2758 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002759 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002760 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002761 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 else
2763 {
2764 copyID = get_copyID();
2765 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2766 }
2767}
2768
2769/*
2770 * "delete()" function
2771 */
2772 static void
2773f_delete(typval_T *argvars, typval_T *rettv)
2774{
2775 char_u nbuf[NUMBUFLEN];
2776 char_u *name;
2777 char_u *flags;
2778
2779 rettv->vval.v_number = -1;
2780 if (check_restricted() || check_secure())
2781 return;
2782
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002783 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784 if (name == NULL || *name == NUL)
2785 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002786 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 return;
2788 }
2789
2790 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002791 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792 else
2793 flags = (char_u *)"";
2794
2795 if (*flags == NUL)
2796 /* delete a file */
2797 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2798 else if (STRCMP(flags, "d") == 0)
2799 /* delete an empty directory */
2800 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2801 else if (STRCMP(flags, "rf") == 0)
2802 /* delete a directory recursively */
2803 rettv->vval.v_number = delete_recursive(name);
2804 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002805 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806}
2807
2808/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002809 * "deletebufline()" function
2810 */
2811 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002812f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002813{
2814 buf_T *buf;
2815 linenr_T first, last;
2816 linenr_T lnum;
2817 long count;
2818 int is_curbuf;
2819 buf_T *curbuf_save = NULL;
2820 win_T *curwin_save = NULL;
2821 tabpage_T *tp;
2822 win_T *wp;
2823
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002824 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002825 if (buf == NULL)
2826 {
2827 rettv->vval.v_number = 1; /* FAIL */
2828 return;
2829 }
2830 is_curbuf = buf == curbuf;
2831
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002832 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002833 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002834 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002835 else
2836 last = first;
2837
2838 if (buf->b_ml.ml_mfp == NULL || first < 1
2839 || first > buf->b_ml.ml_line_count || last < first)
2840 {
2841 rettv->vval.v_number = 1; /* FAIL */
2842 return;
2843 }
2844
2845 if (!is_curbuf)
2846 {
2847 curbuf_save = curbuf;
2848 curwin_save = curwin;
2849 curbuf = buf;
2850 find_win_for_curbuf();
2851 }
2852 if (last > curbuf->b_ml.ml_line_count)
2853 last = curbuf->b_ml.ml_line_count;
2854 count = last - first + 1;
2855
2856 // When coming here from Insert mode, sync undo, so that this can be
2857 // undone separately from what was previously inserted.
2858 if (u_sync_once == 2)
2859 {
2860 u_sync_once = 1; // notify that u_sync() was called
2861 u_sync(TRUE);
2862 }
2863
2864 if (u_save(first - 1, last + 1) == FAIL)
2865 {
2866 rettv->vval.v_number = 1; /* FAIL */
2867 return;
2868 }
2869
2870 for (lnum = first; lnum <= last; ++lnum)
2871 ml_delete(first, TRUE);
2872
2873 FOR_ALL_TAB_WINDOWS(tp, wp)
2874 if (wp->w_buffer == buf)
2875 {
2876 if (wp->w_cursor.lnum > last)
2877 wp->w_cursor.lnum -= count;
2878 else if (wp->w_cursor.lnum> first)
2879 wp->w_cursor.lnum = first;
2880 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2881 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2882 }
2883 check_cursor_col();
2884 deleted_lines_mark(first, count);
2885
2886 if (!is_curbuf)
2887 {
2888 curbuf = curbuf_save;
2889 curwin = curwin_save;
2890 }
2891}
2892
2893/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002894 * "did_filetype()" function
2895 */
2896 static void
2897f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2898{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002900}
2901
2902/*
2903 * "diff_filler()" function
2904 */
2905 static void
2906f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2907{
2908#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002909 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002910#endif
2911}
2912
2913/*
2914 * "diff_hlID()" function
2915 */
2916 static void
2917f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2918{
2919#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002920 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002921 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002922 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002923 static int fnum = 0;
2924 static int change_start = 0;
2925 static int change_end = 0;
2926 static hlf_T hlID = (hlf_T)0;
2927 int filler_lines;
2928 int col;
2929
2930 if (lnum < 0) /* ignore type error in {lnum} arg */
2931 lnum = 0;
2932 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002933 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002934 || fnum != curbuf->b_fnum)
2935 {
2936 /* New line, buffer, change: need to get the values. */
2937 filler_lines = diff_check(curwin, lnum);
2938 if (filler_lines < 0)
2939 {
2940 if (filler_lines == -1)
2941 {
2942 change_start = MAXCOL;
2943 change_end = -1;
2944 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2945 hlID = HLF_ADD; /* added line */
2946 else
2947 hlID = HLF_CHD; /* changed line */
2948 }
2949 else
2950 hlID = HLF_ADD; /* added line */
2951 }
2952 else
2953 hlID = (hlf_T)0;
2954 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002955 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956 fnum = curbuf->b_fnum;
2957 }
2958
2959 if (hlID == HLF_CHD || hlID == HLF_TXD)
2960 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002961 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002962 if (col >= change_start && col <= change_end)
2963 hlID = HLF_TXD; /* changed text */
2964 else
2965 hlID = HLF_CHD; /* changed line */
2966 }
2967 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2968#endif
2969}
2970
2971/*
2972 * "empty({expr})" function
2973 */
2974 static void
2975f_empty(typval_T *argvars, typval_T *rettv)
2976{
2977 int n = FALSE;
2978
2979 switch (argvars[0].v_type)
2980 {
2981 case VAR_STRING:
2982 case VAR_FUNC:
2983 n = argvars[0].vval.v_string == NULL
2984 || *argvars[0].vval.v_string == NUL;
2985 break;
2986 case VAR_PARTIAL:
2987 n = FALSE;
2988 break;
2989 case VAR_NUMBER:
2990 n = argvars[0].vval.v_number == 0;
2991 break;
2992 case VAR_FLOAT:
2993#ifdef FEAT_FLOAT
2994 n = argvars[0].vval.v_float == 0.0;
2995 break;
2996#endif
2997 case VAR_LIST:
2998 n = argvars[0].vval.v_list == NULL
2999 || argvars[0].vval.v_list->lv_first == NULL;
3000 break;
3001 case VAR_DICT:
3002 n = argvars[0].vval.v_dict == NULL
3003 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3004 break;
3005 case VAR_SPECIAL:
3006 n = argvars[0].vval.v_number != VVAL_TRUE;
3007 break;
3008
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003009 case VAR_BLOB:
3010 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003011 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3012 break;
3013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014 case VAR_JOB:
3015#ifdef FEAT_JOB_CHANNEL
3016 n = argvars[0].vval.v_job == NULL
3017 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3018 break;
3019#endif
3020 case VAR_CHANNEL:
3021#ifdef FEAT_JOB_CHANNEL
3022 n = argvars[0].vval.v_channel == NULL
3023 || !channel_is_open(argvars[0].vval.v_channel);
3024 break;
3025#endif
3026 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003027 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003028 n = TRUE;
3029 break;
3030 }
3031
3032 rettv->vval.v_number = n;
3033}
3034
3035/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003036 * "environ()" function
3037 */
3038 static void
3039f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3040{
3041#if !defined(AMIGA)
3042 int i = 0;
3043 char_u *entry, *value;
3044# ifdef MSWIN
3045 extern wchar_t **_wenviron;
3046# else
3047 extern char **environ;
3048# endif
3049
3050 if (rettv_dict_alloc(rettv) != OK)
3051 return;
3052
3053# ifdef MSWIN
3054 if (*_wenviron == NULL)
3055 return;
3056# else
3057 if (*environ == NULL)
3058 return;
3059# endif
3060
3061 for (i = 0; ; ++i)
3062 {
3063# ifdef MSWIN
3064 short_u *p;
3065
3066 if ((p = (short_u *)_wenviron[i]) == NULL)
3067 return;
3068 entry = utf16_to_enc(p, NULL);
3069# else
3070 if ((entry = (char_u *)environ[i]) == NULL)
3071 return;
3072 entry = vim_strsave(entry);
3073# endif
3074 if (entry == NULL) // out of memory
3075 return;
3076 if ((value = vim_strchr(entry, '=')) == NULL)
3077 {
3078 vim_free(entry);
3079 continue;
3080 }
3081 *value++ = NUL;
3082 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3083 vim_free(entry);
3084 }
3085#endif
3086}
3087
3088/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003089 * "escape({string}, {chars})" function
3090 */
3091 static void
3092f_escape(typval_T *argvars, typval_T *rettv)
3093{
3094 char_u buf[NUMBUFLEN];
3095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003096 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3097 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098 rettv->v_type = VAR_STRING;
3099}
3100
3101/*
3102 * "eval()" function
3103 */
3104 static void
3105f_eval(typval_T *argvars, typval_T *rettv)
3106{
3107 char_u *s, *p;
3108
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003109 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003110 if (s != NULL)
3111 s = skipwhite(s);
3112
3113 p = s;
3114 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3115 {
3116 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003117 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003118 need_clr_eos = FALSE;
3119 rettv->v_type = VAR_NUMBER;
3120 rettv->vval.v_number = 0;
3121 }
3122 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003123 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003124}
3125
3126/*
3127 * "eventhandler()" function
3128 */
3129 static void
3130f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3131{
3132 rettv->vval.v_number = vgetc_busy;
3133}
3134
3135/*
3136 * "executable()" function
3137 */
3138 static void
3139f_executable(typval_T *argvars, typval_T *rettv)
3140{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003141 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003142
3143 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003144 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003145}
3146
3147static garray_T redir_execute_ga;
3148
3149/*
3150 * Append "value[value_len]" to the execute() output.
3151 */
3152 void
3153execute_redir_str(char_u *value, int value_len)
3154{
3155 int len;
3156
3157 if (value_len == -1)
3158 len = (int)STRLEN(value); /* Append the entire string */
3159 else
3160 len = value_len; /* Append only "value_len" characters */
3161 if (ga_grow(&redir_execute_ga, len) == OK)
3162 {
3163 mch_memmove((char *)redir_execute_ga.ga_data
3164 + redir_execute_ga.ga_len, value, len);
3165 redir_execute_ga.ga_len += len;
3166 }
3167}
3168
3169/*
3170 * Get next line from a list.
3171 * Called by do_cmdline() to get the next line.
3172 * Returns allocated string, or NULL for end of function.
3173 */
3174
3175 static char_u *
3176get_list_line(
3177 int c UNUSED,
3178 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003179 int indent UNUSED,
3180 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003181{
3182 listitem_T **p = (listitem_T **)cookie;
3183 listitem_T *item = *p;
3184 char_u buf[NUMBUFLEN];
3185 char_u *s;
3186
3187 if (item == NULL)
3188 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003189 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003190 *p = item->li_next;
3191 return s == NULL ? NULL : vim_strsave(s);
3192}
3193
3194/*
3195 * "execute()" function
3196 */
3197 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003198execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003199{
3200 char_u *cmd = NULL;
3201 list_T *list = NULL;
3202 int save_msg_silent = msg_silent;
3203 int save_emsg_silent = emsg_silent;
3204 int save_emsg_noredir = emsg_noredir;
3205 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003206 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003208 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003209 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003210
3211 rettv->vval.v_string = NULL;
3212 rettv->v_type = VAR_STRING;
3213
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003214 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003216 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003217 if (list == NULL || list->lv_first == NULL)
3218 /* empty list, no commands, empty output */
3219 return;
3220 ++list->lv_refcount;
3221 }
3222 else
3223 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003224 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003225 if (cmd == NULL)
3226 return;
3227 }
3228
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003229 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 {
3231 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003232 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003233
3234 if (s == NULL)
3235 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003236 if (*s == NUL)
3237 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 if (STRNCMP(s, "silent", 6) == 0)
3239 ++msg_silent;
3240 if (STRCMP(s, "silent!") == 0)
3241 {
3242 emsg_silent = TRUE;
3243 emsg_noredir = TRUE;
3244 }
3245 }
3246 else
3247 ++msg_silent;
3248
3249 if (redir_execute)
3250 save_ga = redir_execute_ga;
3251 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3252 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003253 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003254 if (!echo_output)
3255 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003256
3257 if (cmd != NULL)
3258 do_cmdline_cmd(cmd);
3259 else
3260 {
3261 listitem_T *item = list->lv_first;
3262
3263 do_cmdline(NULL, get_list_line, (void *)&item,
3264 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3265 --list->lv_refcount;
3266 }
3267
Bram Moolenaard297f352017-01-29 20:31:21 +01003268 /* Need to append a NUL to the result. */
3269 if (ga_grow(&redir_execute_ga, 1) == OK)
3270 {
3271 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3272 rettv->vval.v_string = redir_execute_ga.ga_data;
3273 }
3274 else
3275 {
3276 ga_clear(&redir_execute_ga);
3277 rettv->vval.v_string = NULL;
3278 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003279 msg_silent = save_msg_silent;
3280 emsg_silent = save_emsg_silent;
3281 emsg_noredir = save_emsg_noredir;
3282
3283 redir_execute = save_redir_execute;
3284 if (redir_execute)
3285 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003286 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003287
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003288 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003289 if (echo_output)
3290 // When not working silently: put it in column zero. A following
3291 // "echon" will overwrite the message, unavoidably.
3292 msg_col = 0;
3293 else
3294 // When working silently: Put it back where it was, since nothing
3295 // should have been written.
3296 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297}
3298
3299/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003300 * "execute()" function
3301 */
3302 static void
3303f_execute(typval_T *argvars, typval_T *rettv)
3304{
3305 execute_common(argvars, rettv, 0);
3306}
3307
3308/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003309 * "exepath()" function
3310 */
3311 static void
3312f_exepath(typval_T *argvars, typval_T *rettv)
3313{
3314 char_u *p = NULL;
3315
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003316 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317 rettv->v_type = VAR_STRING;
3318 rettv->vval.v_string = p;
3319}
3320
3321/*
3322 * "exists()" function
3323 */
3324 static void
3325f_exists(typval_T *argvars, typval_T *rettv)
3326{
3327 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003328 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003329
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003330 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003331 if (*p == '$') /* environment variable */
3332 {
3333 /* first try "normal" environment variables (fast) */
3334 if (mch_getenv(p + 1) != NULL)
3335 n = TRUE;
3336 else
3337 {
3338 /* try expanding things like $VIM and ${HOME} */
3339 p = expand_env_save(p);
3340 if (p != NULL && *p != '$')
3341 n = TRUE;
3342 vim_free(p);
3343 }
3344 }
3345 else if (*p == '&' || *p == '+') /* option */
3346 {
3347 n = (get_option_tv(&p, NULL, TRUE) == OK);
3348 if (*skipwhite(p) != NUL)
3349 n = FALSE; /* trailing garbage */
3350 }
3351 else if (*p == '*') /* internal or user defined function */
3352 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003353 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003354 }
3355 else if (*p == ':')
3356 {
3357 n = cmd_exists(p + 1);
3358 }
3359 else if (*p == '#')
3360 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003361 if (p[1] == '#')
3362 n = autocmd_supported(p + 2);
3363 else
3364 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003365 }
3366 else /* internal variable */
3367 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003368 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003369 }
3370
3371 rettv->vval.v_number = n;
3372}
3373
3374#ifdef FEAT_FLOAT
3375/*
3376 * "exp()" function
3377 */
3378 static void
3379f_exp(typval_T *argvars, typval_T *rettv)
3380{
3381 float_T f = 0.0;
3382
3383 rettv->v_type = VAR_FLOAT;
3384 if (get_float_arg(argvars, &f) == OK)
3385 rettv->vval.v_float = exp(f);
3386 else
3387 rettv->vval.v_float = 0.0;
3388}
3389#endif
3390
3391/*
3392 * "expand()" function
3393 */
3394 static void
3395f_expand(typval_T *argvars, typval_T *rettv)
3396{
3397 char_u *s;
3398 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003399 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3401 expand_T xpc;
3402 int error = FALSE;
3403 char_u *result;
3404
3405 rettv->v_type = VAR_STRING;
3406 if (argvars[1].v_type != VAR_UNKNOWN
3407 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003408 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003409 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003410 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003411
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003412 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003413 if (*s == '%' || *s == '#' || *s == '<')
3414 {
3415 ++emsg_off;
3416 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3417 --emsg_off;
3418 if (rettv->v_type == VAR_LIST)
3419 {
3420 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3421 list_append_string(rettv->vval.v_list, result, -1);
3422 else
3423 vim_free(result);
3424 }
3425 else
3426 rettv->vval.v_string = result;
3427 }
3428 else
3429 {
3430 /* When the optional second argument is non-zero, don't remove matches
3431 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3432 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003433 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 options |= WILD_KEEP_ALL;
3435 if (!error)
3436 {
3437 ExpandInit(&xpc);
3438 xpc.xp_context = EXPAND_FILES;
3439 if (p_wic)
3440 options += WILD_ICASE;
3441 if (rettv->v_type == VAR_STRING)
3442 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3443 options, WILD_ALL);
3444 else if (rettv_list_alloc(rettv) != FAIL)
3445 {
3446 int i;
3447
3448 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3449 for (i = 0; i < xpc.xp_numfiles; i++)
3450 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3451 ExpandCleanup(&xpc);
3452 }
3453 }
3454 else
3455 rettv->vval.v_string = NULL;
3456 }
3457}
3458
3459/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003460 * "expandcmd()" function
3461 * Expand all the special characters in a command string.
3462 */
3463 static void
3464f_expandcmd(typval_T *argvars, typval_T *rettv)
3465{
3466 exarg_T eap;
3467 char_u *cmdstr;
3468 char *errormsg = NULL;
3469
3470 rettv->v_type = VAR_STRING;
3471 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3472
3473 memset(&eap, 0, sizeof(eap));
3474 eap.cmd = cmdstr;
3475 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003476 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003477 eap.usefilter = FALSE;
3478 eap.nextcmd = NULL;
3479 eap.cmdidx = CMD_USER;
3480
3481 expand_filename(&eap, &cmdstr, &errormsg);
3482 if (errormsg != NULL && *errormsg != NUL)
3483 emsg(errormsg);
3484
3485 rettv->vval.v_string = cmdstr;
3486}
3487
3488/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489 * "extend(list, list [, idx])" function
3490 * "extend(dict, dict [, action])" function
3491 */
3492 static void
3493f_extend(typval_T *argvars, typval_T *rettv)
3494{
3495 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3496
3497 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3498 {
3499 list_T *l1, *l2;
3500 listitem_T *item;
3501 long before;
3502 int error = FALSE;
3503
3504 l1 = argvars[0].vval.v_list;
3505 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003506 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507 && l2 != NULL)
3508 {
3509 if (argvars[2].v_type != VAR_UNKNOWN)
3510 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003511 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003512 if (error)
3513 return; /* type error; errmsg already given */
3514
3515 if (before == l1->lv_len)
3516 item = NULL;
3517 else
3518 {
3519 item = list_find(l1, before);
3520 if (item == NULL)
3521 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003522 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523 return;
3524 }
3525 }
3526 }
3527 else
3528 item = NULL;
3529 list_extend(l1, l2, item);
3530
3531 copy_tv(&argvars[0], rettv);
3532 }
3533 }
3534 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3535 {
3536 dict_T *d1, *d2;
3537 char_u *action;
3538 int i;
3539
3540 d1 = argvars[0].vval.v_dict;
3541 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003542 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003543 && d2 != NULL)
3544 {
3545 /* Check the third argument. */
3546 if (argvars[2].v_type != VAR_UNKNOWN)
3547 {
3548 static char *(av[]) = {"keep", "force", "error"};
3549
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003550 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003551 if (action == NULL)
3552 return; /* type error; errmsg already given */
3553 for (i = 0; i < 3; ++i)
3554 if (STRCMP(action, av[i]) == 0)
3555 break;
3556 if (i == 3)
3557 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003558 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003559 return;
3560 }
3561 }
3562 else
3563 action = (char_u *)"force";
3564
3565 dict_extend(d1, d2, action);
3566
3567 copy_tv(&argvars[0], rettv);
3568 }
3569 }
3570 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003571 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572}
3573
3574/*
3575 * "feedkeys()" function
3576 */
3577 static void
3578f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3579{
3580 int remap = TRUE;
3581 int insert = FALSE;
3582 char_u *keys, *flags;
3583 char_u nbuf[NUMBUFLEN];
3584 int typed = FALSE;
3585 int execute = FALSE;
3586 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003587 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588 char_u *keys_esc;
3589
3590 /* This is not allowed in the sandbox. If the commands would still be
3591 * executed in the sandbox it would be OK, but it probably happens later,
3592 * when "sandbox" is no longer set. */
3593 if (check_secure())
3594 return;
3595
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003596 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003597
3598 if (argvars[1].v_type != VAR_UNKNOWN)
3599 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003600 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003601 for ( ; *flags != NUL; ++flags)
3602 {
3603 switch (*flags)
3604 {
3605 case 'n': remap = FALSE; break;
3606 case 'm': remap = TRUE; break;
3607 case 't': typed = TRUE; break;
3608 case 'i': insert = TRUE; break;
3609 case 'x': execute = TRUE; break;
3610 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003611 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003612 }
3613 }
3614 }
3615
3616 if (*keys != NUL || execute)
3617 {
3618 /* Need to escape K_SPECIAL and CSI before putting the string in the
3619 * typeahead buffer. */
3620 keys_esc = vim_strsave_escape_csi(keys);
3621 if (keys_esc != NULL)
3622 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003623 if (lowlevel)
3624 {
3625#ifdef USE_INPUT_BUF
3626 add_to_input_buf(keys, (int)STRLEN(keys));
3627#else
3628 emsg(_("E980: lowlevel input not supported"));
3629#endif
3630 }
3631 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003632 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003633 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003635 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003636#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003637 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003638#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003639 )
3640 typebuf_was_filled = TRUE;
3641 }
3642 vim_free(keys_esc);
3643
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644 if (execute)
3645 {
3646 int save_msg_scroll = msg_scroll;
3647
3648 /* Avoid a 1 second delay when the keys start Insert mode. */
3649 msg_scroll = FALSE;
3650
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003651 if (!dangerous)
3652 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003653 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003654 if (!dangerous)
3655 --ex_normal_busy;
3656
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003657 msg_scroll |= save_msg_scroll;
3658 }
3659 }
3660 }
3661}
3662
3663/*
3664 * "filereadable()" function
3665 */
3666 static void
3667f_filereadable(typval_T *argvars, typval_T *rettv)
3668{
3669 int fd;
3670 char_u *p;
3671 int n;
3672
3673#ifndef O_NONBLOCK
3674# define O_NONBLOCK 0
3675#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003676 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3678 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3679 {
3680 n = TRUE;
3681 close(fd);
3682 }
3683 else
3684 n = FALSE;
3685
3686 rettv->vval.v_number = n;
3687}
3688
3689/*
3690 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3691 * rights to write into.
3692 */
3693 static void
3694f_filewritable(typval_T *argvars, typval_T *rettv)
3695{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003696 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003697}
3698
3699 static void
3700findfilendir(
3701 typval_T *argvars UNUSED,
3702 typval_T *rettv,
3703 int find_what UNUSED)
3704{
3705#ifdef FEAT_SEARCHPATH
3706 char_u *fname;
3707 char_u *fresult = NULL;
3708 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3709 char_u *p;
3710 char_u pathbuf[NUMBUFLEN];
3711 int count = 1;
3712 int first = TRUE;
3713 int error = FALSE;
3714#endif
3715
3716 rettv->vval.v_string = NULL;
3717 rettv->v_type = VAR_STRING;
3718
3719#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003720 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003721
3722 if (argvars[1].v_type != VAR_UNKNOWN)
3723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003724 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725 if (p == NULL)
3726 error = TRUE;
3727 else
3728 {
3729 if (*p != NUL)
3730 path = p;
3731
3732 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003733 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003734 }
3735 }
3736
3737 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3738 error = TRUE;
3739
3740 if (*fname != NUL && !error)
3741 {
3742 do
3743 {
3744 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3745 vim_free(fresult);
3746 fresult = find_file_in_path_option(first ? fname : NULL,
3747 first ? (int)STRLEN(fname) : 0,
3748 0, first, path,
3749 find_what,
3750 curbuf->b_ffname,
3751 find_what == FINDFILE_DIR
3752 ? (char_u *)"" : curbuf->b_p_sua);
3753 first = FALSE;
3754
3755 if (fresult != NULL && rettv->v_type == VAR_LIST)
3756 list_append_string(rettv->vval.v_list, fresult, -1);
3757
3758 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3759 }
3760
3761 if (rettv->v_type == VAR_STRING)
3762 rettv->vval.v_string = fresult;
3763#endif
3764}
3765
3766/*
3767 * "filter()" function
3768 */
3769 static void
3770f_filter(typval_T *argvars, typval_T *rettv)
3771{
3772 filter_map(argvars, rettv, FALSE);
3773}
3774
3775/*
3776 * "finddir({fname}[, {path}[, {count}]])" function
3777 */
3778 static void
3779f_finddir(typval_T *argvars, typval_T *rettv)
3780{
3781 findfilendir(argvars, rettv, FINDFILE_DIR);
3782}
3783
3784/*
3785 * "findfile({fname}[, {path}[, {count}]])" function
3786 */
3787 static void
3788f_findfile(typval_T *argvars, typval_T *rettv)
3789{
3790 findfilendir(argvars, rettv, FINDFILE_FILE);
3791}
3792
3793#ifdef FEAT_FLOAT
3794/*
3795 * "float2nr({float})" function
3796 */
3797 static void
3798f_float2nr(typval_T *argvars, typval_T *rettv)
3799{
3800 float_T f = 0.0;
3801
3802 if (get_float_arg(argvars, &f) == OK)
3803 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003804 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003805 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003806 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003807 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808 else
3809 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810 }
3811}
3812
3813/*
3814 * "floor({float})" function
3815 */
3816 static void
3817f_floor(typval_T *argvars, typval_T *rettv)
3818{
3819 float_T f = 0.0;
3820
3821 rettv->v_type = VAR_FLOAT;
3822 if (get_float_arg(argvars, &f) == OK)
3823 rettv->vval.v_float = floor(f);
3824 else
3825 rettv->vval.v_float = 0.0;
3826}
3827
3828/*
3829 * "fmod()" function
3830 */
3831 static void
3832f_fmod(typval_T *argvars, typval_T *rettv)
3833{
3834 float_T fx = 0.0, fy = 0.0;
3835
3836 rettv->v_type = VAR_FLOAT;
3837 if (get_float_arg(argvars, &fx) == OK
3838 && get_float_arg(&argvars[1], &fy) == OK)
3839 rettv->vval.v_float = fmod(fx, fy);
3840 else
3841 rettv->vval.v_float = 0.0;
3842}
3843#endif
3844
3845/*
3846 * "fnameescape({string})" function
3847 */
3848 static void
3849f_fnameescape(typval_T *argvars, typval_T *rettv)
3850{
3851 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003852 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003853 rettv->v_type = VAR_STRING;
3854}
3855
3856/*
3857 * "fnamemodify({fname}, {mods})" function
3858 */
3859 static void
3860f_fnamemodify(typval_T *argvars, typval_T *rettv)
3861{
3862 char_u *fname;
3863 char_u *mods;
3864 int usedlen = 0;
3865 int len;
3866 char_u *fbuf = NULL;
3867 char_u buf[NUMBUFLEN];
3868
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003869 fname = tv_get_string_chk(&argvars[0]);
3870 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 if (fname == NULL || mods == NULL)
3872 fname = NULL;
3873 else
3874 {
3875 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003876 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003877 }
3878
3879 rettv->v_type = VAR_STRING;
3880 if (fname == NULL)
3881 rettv->vval.v_string = NULL;
3882 else
3883 rettv->vval.v_string = vim_strnsave(fname, len);
3884 vim_free(fbuf);
3885}
3886
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003887/*
3888 * "foldclosed()" function
3889 */
3890 static void
3891foldclosed_both(
3892 typval_T *argvars UNUSED,
3893 typval_T *rettv,
3894 int end UNUSED)
3895{
3896#ifdef FEAT_FOLDING
3897 linenr_T lnum;
3898 linenr_T first, last;
3899
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003900 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003901 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3902 {
3903 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3904 {
3905 if (end)
3906 rettv->vval.v_number = (varnumber_T)last;
3907 else
3908 rettv->vval.v_number = (varnumber_T)first;
3909 return;
3910 }
3911 }
3912#endif
3913 rettv->vval.v_number = -1;
3914}
3915
3916/*
3917 * "foldclosed()" function
3918 */
3919 static void
3920f_foldclosed(typval_T *argvars, typval_T *rettv)
3921{
3922 foldclosed_both(argvars, rettv, FALSE);
3923}
3924
3925/*
3926 * "foldclosedend()" function
3927 */
3928 static void
3929f_foldclosedend(typval_T *argvars, typval_T *rettv)
3930{
3931 foldclosed_both(argvars, rettv, TRUE);
3932}
3933
3934/*
3935 * "foldlevel()" function
3936 */
3937 static void
3938f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3939{
3940#ifdef FEAT_FOLDING
3941 linenr_T lnum;
3942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003943 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3945 rettv->vval.v_number = foldLevel(lnum);
3946#endif
3947}
3948
3949/*
3950 * "foldtext()" function
3951 */
3952 static void
3953f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3954{
3955#ifdef FEAT_FOLDING
3956 linenr_T foldstart;
3957 linenr_T foldend;
3958 char_u *dashes;
3959 linenr_T lnum;
3960 char_u *s;
3961 char_u *r;
3962 int len;
3963 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003964 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965#endif
3966
3967 rettv->v_type = VAR_STRING;
3968 rettv->vval.v_string = NULL;
3969#ifdef FEAT_FOLDING
3970 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3971 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3972 dashes = get_vim_var_str(VV_FOLDDASHES);
3973 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3974 && dashes != NULL)
3975 {
3976 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003977 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003978 if (!linewhite(lnum))
3979 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003980
3981 /* Find interesting text in this line. */
3982 s = skipwhite(ml_get(lnum));
3983 /* skip C comment-start */
3984 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3985 {
3986 s = skipwhite(s + 2);
3987 if (*skipwhite(s) == NUL
3988 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3989 {
3990 s = skipwhite(ml_get(lnum + 1));
3991 if (*s == '*')
3992 s = skipwhite(s + 1);
3993 }
3994 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003995 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003996 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003997 r = alloc(STRLEN(txt)
3998 + STRLEN(dashes) // for %s
3999 + 20 // for %3ld
4000 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004001 if (r != NULL)
4002 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004003 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004004 len = (int)STRLEN(r);
4005 STRCAT(r, s);
4006 /* remove 'foldmarker' and 'commentstring' */
4007 foldtext_cleanup(r + len);
4008 rettv->vval.v_string = r;
4009 }
4010 }
4011#endif
4012}
4013
4014/*
4015 * "foldtextresult(lnum)" function
4016 */
4017 static void
4018f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4019{
4020#ifdef FEAT_FOLDING
4021 linenr_T lnum;
4022 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004023 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004024 foldinfo_T foldinfo;
4025 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004026 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027#endif
4028
4029 rettv->v_type = VAR_STRING;
4030 rettv->vval.v_string = NULL;
4031#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004032 if (entered)
4033 return; /* reject recursive use */
4034 entered = TRUE;
4035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004036 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004037 /* treat illegal types and illegal string values for {lnum} the same */
4038 if (lnum < 0)
4039 lnum = 0;
4040 fold_count = foldedCount(curwin, lnum, &foldinfo);
4041 if (fold_count > 0)
4042 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004043 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4044 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004045 if (text == buf)
4046 text = vim_strsave(text);
4047 rettv->vval.v_string = text;
4048 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004049
4050 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004051#endif
4052}
4053
4054/*
4055 * "foreground()" function
4056 */
4057 static void
4058f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4059{
4060#ifdef FEAT_GUI
4061 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004062 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004063 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02004064 return;
4065 }
4066#endif
4067#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004069#endif
4070}
4071
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004073common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004074{
4075 char_u *s;
4076 char_u *name;
4077 int use_string = FALSE;
4078 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004079 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080
4081 if (argvars[0].v_type == VAR_FUNC)
4082 {
4083 /* function(MyFunc, [arg], dict) */
4084 s = argvars[0].vval.v_string;
4085 }
4086 else if (argvars[0].v_type == VAR_PARTIAL
4087 && argvars[0].vval.v_partial != NULL)
4088 {
4089 /* function(dict.MyFunc, [arg]) */
4090 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004091 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004092 }
4093 else
4094 {
4095 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004096 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004097 use_string = TRUE;
4098 }
4099
Bram Moolenaar843b8842016-08-21 14:36:15 +02004100 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004101 {
4102 name = s;
4103 trans_name = trans_function_name(&name, FALSE,
4104 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4105 if (*name != NUL)
4106 s = NULL;
4107 }
4108
Bram Moolenaar843b8842016-08-21 14:36:15 +02004109 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4110 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004111 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004113 else if (trans_name != NULL && (is_funcref
4114 ? find_func(trans_name) == NULL
4115 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004116 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004117 else
4118 {
4119 int dict_idx = 0;
4120 int arg_idx = 0;
4121 list_T *list = NULL;
4122
4123 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4124 {
4125 char sid_buf[25];
4126 int off = *s == 's' ? 2 : 5;
4127
4128 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4129 * also be called from another script. Using trans_function_name()
4130 * would also work, but some plugins depend on the name being
4131 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004132 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004133 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134 if (name != NULL)
4135 {
4136 STRCPY(name, sid_buf);
4137 STRCAT(name, s + off);
4138 }
4139 }
4140 else
4141 name = vim_strsave(s);
4142
4143 if (argvars[1].v_type != VAR_UNKNOWN)
4144 {
4145 if (argvars[2].v_type != VAR_UNKNOWN)
4146 {
4147 /* function(name, [args], dict) */
4148 arg_idx = 1;
4149 dict_idx = 2;
4150 }
4151 else if (argvars[1].v_type == VAR_DICT)
4152 /* function(name, dict) */
4153 dict_idx = 1;
4154 else
4155 /* function(name, [args]) */
4156 arg_idx = 1;
4157 if (dict_idx > 0)
4158 {
4159 if (argvars[dict_idx].v_type != VAR_DICT)
4160 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004161 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004162 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004163 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004164 }
4165 if (argvars[dict_idx].vval.v_dict == NULL)
4166 dict_idx = 0;
4167 }
4168 if (arg_idx > 0)
4169 {
4170 if (argvars[arg_idx].v_type != VAR_LIST)
4171 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004172 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004173 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004174 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004175 }
4176 list = argvars[arg_idx].vval.v_list;
4177 if (list == NULL || list->lv_len == 0)
4178 arg_idx = 0;
4179 }
4180 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004181 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004182 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004183 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004184
4185 /* result is a VAR_PARTIAL */
4186 if (pt == NULL)
4187 vim_free(name);
4188 else
4189 {
4190 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4191 {
4192 listitem_T *li;
4193 int i = 0;
4194 int arg_len = 0;
4195 int lv_len = 0;
4196
4197 if (arg_pt != NULL)
4198 arg_len = arg_pt->pt_argc;
4199 if (list != NULL)
4200 lv_len = list->lv_len;
4201 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004202 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 if (pt->pt_argv == NULL)
4204 {
4205 vim_free(pt);
4206 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004207 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004208 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004209 for (i = 0; i < arg_len; i++)
4210 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4211 if (lv_len > 0)
4212 for (li = list->lv_first; li != NULL;
4213 li = li->li_next)
4214 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004215 }
4216
4217 /* For "function(dict.func, [], dict)" and "func" is a partial
4218 * use "dict". That is backwards compatible. */
4219 if (dict_idx > 0)
4220 {
4221 /* The dict is bound explicitly, pt_auto is FALSE. */
4222 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4223 ++pt->pt_dict->dv_refcount;
4224 }
4225 else if (arg_pt != NULL)
4226 {
4227 /* If the dict was bound automatically the result is also
4228 * bound automatically. */
4229 pt->pt_dict = arg_pt->pt_dict;
4230 pt->pt_auto = arg_pt->pt_auto;
4231 if (pt->pt_dict != NULL)
4232 ++pt->pt_dict->dv_refcount;
4233 }
4234
4235 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004236 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4237 {
4238 pt->pt_func = arg_pt->pt_func;
4239 func_ptr_ref(pt->pt_func);
4240 vim_free(name);
4241 }
4242 else if (is_funcref)
4243 {
4244 pt->pt_func = find_func(trans_name);
4245 func_ptr_ref(pt->pt_func);
4246 vim_free(name);
4247 }
4248 else
4249 {
4250 pt->pt_name = name;
4251 func_ref(name);
4252 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004253 }
4254 rettv->v_type = VAR_PARTIAL;
4255 rettv->vval.v_partial = pt;
4256 }
4257 else
4258 {
4259 /* result is a VAR_FUNC */
4260 rettv->v_type = VAR_FUNC;
4261 rettv->vval.v_string = name;
4262 func_ref(name);
4263 }
4264 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004265theend:
4266 vim_free(trans_name);
4267}
4268
4269/*
4270 * "funcref()" function
4271 */
4272 static void
4273f_funcref(typval_T *argvars, typval_T *rettv)
4274{
4275 common_function(argvars, rettv, TRUE);
4276}
4277
4278/*
4279 * "function()" function
4280 */
4281 static void
4282f_function(typval_T *argvars, typval_T *rettv)
4283{
4284 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004285}
4286
4287/*
4288 * "garbagecollect()" function
4289 */
4290 static void
4291f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4292{
4293 /* This is postponed until we are back at the toplevel, because we may be
4294 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4295 want_garbage_collect = TRUE;
4296
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004297 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 garbage_collect_at_exit = TRUE;
4299}
4300
4301/*
4302 * "get()" function
4303 */
4304 static void
4305f_get(typval_T *argvars, typval_T *rettv)
4306{
4307 listitem_T *li;
4308 list_T *l;
4309 dictitem_T *di;
4310 dict_T *d;
4311 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004312 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004313
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004314 if (argvars[0].v_type == VAR_BLOB)
4315 {
4316 int error = FALSE;
4317 int idx = tv_get_number_chk(&argvars[1], &error);
4318
4319 if (!error)
4320 {
4321 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004322 if (idx < 0)
4323 idx = blob_len(argvars[0].vval.v_blob) + idx;
4324 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4325 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004326 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004327 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004328 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004329 tv = rettv;
4330 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004331 }
4332 }
4333 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004334 {
4335 if ((l = argvars[0].vval.v_list) != NULL)
4336 {
4337 int error = FALSE;
4338
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004339 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004340 if (!error && li != NULL)
4341 tv = &li->li_tv;
4342 }
4343 }
4344 else if (argvars[0].v_type == VAR_DICT)
4345 {
4346 if ((d = argvars[0].vval.v_dict) != NULL)
4347 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004348 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004349 if (di != NULL)
4350 tv = &di->di_tv;
4351 }
4352 }
4353 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4354 {
4355 partial_T *pt;
4356 partial_T fref_pt;
4357
4358 if (argvars[0].v_type == VAR_PARTIAL)
4359 pt = argvars[0].vval.v_partial;
4360 else
4361 {
4362 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4363 fref_pt.pt_name = argvars[0].vval.v_string;
4364 pt = &fref_pt;
4365 }
4366
4367 if (pt != NULL)
4368 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004369 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004370 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371
4372 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4373 {
4374 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004375 n = partial_name(pt);
4376 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004377 rettv->vval.v_string = NULL;
4378 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004379 {
4380 rettv->vval.v_string = vim_strsave(n);
4381 if (rettv->v_type == VAR_FUNC)
4382 func_ref(rettv->vval.v_string);
4383 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 }
4385 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004386 {
4387 what_is_dict = TRUE;
4388 if (pt->pt_dict != NULL)
4389 rettv_dict_set(rettv, pt->pt_dict);
4390 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004391 else if (STRCMP(what, "args") == 0)
4392 {
4393 rettv->v_type = VAR_LIST;
4394 if (rettv_list_alloc(rettv) == OK)
4395 {
4396 int i;
4397
4398 for (i = 0; i < pt->pt_argc; ++i)
4399 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4400 }
4401 }
4402 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004403 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004404
4405 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4406 // third argument
4407 if (!what_is_dict)
4408 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004409 }
4410 }
4411 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004412 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004413
4414 if (tv == NULL)
4415 {
4416 if (argvars[2].v_type != VAR_UNKNOWN)
4417 copy_tv(&argvars[2], rettv);
4418 }
4419 else
4420 copy_tv(tv, rettv);
4421}
4422
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004423/*
4424 * Returns buffer options, variables and other attributes in a dictionary.
4425 */
4426 static dict_T *
4427get_buffer_info(buf_T *buf)
4428{
4429 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004430 tabpage_T *tp;
4431 win_T *wp;
4432 list_T *windows;
4433
4434 dict = dict_alloc();
4435 if (dict == NULL)
4436 return NULL;
4437
Bram Moolenaare0be1672018-07-08 16:50:37 +02004438 dict_add_number(dict, "bufnr", buf->b_fnum);
4439 dict_add_string(dict, "name", buf->b_ffname);
4440 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4441 : buflist_findlnum(buf));
4442 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4443 dict_add_number(dict, "listed", buf->b_p_bl);
4444 dict_add_number(dict, "changed", bufIsChanged(buf));
4445 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4446 dict_add_number(dict, "hidden",
4447 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004448
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004449 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004450 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004451
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004452 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004453 windows = list_alloc();
4454 if (windows != NULL)
4455 {
4456 FOR_ALL_TAB_WINDOWS(tp, wp)
4457 if (wp->w_buffer == buf)
4458 list_append_number(windows, (varnumber_T)wp->w_id);
4459 dict_add_list(dict, "windows", windows);
4460 }
4461
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004462#ifdef FEAT_TEXT_PROP
4463 // List of popup windows displaying this buffer
4464 windows = list_alloc();
4465 if (windows != NULL)
4466 {
4467 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4468 if (wp->w_buffer == buf)
4469 list_append_number(windows, (varnumber_T)wp->w_id);
4470 FOR_ALL_TABPAGES(tp)
4471 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4472 if (wp->w_buffer == buf)
4473 list_append_number(windows, (varnumber_T)wp->w_id);
4474
4475 dict_add_list(dict, "popups", windows);
4476 }
4477#endif
4478
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004479#ifdef FEAT_SIGNS
4480 if (buf->b_signlist != NULL)
4481 {
4482 /* List of signs placed in this buffer */
4483 list_T *signs = list_alloc();
4484 if (signs != NULL)
4485 {
4486 get_buffer_signs(buf, signs);
4487 dict_add_list(dict, "signs", signs);
4488 }
4489 }
4490#endif
4491
4492 return dict;
4493}
4494
4495/*
4496 * "getbufinfo()" function
4497 */
4498 static void
4499f_getbufinfo(typval_T *argvars, typval_T *rettv)
4500{
4501 buf_T *buf = NULL;
4502 buf_T *argbuf = NULL;
4503 dict_T *d;
4504 int filtered = FALSE;
4505 int sel_buflisted = FALSE;
4506 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004507 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004508
4509 if (rettv_list_alloc(rettv) != OK)
4510 return;
4511
4512 /* List of all the buffers or selected buffers */
4513 if (argvars[0].v_type == VAR_DICT)
4514 {
4515 dict_T *sel_d = argvars[0].vval.v_dict;
4516
4517 if (sel_d != NULL)
4518 {
4519 dictitem_T *di;
4520
4521 filtered = TRUE;
4522
4523 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004524 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004525 sel_buflisted = TRUE;
4526
4527 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004528 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004529 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004530
4531 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004532 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004533 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004534 }
4535 }
4536 else if (argvars[0].v_type != VAR_UNKNOWN)
4537 {
4538 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004539 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004540 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004541 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004542 --emsg_off;
4543 if (argbuf == NULL)
4544 return;
4545 }
4546
4547 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004548 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004549 {
4550 if (argbuf != NULL && argbuf != buf)
4551 continue;
4552 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004553 || (sel_buflisted && !buf->b_p_bl)
4554 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004555 continue;
4556
4557 d = get_buffer_info(buf);
4558 if (d != NULL)
4559 list_append_dict(rettv->vval.v_list, d);
4560 if (argbuf != NULL)
4561 return;
4562 }
4563}
4564
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004565/*
4566 * Get line or list of lines from buffer "buf" into "rettv".
4567 * Return a range (from start to end) of lines in rettv from the specified
4568 * buffer.
4569 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4570 */
4571 static void
4572get_buffer_lines(
4573 buf_T *buf,
4574 linenr_T start,
4575 linenr_T end,
4576 int retlist,
4577 typval_T *rettv)
4578{
4579 char_u *p;
4580
4581 rettv->v_type = VAR_STRING;
4582 rettv->vval.v_string = NULL;
4583 if (retlist && rettv_list_alloc(rettv) == FAIL)
4584 return;
4585
4586 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4587 return;
4588
4589 if (!retlist)
4590 {
4591 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4592 p = ml_get_buf(buf, start, FALSE);
4593 else
4594 p = (char_u *)"";
4595 rettv->vval.v_string = vim_strsave(p);
4596 }
4597 else
4598 {
4599 if (end < start)
4600 return;
4601
4602 if (start < 1)
4603 start = 1;
4604 if (end > buf->b_ml.ml_line_count)
4605 end = buf->b_ml.ml_line_count;
4606 while (start <= end)
4607 if (list_append_string(rettv->vval.v_list,
4608 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4609 break;
4610 }
4611}
4612
4613/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004614 * "getbufline()" function
4615 */
4616 static void
4617f_getbufline(typval_T *argvars, typval_T *rettv)
4618{
4619 linenr_T lnum;
4620 linenr_T end;
4621 buf_T *buf;
4622
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004623 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004624 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004625 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004626 --emsg_off;
4627
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004628 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004629 if (argvars[2].v_type == VAR_UNKNOWN)
4630 end = lnum;
4631 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004632 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004633
4634 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4635}
4636
4637/*
4638 * "getbufvar()" function
4639 */
4640 static void
4641f_getbufvar(typval_T *argvars, typval_T *rettv)
4642{
4643 buf_T *buf;
4644 buf_T *save_curbuf;
4645 char_u *varname;
4646 dictitem_T *v;
4647 int done = FALSE;
4648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004649 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4650 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004651 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004652 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004653
4654 rettv->v_type = VAR_STRING;
4655 rettv->vval.v_string = NULL;
4656
4657 if (buf != NULL && varname != NULL)
4658 {
4659 /* set curbuf to be our buf, temporarily */
4660 save_curbuf = curbuf;
4661 curbuf = buf;
4662
Bram Moolenaar30567352016-08-27 21:25:44 +02004663 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004665 if (varname[1] == NUL)
4666 {
4667 /* get all buffer-local options in a dict */
4668 dict_T *opts = get_winbuf_options(TRUE);
4669
4670 if (opts != NULL)
4671 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004672 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004673 done = TRUE;
4674 }
4675 }
4676 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4677 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004678 done = TRUE;
4679 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680 else
4681 {
4682 /* Look up the variable. */
4683 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4684 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4685 'b', varname, FALSE);
4686 if (v != NULL)
4687 {
4688 copy_tv(&v->di_tv, rettv);
4689 done = TRUE;
4690 }
4691 }
4692
4693 /* restore previous notion of curbuf */
4694 curbuf = save_curbuf;
4695 }
4696
4697 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4698 /* use the default value */
4699 copy_tv(&argvars[2], rettv);
4700
4701 --emsg_off;
4702}
4703
4704/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004705 * "getchangelist()" function
4706 */
4707 static void
4708f_getchangelist(typval_T *argvars, typval_T *rettv)
4709{
4710#ifdef FEAT_JUMPLIST
4711 buf_T *buf;
4712 int i;
4713 list_T *l;
4714 dict_T *d;
4715#endif
4716
4717 if (rettv_list_alloc(rettv) != OK)
4718 return;
4719
4720#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004721 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004722 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004723 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004724 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004725 if (buf == NULL)
4726 return;
4727
4728 l = list_alloc();
4729 if (l == NULL)
4730 return;
4731
4732 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4733 return;
4734 /*
4735 * The current window change list index tracks only the position in the
4736 * current buffer change list. For other buffers, use the change list
4737 * length as the current index.
4738 */
4739 list_append_number(rettv->vval.v_list,
4740 (varnumber_T)((buf == curwin->w_buffer)
4741 ? curwin->w_changelistidx : buf->b_changelistlen));
4742
4743 for (i = 0; i < buf->b_changelistlen; ++i)
4744 {
4745 if (buf->b_changelist[i].lnum == 0)
4746 continue;
4747 if ((d = dict_alloc()) == NULL)
4748 return;
4749 if (list_append_dict(l, d) == FAIL)
4750 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004751 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4752 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004753 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004754 }
4755#endif
4756}
4757/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758 * "getchar()" function
4759 */
4760 static void
4761f_getchar(typval_T *argvars, typval_T *rettv)
4762{
4763 varnumber_T n;
4764 int error = FALSE;
4765
Bram Moolenaar84d93902018-09-11 20:10:20 +02004766#ifdef MESSAGE_QUEUE
4767 // vpeekc() used to check for messages, but that caused problems, invoking
4768 // a callback where it was not expected. Some plugins use getchar(1) in a
4769 // loop to await a message, therefore make sure we check for messages here.
4770 parse_queued_messages();
4771#endif
4772
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004773 /* Position the cursor. Needed after a message that ends in a space. */
4774 windgoto(msg_row, msg_col);
4775
4776 ++no_mapping;
4777 ++allow_keys;
4778 for (;;)
4779 {
4780 if (argvars[0].v_type == VAR_UNKNOWN)
4781 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004782 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004783 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004784 /* getchar(1): only check if char avail */
4785 n = vpeekc_any();
4786 else if (error || vpeekc_any() == NUL)
4787 /* illegal argument or getchar(0) and no char avail: return zero */
4788 n = 0;
4789 else
4790 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004791 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004792
4793 if (n == K_IGNORE)
4794 continue;
4795 break;
4796 }
4797 --no_mapping;
4798 --allow_keys;
4799
4800 set_vim_var_nr(VV_MOUSE_WIN, 0);
4801 set_vim_var_nr(VV_MOUSE_WINID, 0);
4802 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4803 set_vim_var_nr(VV_MOUSE_COL, 0);
4804
4805 rettv->vval.v_number = n;
4806 if (IS_SPECIAL(n) || mod_mask != 0)
4807 {
4808 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4809 int i = 0;
4810
4811 /* Turn a special key into three bytes, plus modifier. */
4812 if (mod_mask != 0)
4813 {
4814 temp[i++] = K_SPECIAL;
4815 temp[i++] = KS_MODIFIER;
4816 temp[i++] = mod_mask;
4817 }
4818 if (IS_SPECIAL(n))
4819 {
4820 temp[i++] = K_SPECIAL;
4821 temp[i++] = K_SECOND(n);
4822 temp[i++] = K_THIRD(n);
4823 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004824 else if (has_mbyte)
4825 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826 else
4827 temp[i++] = n;
4828 temp[i++] = NUL;
4829 rettv->v_type = VAR_STRING;
4830 rettv->vval.v_string = vim_strsave(temp);
4831
4832#ifdef FEAT_MOUSE
4833 if (is_mouse_key(n))
4834 {
4835 int row = mouse_row;
4836 int col = mouse_col;
4837 win_T *win;
4838 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004840 int winnr = 1;
4841
4842 if (row >= 0 && col >= 0)
4843 {
4844 /* Find the window at the mouse coordinates and compute the
4845 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004846 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004847 if (win == NULL)
4848 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004849 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004850# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004851 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004852 winnr = 0;
4853 else
4854# endif
4855 for (wp = firstwin; wp != win && wp != NULL;
4856 wp = wp->w_next)
4857 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004858 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4859 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4860 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4861 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4862 }
4863 }
4864#endif
4865 }
4866}
4867
4868/*
4869 * "getcharmod()" function
4870 */
4871 static void
4872f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4873{
4874 rettv->vval.v_number = mod_mask;
4875}
4876
4877/*
4878 * "getcharsearch()" function
4879 */
4880 static void
4881f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4882{
4883 if (rettv_dict_alloc(rettv) != FAIL)
4884 {
4885 dict_T *dict = rettv->vval.v_dict;
4886
Bram Moolenaare0be1672018-07-08 16:50:37 +02004887 dict_add_string(dict, "char", last_csearch());
4888 dict_add_number(dict, "forward", last_csearch_forward());
4889 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004890 }
4891}
4892
4893/*
4894 * "getcmdline()" function
4895 */
4896 static void
4897f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4898{
4899 rettv->v_type = VAR_STRING;
4900 rettv->vval.v_string = get_cmdline_str();
4901}
4902
4903/*
4904 * "getcmdpos()" function
4905 */
4906 static void
4907f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4908{
4909 rettv->vval.v_number = get_cmdline_pos() + 1;
4910}
4911
4912/*
4913 * "getcmdtype()" function
4914 */
4915 static void
4916f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4917{
4918 rettv->v_type = VAR_STRING;
4919 rettv->vval.v_string = alloc(2);
4920 if (rettv->vval.v_string != NULL)
4921 {
4922 rettv->vval.v_string[0] = get_cmdline_type();
4923 rettv->vval.v_string[1] = NUL;
4924 }
4925}
4926
4927/*
4928 * "getcmdwintype()" function
4929 */
4930 static void
4931f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4932{
4933 rettv->v_type = VAR_STRING;
4934 rettv->vval.v_string = NULL;
4935#ifdef FEAT_CMDWIN
4936 rettv->vval.v_string = alloc(2);
4937 if (rettv->vval.v_string != NULL)
4938 {
4939 rettv->vval.v_string[0] = cmdwin_type;
4940 rettv->vval.v_string[1] = NUL;
4941 }
4942#endif
4943}
4944
4945#if defined(FEAT_CMDL_COMPL)
4946/*
4947 * "getcompletion()" function
4948 */
4949 static void
4950f_getcompletion(typval_T *argvars, typval_T *rettv)
4951{
4952 char_u *pat;
4953 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004954 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004955 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4956 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004957
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004958 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004959 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004960
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961 if (p_wic)
4962 options |= WILD_ICASE;
4963
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004964 /* For filtered results, 'wildignore' is used */
4965 if (!filtered)
4966 options |= WILD_KEEP_ALL;
4967
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004968 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004969 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004971 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972 if (xpc.xp_context == EXPAND_NOTHING)
4973 {
4974 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004975 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004977 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004978 return;
4979 }
4980
4981# if defined(FEAT_MENU)
4982 if (xpc.xp_context == EXPAND_MENUS)
4983 {
4984 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4985 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4986 }
4987# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004988#ifdef FEAT_CSCOPE
4989 if (xpc.xp_context == EXPAND_CSCOPE)
4990 {
4991 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4992 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4993 }
4994#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004995#ifdef FEAT_SIGNS
4996 if (xpc.xp_context == EXPAND_SIGN)
4997 {
4998 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4999 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5000 }
5001#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002
5003 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5004 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5005 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005006 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005007
5008 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5009
5010 for (i = 0; i < xpc.xp_numfiles; i++)
5011 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5012 }
5013 vim_free(pat);
5014 ExpandCleanup(&xpc);
5015}
5016#endif
5017
5018/*
5019 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005020 *
5021 * Return the current working directory of a window in a tab page.
5022 * First optional argument 'winnr' is the window number or -1 and the second
5023 * optional argument 'tabnr' is the tab page number.
5024 *
5025 * If no arguments are supplied, then return the directory of the current
5026 * window.
5027 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
5028 * the specified window.
5029 * If 'winnr' is 0 then return the directory of the current window.
5030 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
5031 * directory of the specified tab page. Otherwise return the directory of the
5032 * specified window in the specified tab page.
5033 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 */
5035 static void
5036f_getcwd(typval_T *argvars, typval_T *rettv)
5037{
5038 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005039 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005041 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042
5043 rettv->v_type = VAR_STRING;
5044 rettv->vval.v_string = NULL;
5045
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005046 if (argvars[0].v_type == VAR_NUMBER
5047 && argvars[0].vval.v_number == -1
5048 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01005049 global = TRUE;
5050 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005051 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01005052
5053 if (wp != NULL && wp->w_localdir != NULL)
5054 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005055 else if (tp != NULL && tp->tp_localdir != NULL)
5056 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
5057 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005058 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005059 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 rettv->vval.v_string = vim_strsave(globaldir);
5061 else
5062 {
5063 cwd = alloc(MAXPATHL);
5064 if (cwd != NULL)
5065 {
5066 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5067 rettv->vval.v_string = vim_strsave(cwd);
5068 vim_free(cwd);
5069 }
5070 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005072#ifdef BACKSLASH_IN_FILENAME
5073 if (rettv->vval.v_string != NULL)
5074 slash_adjust(rettv->vval.v_string);
5075#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076}
5077
5078/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02005079 * "getenv()" function
5080 */
5081 static void
5082f_getenv(typval_T *argvars, typval_T *rettv)
5083{
5084 int mustfree = FALSE;
5085 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
5086
5087 if (p == NULL)
5088 {
5089 rettv->v_type = VAR_SPECIAL;
5090 rettv->vval.v_number = VVAL_NULL;
5091 return;
5092 }
5093 if (!mustfree)
5094 p = vim_strsave(p);
5095 rettv->vval.v_string = p;
5096 rettv->v_type = VAR_STRING;
5097}
5098
5099/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005100 * "getfontname()" function
5101 */
5102 static void
5103f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5104{
5105 rettv->v_type = VAR_STRING;
5106 rettv->vval.v_string = NULL;
5107#ifdef FEAT_GUI
5108 if (gui.in_use)
5109 {
5110 GuiFont font;
5111 char_u *name = NULL;
5112
5113 if (argvars[0].v_type == VAR_UNKNOWN)
5114 {
5115 /* Get the "Normal" font. Either the name saved by
5116 * hl_set_font_name() or from the font ID. */
5117 font = gui.norm_font;
5118 name = hl_get_font_name();
5119 }
5120 else
5121 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005122 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005123 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5124 return;
5125 font = gui_mch_get_font(name, FALSE);
5126 if (font == NOFONT)
5127 return; /* Invalid font name, return empty string. */
5128 }
5129 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5130 if (argvars[0].v_type != VAR_UNKNOWN)
5131 gui_mch_free_font(font);
5132 }
5133#endif
5134}
5135
5136/*
5137 * "getfperm({fname})" function
5138 */
5139 static void
5140f_getfperm(typval_T *argvars, typval_T *rettv)
5141{
5142 char_u *fname;
5143 stat_T st;
5144 char_u *perm = NULL;
5145 char_u flags[] = "rwx";
5146 int i;
5147
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005148 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005149
5150 rettv->v_type = VAR_STRING;
5151 if (mch_stat((char *)fname, &st) >= 0)
5152 {
5153 perm = vim_strsave((char_u *)"---------");
5154 if (perm != NULL)
5155 {
5156 for (i = 0; i < 9; i++)
5157 {
5158 if (st.st_mode & (1 << (8 - i)))
5159 perm[i] = flags[i % 3];
5160 }
5161 }
5162 }
5163 rettv->vval.v_string = perm;
5164}
5165
5166/*
5167 * "getfsize({fname})" function
5168 */
5169 static void
5170f_getfsize(typval_T *argvars, typval_T *rettv)
5171{
5172 char_u *fname;
5173 stat_T st;
5174
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005175 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005176
5177 rettv->v_type = VAR_NUMBER;
5178
5179 if (mch_stat((char *)fname, &st) >= 0)
5180 {
5181 if (mch_isdir(fname))
5182 rettv->vval.v_number = 0;
5183 else
5184 {
5185 rettv->vval.v_number = (varnumber_T)st.st_size;
5186
5187 /* non-perfect check for overflow */
5188 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5189 rettv->vval.v_number = -2;
5190 }
5191 }
5192 else
5193 rettv->vval.v_number = -1;
5194}
5195
5196/*
5197 * "getftime({fname})" function
5198 */
5199 static void
5200f_getftime(typval_T *argvars, typval_T *rettv)
5201{
5202 char_u *fname;
5203 stat_T st;
5204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005205 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005206
5207 if (mch_stat((char *)fname, &st) >= 0)
5208 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5209 else
5210 rettv->vval.v_number = -1;
5211}
5212
5213/*
5214 * "getftype({fname})" function
5215 */
5216 static void
5217f_getftype(typval_T *argvars, typval_T *rettv)
5218{
5219 char_u *fname;
5220 stat_T st;
5221 char_u *type = NULL;
5222 char *t;
5223
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005224 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005225
5226 rettv->v_type = VAR_STRING;
5227 if (mch_lstat((char *)fname, &st) >= 0)
5228 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005229 if (S_ISREG(st.st_mode))
5230 t = "file";
5231 else if (S_ISDIR(st.st_mode))
5232 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233 else if (S_ISLNK(st.st_mode))
5234 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235 else if (S_ISBLK(st.st_mode))
5236 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005237 else if (S_ISCHR(st.st_mode))
5238 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005239 else if (S_ISFIFO(st.st_mode))
5240 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005241 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005242 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005243 else
5244 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005245 type = vim_strsave((char_u *)t);
5246 }
5247 rettv->vval.v_string = type;
5248}
5249
5250/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005251 * "getjumplist()" function
5252 */
5253 static void
5254f_getjumplist(typval_T *argvars, typval_T *rettv)
5255{
5256#ifdef FEAT_JUMPLIST
5257 win_T *wp;
5258 int i;
5259 list_T *l;
5260 dict_T *d;
5261#endif
5262
5263 if (rettv_list_alloc(rettv) != OK)
5264 return;
5265
5266#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005267 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005268 if (wp == NULL)
5269 return;
5270
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005271 cleanup_jumplist(wp, TRUE);
5272
Bram Moolenaar4f505882018-02-10 21:06:32 +01005273 l = list_alloc();
5274 if (l == NULL)
5275 return;
5276
5277 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5278 return;
5279 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5280
5281 for (i = 0; i < wp->w_jumplistlen; ++i)
5282 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005283 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5284 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005285 if ((d = dict_alloc()) == NULL)
5286 return;
5287 if (list_append_dict(l, d) == FAIL)
5288 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005289 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5290 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005291 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005292 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005293 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005294 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005295 }
5296#endif
5297}
5298
5299/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300 * "getline(lnum, [end])" function
5301 */
5302 static void
5303f_getline(typval_T *argvars, typval_T *rettv)
5304{
5305 linenr_T lnum;
5306 linenr_T end;
5307 int retlist;
5308
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005309 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005310 if (argvars[1].v_type == VAR_UNKNOWN)
5311 {
5312 end = 0;
5313 retlist = FALSE;
5314 }
5315 else
5316 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005317 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 retlist = TRUE;
5319 }
5320
5321 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5322}
5323
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005324#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005325 static void
5326get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5327{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005328 if (what_arg->v_type == VAR_UNKNOWN)
5329 {
5330 if (rettv_list_alloc(rettv) == OK)
5331 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005332 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005333 }
5334 else
5335 {
5336 if (rettv_dict_alloc(rettv) == OK)
5337 if (is_qf || (wp != NULL))
5338 {
5339 if (what_arg->v_type == VAR_DICT)
5340 {
5341 dict_T *d = what_arg->vval.v_dict;
5342
5343 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005344 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005345 }
5346 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005347 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005348 }
5349 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005350}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005351#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005352
5353/*
5354 * "getloclist()" function
5355 */
5356 static void
5357f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5358{
5359#ifdef FEAT_QUICKFIX
5360 win_T *wp;
5361
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005362 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005363 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5364#endif
5365}
5366
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005367/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005368 * "getpid()" function
5369 */
5370 static void
5371f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5372{
5373 rettv->vval.v_number = mch_get_pid();
5374}
5375
5376 static void
5377getpos_both(
5378 typval_T *argvars,
5379 typval_T *rettv,
5380 int getcurpos)
5381{
5382 pos_T *fp;
5383 list_T *l;
5384 int fnum = -1;
5385
5386 if (rettv_list_alloc(rettv) == OK)
5387 {
5388 l = rettv->vval.v_list;
5389 if (getcurpos)
5390 fp = &curwin->w_cursor;
5391 else
5392 fp = var2fpos(&argvars[0], TRUE, &fnum);
5393 if (fnum != -1)
5394 list_append_number(l, (varnumber_T)fnum);
5395 else
5396 list_append_number(l, (varnumber_T)0);
5397 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5398 : (varnumber_T)0);
5399 list_append_number(l, (fp != NULL)
5400 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5401 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005402 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005403 (varnumber_T)0);
5404 if (getcurpos)
5405 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005406 int save_set_curswant = curwin->w_set_curswant;
5407 colnr_T save_curswant = curwin->w_curswant;
5408 colnr_T save_virtcol = curwin->w_virtcol;
5409
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005410 update_curswant();
5411 list_append_number(l, curwin->w_curswant == MAXCOL ?
5412 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005413
5414 // Do not change "curswant", as it is unexpected that a get
5415 // function has a side effect.
5416 if (save_set_curswant)
5417 {
5418 curwin->w_set_curswant = save_set_curswant;
5419 curwin->w_curswant = save_curswant;
5420 curwin->w_virtcol = save_virtcol;
5421 curwin->w_valid &= ~VALID_VIRTCOL;
5422 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005423 }
5424 }
5425 else
5426 rettv->vval.v_number = FALSE;
5427}
5428
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005429/*
5430 * "getcurpos()" function
5431 */
5432 static void
5433f_getcurpos(typval_T *argvars, typval_T *rettv)
5434{
5435 getpos_both(argvars, rettv, TRUE);
5436}
5437
5438/*
5439 * "getpos(string)" function
5440 */
5441 static void
5442f_getpos(typval_T *argvars, typval_T *rettv)
5443{
5444 getpos_both(argvars, rettv, FALSE);
5445}
5446
5447/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005448 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005449 */
5450 static void
5451f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5452{
5453#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005454 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005455#endif
5456}
5457
5458/*
5459 * "getreg()" function
5460 */
5461 static void
5462f_getreg(typval_T *argvars, typval_T *rettv)
5463{
5464 char_u *strregname;
5465 int regname;
5466 int arg2 = FALSE;
5467 int return_list = FALSE;
5468 int error = FALSE;
5469
5470 if (argvars[0].v_type != VAR_UNKNOWN)
5471 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005472 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 error = strregname == NULL;
5474 if (argvars[1].v_type != VAR_UNKNOWN)
5475 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005476 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005477 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005478 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 }
5480 }
5481 else
5482 strregname = get_vim_var_str(VV_REG);
5483
5484 if (error)
5485 return;
5486
5487 regname = (strregname == NULL ? '"' : *strregname);
5488 if (regname == 0)
5489 regname = '"';
5490
5491 if (return_list)
5492 {
5493 rettv->v_type = VAR_LIST;
5494 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5495 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5496 if (rettv->vval.v_list == NULL)
5497 (void)rettv_list_alloc(rettv);
5498 else
5499 ++rettv->vval.v_list->lv_refcount;
5500 }
5501 else
5502 {
5503 rettv->v_type = VAR_STRING;
5504 rettv->vval.v_string = get_reg_contents(regname,
5505 arg2 ? GREG_EXPR_SRC : 0);
5506 }
5507}
5508
5509/*
5510 * "getregtype()" function
5511 */
5512 static void
5513f_getregtype(typval_T *argvars, typval_T *rettv)
5514{
5515 char_u *strregname;
5516 int regname;
5517 char_u buf[NUMBUFLEN + 2];
5518 long reglen = 0;
5519
5520 if (argvars[0].v_type != VAR_UNKNOWN)
5521 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005522 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005523 if (strregname == NULL) /* type error; errmsg already given */
5524 {
5525 rettv->v_type = VAR_STRING;
5526 rettv->vval.v_string = NULL;
5527 return;
5528 }
5529 }
5530 else
5531 /* Default to v:register */
5532 strregname = get_vim_var_str(VV_REG);
5533
5534 regname = (strregname == NULL ? '"' : *strregname);
5535 if (regname == 0)
5536 regname = '"';
5537
5538 buf[0] = NUL;
5539 buf[1] = NUL;
5540 switch (get_reg_type(regname, &reglen))
5541 {
5542 case MLINE: buf[0] = 'V'; break;
5543 case MCHAR: buf[0] = 'v'; break;
5544 case MBLOCK:
5545 buf[0] = Ctrl_V;
5546 sprintf((char *)buf + 1, "%ld", reglen + 1);
5547 break;
5548 }
5549 rettv->v_type = VAR_STRING;
5550 rettv->vval.v_string = vim_strsave(buf);
5551}
5552
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005553/*
5554 * Returns information (variables, options, etc.) about a tab page
5555 * as a dictionary.
5556 */
5557 static dict_T *
5558get_tabpage_info(tabpage_T *tp, int tp_idx)
5559{
5560 win_T *wp;
5561 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005562 list_T *l;
5563
5564 dict = dict_alloc();
5565 if (dict == NULL)
5566 return NULL;
5567
Bram Moolenaare0be1672018-07-08 16:50:37 +02005568 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005569
5570 l = list_alloc();
5571 if (l != NULL)
5572 {
5573 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005574 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005575 list_append_number(l, (varnumber_T)wp->w_id);
5576 dict_add_list(dict, "windows", l);
5577 }
5578
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005579 /* Make a reference to tabpage variables */
5580 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005581
5582 return dict;
5583}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005584
5585/*
5586 * "gettabinfo()" function
5587 */
5588 static void
5589f_gettabinfo(typval_T *argvars, typval_T *rettv)
5590{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005591 tabpage_T *tp, *tparg = NULL;
5592 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005593 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005594
5595 if (rettv_list_alloc(rettv) != OK)
5596 return;
5597
5598 if (argvars[0].v_type != VAR_UNKNOWN)
5599 {
5600 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005601 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005602 if (tparg == NULL)
5603 return;
5604 }
5605
5606 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005607 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005608 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005609 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005610 if (tparg != NULL && tp != tparg)
5611 continue;
5612 d = get_tabpage_info(tp, tpnr);
5613 if (d != NULL)
5614 list_append_dict(rettv->vval.v_list, d);
5615 if (tparg != NULL)
5616 return;
5617 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005618}
5619
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620/*
5621 * "gettabvar()" function
5622 */
5623 static void
5624f_gettabvar(typval_T *argvars, typval_T *rettv)
5625{
5626 win_T *oldcurwin;
5627 tabpage_T *tp, *oldtabpage;
5628 dictitem_T *v;
5629 char_u *varname;
5630 int done = FALSE;
5631
5632 rettv->v_type = VAR_STRING;
5633 rettv->vval.v_string = NULL;
5634
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005635 varname = tv_get_string_chk(&argvars[1]);
5636 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005637 if (tp != NULL && varname != NULL)
5638 {
5639 /* Set tp to be our tabpage, temporarily. Also set the window to the
5640 * first window in the tabpage, otherwise the window is not valid. */
5641 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005642 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5643 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 {
5645 /* look up the variable */
5646 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5647 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5648 if (v != NULL)
5649 {
5650 copy_tv(&v->di_tv, rettv);
5651 done = TRUE;
5652 }
5653 }
5654
5655 /* restore previous notion of curwin */
5656 restore_win(oldcurwin, oldtabpage, TRUE);
5657 }
5658
5659 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5660 copy_tv(&argvars[2], rettv);
5661}
5662
5663/*
5664 * "gettabwinvar()" function
5665 */
5666 static void
5667f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5668{
5669 getwinvar(argvars, rettv, 1);
5670}
5671
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005672/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005673 * "gettagstack()" function
5674 */
5675 static void
5676f_gettagstack(typval_T *argvars, typval_T *rettv)
5677{
5678 win_T *wp = curwin; // default is current window
5679
5680 if (rettv_dict_alloc(rettv) != OK)
5681 return;
5682
5683 if (argvars[0].v_type != VAR_UNKNOWN)
5684 {
5685 wp = find_win_by_nr_or_id(&argvars[0]);
5686 if (wp == NULL)
5687 return;
5688 }
5689
5690 get_tagstack(wp, rettv->vval.v_dict);
5691}
5692
5693/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005694 * Returns information about a window as a dictionary.
5695 */
5696 static dict_T *
5697get_win_info(win_T *wp, short tpnr, short winnr)
5698{
5699 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005700
5701 dict = dict_alloc();
5702 if (dict == NULL)
5703 return NULL;
5704
Bram Moolenaare0be1672018-07-08 16:50:37 +02005705 dict_add_number(dict, "tabnr", tpnr);
5706 dict_add_number(dict, "winnr", winnr);
5707 dict_add_number(dict, "winid", wp->w_id);
5708 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005709 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005710 dict_add_number(dict, "topline", wp->w_topline);
5711 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005712#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005713 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005714#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005715 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005716 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005717 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005718
Bram Moolenaar69905d12017-08-13 18:14:47 +02005719#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005720 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005721#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005722#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005723 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5724 dict_add_number(dict, "loclist",
5725 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005726#endif
5727
Bram Moolenaar30567352016-08-27 21:25:44 +02005728 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005729 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005730
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005731 return dict;
5732}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005733
5734/*
5735 * "getwininfo()" function
5736 */
5737 static void
5738f_getwininfo(typval_T *argvars, typval_T *rettv)
5739{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005740 tabpage_T *tp;
5741 win_T *wp = NULL, *wparg = NULL;
5742 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005743 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005744
5745 if (rettv_list_alloc(rettv) != OK)
5746 return;
5747
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005748 if (argvars[0].v_type != VAR_UNKNOWN)
5749 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005750 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005751 if (wparg == NULL)
5752 return;
5753 }
5754
5755 /* Collect information about either all the windows across all the tab
5756 * pages or one particular window.
5757 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005758 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005759 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005760 tabnr++;
5761 winnr = 0;
5762 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005763 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005764 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005765 if (wparg != NULL && wp != wparg)
5766 continue;
5767 d = get_win_info(wp, tabnr, winnr);
5768 if (d != NULL)
5769 list_append_dict(rettv->vval.v_list, d);
5770 if (wparg != NULL)
5771 /* found information about a specific window */
5772 return;
5773 }
5774 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005775}
5776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005777/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005778 * "win_execute()" function
5779 */
5780 static void
5781f_win_execute(typval_T *argvars, typval_T *rettv)
5782{
5783 int id = (int)tv_get_number(argvars);
5784 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005785 win_T *save_curwin;
5786 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005787
5788 if (wp != NULL)
5789 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005790 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5791 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005792 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005793 check_cursor();
5794 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005795 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005796 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005797 }
5798}
5799
5800/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 * "win_findbuf()" function
5802 */
5803 static void
5804f_win_findbuf(typval_T *argvars, typval_T *rettv)
5805{
5806 if (rettv_list_alloc(rettv) != FAIL)
5807 win_findbuf(argvars, rettv->vval.v_list);
5808}
5809
5810/*
5811 * "win_getid()" function
5812 */
5813 static void
5814f_win_getid(typval_T *argvars, typval_T *rettv)
5815{
5816 rettv->vval.v_number = win_getid(argvars);
5817}
5818
5819/*
5820 * "win_gotoid()" function
5821 */
5822 static void
5823f_win_gotoid(typval_T *argvars, typval_T *rettv)
5824{
5825 rettv->vval.v_number = win_gotoid(argvars);
5826}
5827
5828/*
5829 * "win_id2tabwin()" function
5830 */
5831 static void
5832f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5833{
5834 if (rettv_list_alloc(rettv) != FAIL)
5835 win_id2tabwin(argvars, rettv->vval.v_list);
5836}
5837
5838/*
5839 * "win_id2win()" function
5840 */
5841 static void
5842f_win_id2win(typval_T *argvars, typval_T *rettv)
5843{
5844 rettv->vval.v_number = win_id2win(argvars);
5845}
5846
5847/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005848 * "win_screenpos()" function
5849 */
5850 static void
5851f_win_screenpos(typval_T *argvars, typval_T *rettv)
5852{
5853 win_T *wp;
5854
5855 if (rettv_list_alloc(rettv) == FAIL)
5856 return;
5857
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005858 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005859 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5860 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5861}
5862
5863/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005864 * "getwinpos({timeout})" function
5865 */
5866 static void
5867f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5868{
5869 int x = -1;
5870 int y = -1;
5871
5872 if (rettv_list_alloc(rettv) == FAIL)
5873 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005874#if defined(FEAT_GUI) \
5875 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5876 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005877 {
5878 varnumber_T timeout = 100;
5879
5880 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005881 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005882
5883 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005884 }
5885#endif
5886 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5887 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5888}
5889
5890
5891/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005892 * "getwinposx()" function
5893 */
5894 static void
5895f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5896{
5897 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005898#if defined(FEAT_GUI) \
5899 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5900 || defined(MSWIN)
5901
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005902 {
5903 int x, y;
5904
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005905 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005906 rettv->vval.v_number = x;
5907 }
5908#endif
5909}
5910
5911/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 * "getwinposy()" function
5913 */
5914 static void
5915f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5916{
5917 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005918#if defined(FEAT_GUI) \
5919 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5920 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005921 {
5922 int x, y;
5923
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005924 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005925 rettv->vval.v_number = y;
5926 }
5927#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005928}
5929
5930/*
5931 * "getwinvar()" function
5932 */
5933 static void
5934f_getwinvar(typval_T *argvars, typval_T *rettv)
5935{
5936 getwinvar(argvars, rettv, 0);
5937}
5938
5939/*
5940 * "glob()" function
5941 */
5942 static void
5943f_glob(typval_T *argvars, typval_T *rettv)
5944{
5945 int options = WILD_SILENT|WILD_USE_NL;
5946 expand_T xpc;
5947 int error = FALSE;
5948
5949 /* When the optional second argument is non-zero, don't remove matches
5950 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5951 rettv->v_type = VAR_STRING;
5952 if (argvars[1].v_type != VAR_UNKNOWN)
5953 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005954 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955 options |= WILD_KEEP_ALL;
5956 if (argvars[2].v_type != VAR_UNKNOWN)
5957 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005958 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005959 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005960 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005961 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005962 options |= WILD_ALLLINKS;
5963 }
5964 }
5965 if (!error)
5966 {
5967 ExpandInit(&xpc);
5968 xpc.xp_context = EXPAND_FILES;
5969 if (p_wic)
5970 options += WILD_ICASE;
5971 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005972 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005973 NULL, options, WILD_ALL);
5974 else if (rettv_list_alloc(rettv) != FAIL)
5975 {
5976 int i;
5977
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005978 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979 NULL, options, WILD_ALL_KEEP);
5980 for (i = 0; i < xpc.xp_numfiles; i++)
5981 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5982
5983 ExpandCleanup(&xpc);
5984 }
5985 }
5986 else
5987 rettv->vval.v_string = NULL;
5988}
5989
5990/*
5991 * "globpath()" function
5992 */
5993 static void
5994f_globpath(typval_T *argvars, typval_T *rettv)
5995{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005996 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005998 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005999 int error = FALSE;
6000 garray_T ga;
6001 int i;
6002
Bram Moolenaar50f91d22019-08-02 19:52:15 +02006003 // When the optional second argument is non-zero, don't remove matches
6004 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006005 rettv->v_type = VAR_STRING;
6006 if (argvars[2].v_type != VAR_UNKNOWN)
6007 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006008 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006009 flags |= WILD_KEEP_ALL;
6010 if (argvars[3].v_type != VAR_UNKNOWN)
6011 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006012 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006013 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006014 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006015 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006016 flags |= WILD_ALLLINKS;
6017 }
6018 }
6019 if (file != NULL && !error)
6020 {
6021 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006022 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 if (rettv->v_type == VAR_STRING)
6024 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6025 else if (rettv_list_alloc(rettv) != FAIL)
6026 for (i = 0; i < ga.ga_len; ++i)
6027 list_append_string(rettv->vval.v_list,
6028 ((char_u **)(ga.ga_data))[i], -1);
6029 ga_clear_strings(&ga);
6030 }
6031 else
6032 rettv->vval.v_string = NULL;
6033}
6034
6035/*
6036 * "glob2regpat()" function
6037 */
6038 static void
6039f_glob2regpat(typval_T *argvars, typval_T *rettv)
6040{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006041 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006042
6043 rettv->v_type = VAR_STRING;
6044 rettv->vval.v_string = (pat == NULL)
6045 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6046}
6047
6048/* for VIM_VERSION_ defines */
6049#include "version.h"
6050
6051/*
6052 * "has()" function
6053 */
6054 static void
6055f_has(typval_T *argvars, typval_T *rettv)
6056{
6057 int i;
6058 char_u *name;
6059 int n = FALSE;
6060 static char *(has_list[]) =
6061 {
6062#ifdef AMIGA
6063 "amiga",
6064# ifdef FEAT_ARP
6065 "arp",
6066# endif
6067#endif
6068#ifdef __BEOS__
6069 "beos",
6070#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006071#if defined(BSD) && !defined(MACOS_X)
6072 "bsd",
6073#endif
6074#ifdef hpux
6075 "hpux",
6076#endif
6077#ifdef __linux__
6078 "linux",
6079#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006080#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006081 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6082 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006083# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006084 "macunix", /* Mac OS X, with the darwin feature */
6085 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006086# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087#endif
6088#ifdef __QNX__
6089 "qnx",
6090#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006091#ifdef SUN_SYSTEM
6092 "sun",
6093#else
6094 "moon",
6095#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006096#ifdef UNIX
6097 "unix",
6098#endif
6099#ifdef VMS
6100 "vms",
6101#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006102#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006103 "win32",
6104#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006105#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006106 "win32unix",
6107#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006108#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006109 "win64",
6110#endif
6111#ifdef EBCDIC
6112 "ebcdic",
6113#endif
6114#ifndef CASE_INSENSITIVE_FILENAME
6115 "fname_case",
6116#endif
6117#ifdef HAVE_ACL
6118 "acl",
6119#endif
6120#ifdef FEAT_ARABIC
6121 "arabic",
6122#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006123 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006124#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006125 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006126#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006127#ifdef FEAT_AUTOSERVERNAME
6128 "autoservername",
6129#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006130#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006131 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006132# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006133 "balloon_multiline",
6134# endif
6135#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006136#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006137 "balloon_eval_term",
6138#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006139#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6140 "builtin_terms",
6141# ifdef ALL_BUILTIN_TCAPS
6142 "all_builtin_terms",
6143# endif
6144#endif
6145#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006146 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006147 || defined(FEAT_GUI_MOTIF))
6148 "browsefilter",
6149#endif
6150#ifdef FEAT_BYTEOFF
6151 "byte_offset",
6152#endif
6153#ifdef FEAT_JOB_CHANNEL
6154 "channel",
6155#endif
6156#ifdef FEAT_CINDENT
6157 "cindent",
6158#endif
6159#ifdef FEAT_CLIENTSERVER
6160 "clientserver",
6161#endif
6162#ifdef FEAT_CLIPBOARD
6163 "clipboard",
6164#endif
6165#ifdef FEAT_CMDL_COMPL
6166 "cmdline_compl",
6167#endif
6168#ifdef FEAT_CMDHIST
6169 "cmdline_hist",
6170#endif
6171#ifdef FEAT_COMMENTS
6172 "comments",
6173#endif
6174#ifdef FEAT_CONCEAL
6175 "conceal",
6176#endif
6177#ifdef FEAT_CRYPT
6178 "cryptv",
6179 "crypt-blowfish",
6180 "crypt-blowfish2",
6181#endif
6182#ifdef FEAT_CSCOPE
6183 "cscope",
6184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186#ifdef CURSOR_SHAPE
6187 "cursorshape",
6188#endif
6189#ifdef DEBUG
6190 "debug",
6191#endif
6192#ifdef FEAT_CON_DIALOG
6193 "dialog_con",
6194#endif
6195#ifdef FEAT_GUI_DIALOG
6196 "dialog_gui",
6197#endif
6198#ifdef FEAT_DIFF
6199 "diff",
6200#endif
6201#ifdef FEAT_DIGRAPHS
6202 "digraphs",
6203#endif
6204#ifdef FEAT_DIRECTX
6205 "directx",
6206#endif
6207#ifdef FEAT_DND
6208 "dnd",
6209#endif
6210#ifdef FEAT_EMACS_TAGS
6211 "emacs_tags",
6212#endif
6213 "eval", /* always present, of course! */
6214 "ex_extra", /* graduated feature */
6215#ifdef FEAT_SEARCH_EXTRA
6216 "extra_search",
6217#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218#ifdef FEAT_SEARCHPATH
6219 "file_in_path",
6220#endif
6221#ifdef FEAT_FILTERPIPE
6222 "filterpipe",
6223#endif
6224#ifdef FEAT_FIND_ID
6225 "find_in_path",
6226#endif
6227#ifdef FEAT_FLOAT
6228 "float",
6229#endif
6230#ifdef FEAT_FOLDING
6231 "folding",
6232#endif
6233#ifdef FEAT_FOOTER
6234 "footer",
6235#endif
6236#if !defined(USE_SYSTEM) && defined(UNIX)
6237 "fork",
6238#endif
6239#ifdef FEAT_GETTEXT
6240 "gettext",
6241#endif
6242#ifdef FEAT_GUI
6243 "gui",
6244#endif
6245#ifdef FEAT_GUI_ATHENA
6246# ifdef FEAT_GUI_NEXTAW
6247 "gui_neXtaw",
6248# else
6249 "gui_athena",
6250# endif
6251#endif
6252#ifdef FEAT_GUI_GTK
6253 "gui_gtk",
6254# ifdef USE_GTK3
6255 "gui_gtk3",
6256# else
6257 "gui_gtk2",
6258# endif
6259#endif
6260#ifdef FEAT_GUI_GNOME
6261 "gui_gnome",
6262#endif
6263#ifdef FEAT_GUI_MAC
6264 "gui_mac",
6265#endif
6266#ifdef FEAT_GUI_MOTIF
6267 "gui_motif",
6268#endif
6269#ifdef FEAT_GUI_PHOTON
6270 "gui_photon",
6271#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006272#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006273 "gui_win32",
6274#endif
6275#ifdef FEAT_HANGULIN
6276 "hangul_input",
6277#endif
6278#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6279 "iconv",
6280#endif
6281#ifdef FEAT_INS_EXPAND
6282 "insert_expand",
6283#endif
6284#ifdef FEAT_JOB_CHANNEL
6285 "job",
6286#endif
6287#ifdef FEAT_JUMPLIST
6288 "jumplist",
6289#endif
6290#ifdef FEAT_KEYMAP
6291 "keymap",
6292#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006293 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294#ifdef FEAT_LANGMAP
6295 "langmap",
6296#endif
6297#ifdef FEAT_LIBCALL
6298 "libcall",
6299#endif
6300#ifdef FEAT_LINEBREAK
6301 "linebreak",
6302#endif
6303#ifdef FEAT_LISP
6304 "lispindent",
6305#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006306 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006308#ifdef FEAT_LUA
6309# ifndef DYNAMIC_LUA
6310 "lua",
6311# endif
6312#endif
6313#ifdef FEAT_MENU
6314 "menu",
6315#endif
6316#ifdef FEAT_SESSION
6317 "mksession",
6318#endif
6319#ifdef FEAT_MODIFY_FNAME
6320 "modify_fname",
6321#endif
6322#ifdef FEAT_MOUSE
6323 "mouse",
6324#endif
6325#ifdef FEAT_MOUSESHAPE
6326 "mouseshape",
6327#endif
6328#if defined(UNIX) || defined(VMS)
6329# ifdef FEAT_MOUSE_DEC
6330 "mouse_dec",
6331# endif
6332# ifdef FEAT_MOUSE_GPM
6333 "mouse_gpm",
6334# endif
6335# ifdef FEAT_MOUSE_JSB
6336 "mouse_jsbterm",
6337# endif
6338# ifdef FEAT_MOUSE_NET
6339 "mouse_netterm",
6340# endif
6341# ifdef FEAT_MOUSE_PTERM
6342 "mouse_pterm",
6343# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006344# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345 "mouse_sgr",
6346# endif
6347# ifdef FEAT_SYSMOUSE
6348 "mouse_sysmouse",
6349# endif
6350# ifdef FEAT_MOUSE_URXVT
6351 "mouse_urxvt",
6352# endif
6353# ifdef FEAT_MOUSE_XTERM
6354 "mouse_xterm",
6355# endif
6356#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006357 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006358#ifdef FEAT_MBYTE_IME
6359 "multi_byte_ime",
6360#endif
6361#ifdef FEAT_MULTI_LANG
6362 "multi_lang",
6363#endif
6364#ifdef FEAT_MZSCHEME
6365#ifndef DYNAMIC_MZSCHEME
6366 "mzscheme",
6367#endif
6368#endif
6369#ifdef FEAT_NUM64
6370 "num64",
6371#endif
6372#ifdef FEAT_OLE
6373 "ole",
6374#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006375#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006377#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006378#ifdef FEAT_PATH_EXTRA
6379 "path_extra",
6380#endif
6381#ifdef FEAT_PERL
6382#ifndef DYNAMIC_PERL
6383 "perl",
6384#endif
6385#endif
6386#ifdef FEAT_PERSISTENT_UNDO
6387 "persistent_undo",
6388#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006389#if defined(FEAT_PYTHON)
6390 "python_compiled",
6391# if defined(DYNAMIC_PYTHON)
6392 "python_dynamic",
6393# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006395 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006396# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006397#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006398#if defined(FEAT_PYTHON3)
6399 "python3_compiled",
6400# if defined(DYNAMIC_PYTHON3)
6401 "python3_dynamic",
6402# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006403 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006404 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006405# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406#endif
6407#ifdef FEAT_POSTSCRIPT
6408 "postscript",
6409#endif
6410#ifdef FEAT_PRINTER
6411 "printer",
6412#endif
6413#ifdef FEAT_PROFILE
6414 "profile",
6415#endif
6416#ifdef FEAT_RELTIME
6417 "reltime",
6418#endif
6419#ifdef FEAT_QUICKFIX
6420 "quickfix",
6421#endif
6422#ifdef FEAT_RIGHTLEFT
6423 "rightleft",
6424#endif
6425#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6426 "ruby",
6427#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006428 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006429#ifdef FEAT_CMDL_INFO
6430 "showcmd",
6431 "cmdline_info",
6432#endif
6433#ifdef FEAT_SIGNS
6434 "signs",
6435#endif
6436#ifdef FEAT_SMARTINDENT
6437 "smartindent",
6438#endif
6439#ifdef STARTUPTIME
6440 "startuptime",
6441#endif
6442#ifdef FEAT_STL_OPT
6443 "statusline",
6444#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445#ifdef FEAT_NETBEANS_INTG
6446 "netbeans_intg",
6447#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006448#ifdef FEAT_SOUND
6449 "sound",
6450#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451#ifdef FEAT_SPELL
6452 "spell",
6453#endif
6454#ifdef FEAT_SYN_HL
6455 "syntax",
6456#endif
6457#if defined(USE_SYSTEM) || !defined(UNIX)
6458 "system",
6459#endif
6460#ifdef FEAT_TAG_BINS
6461 "tag_binary",
6462#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463#ifdef FEAT_TCL
6464# ifndef DYNAMIC_TCL
6465 "tcl",
6466# endif
6467#endif
6468#ifdef FEAT_TERMGUICOLORS
6469 "termguicolors",
6470#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006471#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006472 "terminal",
6473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474#ifdef TERMINFO
6475 "terminfo",
6476#endif
6477#ifdef FEAT_TERMRESPONSE
6478 "termresponse",
6479#endif
6480#ifdef FEAT_TEXTOBJ
6481 "textobjects",
6482#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006483#ifdef FEAT_TEXT_PROP
6484 "textprop",
6485#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486#ifdef HAVE_TGETENT
6487 "tgetent",
6488#endif
6489#ifdef FEAT_TIMERS
6490 "timers",
6491#endif
6492#ifdef FEAT_TITLE
6493 "title",
6494#endif
6495#ifdef FEAT_TOOLBAR
6496 "toolbar",
6497#endif
6498#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6499 "unnamedplus",
6500#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 "user-commands", /* was accidentally included in 5.4 */
6502 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006503#ifdef FEAT_VARTABS
6504 "vartabs",
6505#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006506 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507#ifdef FEAT_VIMINFO
6508 "viminfo",
6509#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006510 "vimscript-1",
6511 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006512 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006513 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006516 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006517#ifdef FEAT_VTP
6518 "vtp",
6519#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006520#ifdef FEAT_WILDIGN
6521 "wildignore",
6522#endif
6523#ifdef FEAT_WILDMENU
6524 "wildmenu",
6525#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527#ifdef FEAT_WAK
6528 "winaltkeys",
6529#endif
6530#ifdef FEAT_WRITEBACKUP
6531 "writebackup",
6532#endif
6533#ifdef FEAT_XIM
6534 "xim",
6535#endif
6536#ifdef FEAT_XFONTSET
6537 "xfontset",
6538#endif
6539#ifdef FEAT_XPM_W32
6540 "xpm",
6541 "xpm_w32", /* for backward compatibility */
6542#else
6543# if defined(HAVE_XPM)
6544 "xpm",
6545# endif
6546#endif
6547#ifdef USE_XSMP
6548 "xsmp",
6549#endif
6550#ifdef USE_XSMP_INTERACT
6551 "xsmp_interact",
6552#endif
6553#ifdef FEAT_XCLIPBOARD
6554 "xterm_clipboard",
6555#endif
6556#ifdef FEAT_XTERM_SAVE
6557 "xterm_save",
6558#endif
6559#if defined(UNIX) && defined(FEAT_X11)
6560 "X11",
6561#endif
6562 NULL
6563 };
6564
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006565 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006566 for (i = 0; has_list[i] != NULL; ++i)
6567 if (STRICMP(name, has_list[i]) == 0)
6568 {
6569 n = TRUE;
6570 break;
6571 }
6572
6573 if (n == FALSE)
6574 {
6575 if (STRNICMP(name, "patch", 5) == 0)
6576 {
6577 if (name[5] == '-'
6578 && STRLEN(name) >= 11
6579 && vim_isdigit(name[6])
6580 && vim_isdigit(name[8])
6581 && vim_isdigit(name[10]))
6582 {
6583 int major = atoi((char *)name + 6);
6584 int minor = atoi((char *)name + 8);
6585
6586 /* Expect "patch-9.9.01234". */
6587 n = (major < VIM_VERSION_MAJOR
6588 || (major == VIM_VERSION_MAJOR
6589 && (minor < VIM_VERSION_MINOR
6590 || (minor == VIM_VERSION_MINOR
6591 && has_patch(atoi((char *)name + 10))))));
6592 }
6593 else
6594 n = has_patch(atoi((char *)name + 5));
6595 }
6596 else if (STRICMP(name, "vim_starting") == 0)
6597 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006598 else if (STRICMP(name, "ttyin") == 0)
6599 n = mch_input_isatty();
6600 else if (STRICMP(name, "ttyout") == 0)
6601 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602 else if (STRICMP(name, "multi_byte_encoding") == 0)
6603 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006604#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006605 else if (STRICMP(name, "balloon_multiline") == 0)
6606 n = multiline_balloon_available();
6607#endif
6608#ifdef DYNAMIC_TCL
6609 else if (STRICMP(name, "tcl") == 0)
6610 n = tcl_enabled(FALSE);
6611#endif
6612#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6613 else if (STRICMP(name, "iconv") == 0)
6614 n = iconv_enabled(FALSE);
6615#endif
6616#ifdef DYNAMIC_LUA
6617 else if (STRICMP(name, "lua") == 0)
6618 n = lua_enabled(FALSE);
6619#endif
6620#ifdef DYNAMIC_MZSCHEME
6621 else if (STRICMP(name, "mzscheme") == 0)
6622 n = mzscheme_enabled(FALSE);
6623#endif
6624#ifdef DYNAMIC_RUBY
6625 else if (STRICMP(name, "ruby") == 0)
6626 n = ruby_enabled(FALSE);
6627#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006628#ifdef DYNAMIC_PYTHON
6629 else if (STRICMP(name, "python") == 0)
6630 n = python_enabled(FALSE);
6631#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006632#ifdef DYNAMIC_PYTHON3
6633 else if (STRICMP(name, "python3") == 0)
6634 n = python3_enabled(FALSE);
6635#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006636#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6637 else if (STRICMP(name, "pythonx") == 0)
6638 {
6639# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6640 if (p_pyx == 0)
6641 n = python3_enabled(FALSE) || python_enabled(FALSE);
6642 else if (p_pyx == 3)
6643 n = python3_enabled(FALSE);
6644 else if (p_pyx == 2)
6645 n = python_enabled(FALSE);
6646# elif defined(DYNAMIC_PYTHON)
6647 n = python_enabled(FALSE);
6648# elif defined(DYNAMIC_PYTHON3)
6649 n = python3_enabled(FALSE);
6650# endif
6651 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652#endif
6653#ifdef DYNAMIC_PERL
6654 else if (STRICMP(name, "perl") == 0)
6655 n = perl_enabled(FALSE);
6656#endif
6657#ifdef FEAT_GUI
6658 else if (STRICMP(name, "gui_running") == 0)
6659 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660# ifdef FEAT_BROWSE
6661 else if (STRICMP(name, "browse") == 0)
6662 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6663# endif
6664#endif
6665#ifdef FEAT_SYN_HL
6666 else if (STRICMP(name, "syntax_items") == 0)
6667 n = syntax_present(curwin);
6668#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006669#ifdef FEAT_VTP
6670 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006671 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006672#endif
6673#ifdef FEAT_NETBEANS_INTG
6674 else if (STRICMP(name, "netbeans_enabled") == 0)
6675 n = netbeans_active();
6676#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006677#ifdef FEAT_MOUSE_GPM
6678 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6679 n = gpm_enabled();
6680#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006681#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006682 else if (STRICMP(name, "terminal") == 0)
6683 n = terminal_enabled();
6684#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006685#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006686 else if (STRICMP(name, "conpty") == 0)
6687 n = use_conpty();
6688#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 }
6690
6691 rettv->vval.v_number = n;
6692}
6693
6694/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695 * "haslocaldir()" function
6696 */
6697 static void
6698f_haslocaldir(typval_T *argvars, typval_T *rettv)
6699{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006700 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 win_T *wp = NULL;
6702
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006703 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6704
6705 // Check for window-local and tab-local directories
6706 if (wp != NULL && wp->w_localdir != NULL)
6707 rettv->vval.v_number = 1;
6708 else if (tp != NULL && tp->tp_localdir != NULL)
6709 rettv->vval.v_number = 2;
6710 else
6711 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006712}
6713
6714/*
6715 * "hasmapto()" function
6716 */
6717 static void
6718f_hasmapto(typval_T *argvars, typval_T *rettv)
6719{
6720 char_u *name;
6721 char_u *mode;
6722 char_u buf[NUMBUFLEN];
6723 int abbr = FALSE;
6724
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006725 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 if (argvars[1].v_type == VAR_UNKNOWN)
6727 mode = (char_u *)"nvo";
6728 else
6729 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006730 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006731 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006732 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006733 }
6734
6735 if (map_to_exists(name, mode, abbr))
6736 rettv->vval.v_number = TRUE;
6737 else
6738 rettv->vval.v_number = FALSE;
6739}
6740
6741/*
6742 * "histadd()" function
6743 */
6744 static void
6745f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6746{
6747#ifdef FEAT_CMDHIST
6748 int histype;
6749 char_u *str;
6750 char_u buf[NUMBUFLEN];
6751#endif
6752
6753 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006754 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006755 return;
6756#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006757 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 histype = str != NULL ? get_histtype(str) : -1;
6759 if (histype >= 0)
6760 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006761 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006762 if (*str != NUL)
6763 {
6764 init_history();
6765 add_to_history(histype, str, FALSE, NUL);
6766 rettv->vval.v_number = TRUE;
6767 return;
6768 }
6769 }
6770#endif
6771}
6772
6773/*
6774 * "histdel()" function
6775 */
6776 static void
6777f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6778{
6779#ifdef FEAT_CMDHIST
6780 int n;
6781 char_u buf[NUMBUFLEN];
6782 char_u *str;
6783
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006784 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006785 if (str == NULL)
6786 n = 0;
6787 else if (argvars[1].v_type == VAR_UNKNOWN)
6788 /* only one argument: clear entire history */
6789 n = clr_history(get_histtype(str));
6790 else if (argvars[1].v_type == VAR_NUMBER)
6791 /* index given: remove that entry */
6792 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 else
6795 /* string given: remove all matching entries */
6796 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006797 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798 rettv->vval.v_number = n;
6799#endif
6800}
6801
6802/*
6803 * "histget()" function
6804 */
6805 static void
6806f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6807{
6808#ifdef FEAT_CMDHIST
6809 int type;
6810 int idx;
6811 char_u *str;
6812
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006813 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 if (str == NULL)
6815 rettv->vval.v_string = NULL;
6816 else
6817 {
6818 type = get_histtype(str);
6819 if (argvars[1].v_type == VAR_UNKNOWN)
6820 idx = get_history_idx(type);
6821 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006822 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 /* -1 on type error */
6824 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6825 }
6826#else
6827 rettv->vval.v_string = NULL;
6828#endif
6829 rettv->v_type = VAR_STRING;
6830}
6831
6832/*
6833 * "histnr()" function
6834 */
6835 static void
6836f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6837{
6838 int i;
6839
6840#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006841 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842
6843 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6844 if (i >= HIST_CMD && i < HIST_COUNT)
6845 i = get_history_idx(i);
6846 else
6847#endif
6848 i = -1;
6849 rettv->vval.v_number = i;
6850}
6851
6852/*
6853 * "highlightID(name)" function
6854 */
6855 static void
6856f_hlID(typval_T *argvars, typval_T *rettv)
6857{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006858 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006859}
6860
6861/*
6862 * "highlight_exists()" function
6863 */
6864 static void
6865f_hlexists(typval_T *argvars, typval_T *rettv)
6866{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006867 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868}
6869
6870/*
6871 * "hostname()" function
6872 */
6873 static void
6874f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6875{
6876 char_u hostname[256];
6877
6878 mch_get_host_name(hostname, 256);
6879 rettv->v_type = VAR_STRING;
6880 rettv->vval.v_string = vim_strsave(hostname);
6881}
6882
6883/*
6884 * iconv() function
6885 */
6886 static void
6887f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6888{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006889 char_u buf1[NUMBUFLEN];
6890 char_u buf2[NUMBUFLEN];
6891 char_u *from, *to, *str;
6892 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893
6894 rettv->v_type = VAR_STRING;
6895 rettv->vval.v_string = NULL;
6896
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006897 str = tv_get_string(&argvars[0]);
6898 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6899 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006900 vimconv.vc_type = CONV_NONE;
6901 convert_setup(&vimconv, from, to);
6902
6903 /* If the encodings are equal, no conversion needed. */
6904 if (vimconv.vc_type == CONV_NONE)
6905 rettv->vval.v_string = vim_strsave(str);
6906 else
6907 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6908
6909 convert_setup(&vimconv, NULL, NULL);
6910 vim_free(from);
6911 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006912}
6913
6914/*
6915 * "indent()" function
6916 */
6917 static void
6918f_indent(typval_T *argvars, typval_T *rettv)
6919{
6920 linenr_T lnum;
6921
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006922 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006923 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6924 rettv->vval.v_number = get_indent_lnum(lnum);
6925 else
6926 rettv->vval.v_number = -1;
6927}
6928
6929/*
6930 * "index()" function
6931 */
6932 static void
6933f_index(typval_T *argvars, typval_T *rettv)
6934{
6935 list_T *l;
6936 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006937 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006938 long idx = 0;
6939 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006940 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006941
6942 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006943 if (argvars[0].v_type == VAR_BLOB)
6944 {
6945 typval_T tv;
6946 int start = 0;
6947
6948 if (argvars[2].v_type != VAR_UNKNOWN)
6949 {
6950 start = tv_get_number_chk(&argvars[2], &error);
6951 if (error)
6952 return;
6953 }
6954 b = argvars[0].vval.v_blob;
6955 if (b == NULL)
6956 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006957 if (start < 0)
6958 {
6959 start = blob_len(b) + start;
6960 if (start < 0)
6961 start = 0;
6962 }
6963
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006964 for (idx = start; idx < blob_len(b); ++idx)
6965 {
6966 tv.v_type = VAR_NUMBER;
6967 tv.vval.v_number = blob_get(b, idx);
6968 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6969 {
6970 rettv->vval.v_number = idx;
6971 return;
6972 }
6973 }
6974 return;
6975 }
6976 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006977 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006978 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979 return;
6980 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006981
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 l = argvars[0].vval.v_list;
6983 if (l != NULL)
6984 {
6985 item = l->lv_first;
6986 if (argvars[2].v_type != VAR_UNKNOWN)
6987 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006988 /* Start at specified item. Use the cached index that list_find()
6989 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006990 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 idx = l->lv_idx;
6992 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006993 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006994 if (error)
6995 item = NULL;
6996 }
6997
6998 for ( ; item != NULL; item = item->li_next, ++idx)
6999 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7000 {
7001 rettv->vval.v_number = idx;
7002 break;
7003 }
7004 }
7005}
7006
7007static int inputsecret_flag = 0;
7008
7009/*
7010 * "input()" function
7011 * Also handles inputsecret() when inputsecret is set.
7012 */
7013 static void
7014f_input(typval_T *argvars, typval_T *rettv)
7015{
7016 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7017}
7018
7019/*
7020 * "inputdialog()" function
7021 */
7022 static void
7023f_inputdialog(typval_T *argvars, typval_T *rettv)
7024{
7025#if defined(FEAT_GUI_TEXTDIALOG)
7026 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7027 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7028 {
7029 char_u *message;
7030 char_u buf[NUMBUFLEN];
7031 char_u *defstr = (char_u *)"";
7032
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007033 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007035 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7037 else
7038 IObuff[0] = NUL;
7039 if (message != NULL && defstr != NULL
7040 && do_dialog(VIM_QUESTION, NULL, message,
7041 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7042 rettv->vval.v_string = vim_strsave(IObuff);
7043 else
7044 {
7045 if (message != NULL && defstr != NULL
7046 && argvars[1].v_type != VAR_UNKNOWN
7047 && argvars[2].v_type != VAR_UNKNOWN)
7048 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007049 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007050 else
7051 rettv->vval.v_string = NULL;
7052 }
7053 rettv->v_type = VAR_STRING;
7054 }
7055 else
7056#endif
7057 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7058}
7059
7060/*
7061 * "inputlist()" function
7062 */
7063 static void
7064f_inputlist(typval_T *argvars, typval_T *rettv)
7065{
7066 listitem_T *li;
7067 int selected;
7068 int mouse_used;
7069
7070#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007071 /* While starting up, there is no place to enter text. When running tests
7072 * with --not-a-term we assume feedkeys() will be used. */
7073 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 return;
7075#endif
7076 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7077 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007078 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007079 return;
7080 }
7081
7082 msg_start();
7083 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7084 lines_left = Rows; /* avoid more prompt */
7085 msg_scroll = TRUE;
7086 msg_clr_eos();
7087
7088 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7089 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007090 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007091 msg_putchar('\n');
7092 }
7093
7094 /* Ask for choice. */
7095 selected = prompt_for_number(&mouse_used);
7096 if (mouse_used)
7097 selected -= lines_left;
7098
7099 rettv->vval.v_number = selected;
7100}
7101
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007102static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7103
7104/*
7105 * "inputrestore()" function
7106 */
7107 static void
7108f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7109{
7110 if (ga_userinput.ga_len > 0)
7111 {
7112 --ga_userinput.ga_len;
7113 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7114 + ga_userinput.ga_len);
7115 /* default return is zero == OK */
7116 }
7117 else if (p_verbose > 1)
7118 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007119 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007120 rettv->vval.v_number = 1; /* Failed */
7121 }
7122}
7123
7124/*
7125 * "inputsave()" function
7126 */
7127 static void
7128f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7129{
7130 /* Add an entry to the stack of typeahead storage. */
7131 if (ga_grow(&ga_userinput, 1) == OK)
7132 {
7133 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7134 + ga_userinput.ga_len);
7135 ++ga_userinput.ga_len;
7136 /* default return is zero == OK */
7137 }
7138 else
7139 rettv->vval.v_number = 1; /* Failed */
7140}
7141
7142/*
7143 * "inputsecret()" function
7144 */
7145 static void
7146f_inputsecret(typval_T *argvars, typval_T *rettv)
7147{
7148 ++cmdline_star;
7149 ++inputsecret_flag;
7150 f_input(argvars, rettv);
7151 --cmdline_star;
7152 --inputsecret_flag;
7153}
7154
7155/*
7156 * "insert()" function
7157 */
7158 static void
7159f_insert(typval_T *argvars, typval_T *rettv)
7160{
7161 long before = 0;
7162 listitem_T *item;
7163 list_T *l;
7164 int error = FALSE;
7165
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007166 if (argvars[0].v_type == VAR_BLOB)
7167 {
7168 int val, len;
7169 char_u *p;
7170
7171 len = blob_len(argvars[0].vval.v_blob);
7172 if (argvars[2].v_type != VAR_UNKNOWN)
7173 {
7174 before = (long)tv_get_number_chk(&argvars[2], &error);
7175 if (error)
7176 return; // type error; errmsg already given
7177 if (before < 0 || before > len)
7178 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007179 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007180 return;
7181 }
7182 }
7183 val = tv_get_number_chk(&argvars[1], &error);
7184 if (error)
7185 return;
7186 if (val < 0 || val > 255)
7187 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007188 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007189 return;
7190 }
7191
7192 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7193 return;
7194 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7195 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7196 *(p + before) = val;
7197 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7198
7199 copy_tv(&argvars[0], rettv);
7200 }
7201 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007202 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007203 else if ((l = argvars[0].vval.v_list) != NULL
7204 && !var_check_lock(l->lv_lock,
7205 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 {
7207 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007208 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007209 if (error)
7210 return; /* type error; errmsg already given */
7211
7212 if (before == l->lv_len)
7213 item = NULL;
7214 else
7215 {
7216 item = list_find(l, before);
7217 if (item == NULL)
7218 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007219 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007220 l = NULL;
7221 }
7222 }
7223 if (l != NULL)
7224 {
7225 list_insert_tv(l, &argvars[1], item);
7226 copy_tv(&argvars[0], rettv);
7227 }
7228 }
7229}
7230
7231/*
7232 * "invert(expr)" function
7233 */
7234 static void
7235f_invert(typval_T *argvars, typval_T *rettv)
7236{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007237 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238}
7239
7240/*
7241 * "isdirectory()" function
7242 */
7243 static void
7244f_isdirectory(typval_T *argvars, typval_T *rettv)
7245{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007246 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247}
7248
7249/*
7250 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7251 * or it refers to a List or Dictionary that is locked.
7252 */
7253 static int
7254tv_islocked(typval_T *tv)
7255{
7256 return (tv->v_lock & VAR_LOCKED)
7257 || (tv->v_type == VAR_LIST
7258 && tv->vval.v_list != NULL
7259 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7260 || (tv->v_type == VAR_DICT
7261 && tv->vval.v_dict != NULL
7262 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7263}
7264
7265/*
7266 * "islocked()" function
7267 */
7268 static void
7269f_islocked(typval_T *argvars, typval_T *rettv)
7270{
7271 lval_T lv;
7272 char_u *end;
7273 dictitem_T *di;
7274
7275 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007276 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007277 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007278 if (end != NULL && lv.ll_name != NULL)
7279 {
7280 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007281 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007282 else
7283 {
7284 if (lv.ll_tv == NULL)
7285 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007286 di = find_var(lv.ll_name, NULL, TRUE);
7287 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007289 /* Consider a variable locked when:
7290 * 1. the variable itself is locked
7291 * 2. the value of the variable is locked.
7292 * 3. the List or Dict value is locked.
7293 */
7294 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7295 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296 }
7297 }
7298 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007299 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007300 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007301 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302 else if (lv.ll_list != NULL)
7303 /* List item. */
7304 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7305 else
7306 /* Dictionary item. */
7307 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7308 }
7309 }
7310
7311 clear_lval(&lv);
7312}
7313
7314#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7315/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007316 * "isinf()" function
7317 */
7318 static void
7319f_isinf(typval_T *argvars, typval_T *rettv)
7320{
7321 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7322 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7323}
7324
7325/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007326 * "isnan()" function
7327 */
7328 static void
7329f_isnan(typval_T *argvars, typval_T *rettv)
7330{
7331 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7332 && isnan(argvars[0].vval.v_float);
7333}
7334#endif
7335
7336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007337 * "last_buffer_nr()" function.
7338 */
7339 static void
7340f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7341{
7342 int n = 0;
7343 buf_T *buf;
7344
Bram Moolenaar29323592016-07-24 22:04:11 +02007345 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346 if (n < buf->b_fnum)
7347 n = buf->b_fnum;
7348
7349 rettv->vval.v_number = n;
7350}
7351
7352/*
7353 * "len()" function
7354 */
7355 static void
7356f_len(typval_T *argvars, typval_T *rettv)
7357{
7358 switch (argvars[0].v_type)
7359 {
7360 case VAR_STRING:
7361 case VAR_NUMBER:
7362 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007363 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007365 case VAR_BLOB:
7366 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7367 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 case VAR_LIST:
7369 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7370 break;
7371 case VAR_DICT:
7372 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7373 break;
7374 case VAR_UNKNOWN:
7375 case VAR_SPECIAL:
7376 case VAR_FLOAT:
7377 case VAR_FUNC:
7378 case VAR_PARTIAL:
7379 case VAR_JOB:
7380 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007381 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 break;
7383 }
7384}
7385
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007387libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388{
7389#ifdef FEAT_LIBCALL
7390 char_u *string_in;
7391 char_u **string_result;
7392 int nr_result;
7393#endif
7394
7395 rettv->v_type = type;
7396 if (type != VAR_NUMBER)
7397 rettv->vval.v_string = NULL;
7398
7399 if (check_restricted() || check_secure())
7400 return;
7401
7402#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007403 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7405 {
7406 string_in = NULL;
7407 if (argvars[2].v_type == VAR_STRING)
7408 string_in = argvars[2].vval.v_string;
7409 if (type == VAR_NUMBER)
7410 string_result = NULL;
7411 else
7412 string_result = &rettv->vval.v_string;
7413 if (mch_libcall(argvars[0].vval.v_string,
7414 argvars[1].vval.v_string,
7415 string_in,
7416 argvars[2].vval.v_number,
7417 string_result,
7418 &nr_result) == OK
7419 && type == VAR_NUMBER)
7420 rettv->vval.v_number = nr_result;
7421 }
7422#endif
7423}
7424
7425/*
7426 * "libcall()" function
7427 */
7428 static void
7429f_libcall(typval_T *argvars, typval_T *rettv)
7430{
7431 libcall_common(argvars, rettv, VAR_STRING);
7432}
7433
7434/*
7435 * "libcallnr()" function
7436 */
7437 static void
7438f_libcallnr(typval_T *argvars, typval_T *rettv)
7439{
7440 libcall_common(argvars, rettv, VAR_NUMBER);
7441}
7442
7443/*
7444 * "line(string)" function
7445 */
7446 static void
7447f_line(typval_T *argvars, typval_T *rettv)
7448{
7449 linenr_T lnum = 0;
7450 pos_T *fp;
7451 int fnum;
7452
7453 fp = var2fpos(&argvars[0], TRUE, &fnum);
7454 if (fp != NULL)
7455 lnum = fp->lnum;
7456 rettv->vval.v_number = lnum;
7457}
7458
7459/*
7460 * "line2byte(lnum)" function
7461 */
7462 static void
7463f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7464{
7465#ifndef FEAT_BYTEOFF
7466 rettv->vval.v_number = -1;
7467#else
7468 linenr_T lnum;
7469
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007470 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7472 rettv->vval.v_number = -1;
7473 else
7474 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7475 if (rettv->vval.v_number >= 0)
7476 ++rettv->vval.v_number;
7477#endif
7478}
7479
7480/*
7481 * "lispindent(lnum)" function
7482 */
7483 static void
7484f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7485{
7486#ifdef FEAT_LISP
7487 pos_T pos;
7488 linenr_T lnum;
7489
7490 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007491 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7493 {
7494 curwin->w_cursor.lnum = lnum;
7495 rettv->vval.v_number = get_lisp_indent();
7496 curwin->w_cursor = pos;
7497 }
7498 else
7499#endif
7500 rettv->vval.v_number = -1;
7501}
7502
7503/*
7504 * "localtime()" function
7505 */
7506 static void
7507f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7508{
7509 rettv->vval.v_number = (varnumber_T)time(NULL);
7510}
7511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512#ifdef FEAT_FLOAT
7513/*
7514 * "log()" function
7515 */
7516 static void
7517f_log(typval_T *argvars, typval_T *rettv)
7518{
7519 float_T f = 0.0;
7520
7521 rettv->v_type = VAR_FLOAT;
7522 if (get_float_arg(argvars, &f) == OK)
7523 rettv->vval.v_float = log(f);
7524 else
7525 rettv->vval.v_float = 0.0;
7526}
7527
7528/*
7529 * "log10()" function
7530 */
7531 static void
7532f_log10(typval_T *argvars, typval_T *rettv)
7533{
7534 float_T f = 0.0;
7535
7536 rettv->v_type = VAR_FLOAT;
7537 if (get_float_arg(argvars, &f) == OK)
7538 rettv->vval.v_float = log10(f);
7539 else
7540 rettv->vval.v_float = 0.0;
7541}
7542#endif
7543
7544#ifdef FEAT_LUA
7545/*
7546 * "luaeval()" function
7547 */
7548 static void
7549f_luaeval(typval_T *argvars, typval_T *rettv)
7550{
7551 char_u *str;
7552 char_u buf[NUMBUFLEN];
7553
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007554 if (check_restricted() || check_secure())
7555 return;
7556
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007557 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558 do_luaeval(str, argvars + 1, rettv);
7559}
7560#endif
7561
7562/*
7563 * "map()" function
7564 */
7565 static void
7566f_map(typval_T *argvars, typval_T *rettv)
7567{
7568 filter_map(argvars, rettv, TRUE);
7569}
7570
7571/*
7572 * "maparg()" function
7573 */
7574 static void
7575f_maparg(typval_T *argvars, typval_T *rettv)
7576{
7577 get_maparg(argvars, rettv, TRUE);
7578}
7579
7580/*
7581 * "mapcheck()" function
7582 */
7583 static void
7584f_mapcheck(typval_T *argvars, typval_T *rettv)
7585{
7586 get_maparg(argvars, rettv, FALSE);
7587}
7588
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007589typedef enum
7590{
7591 MATCH_END, /* matchend() */
7592 MATCH_MATCH, /* match() */
7593 MATCH_STR, /* matchstr() */
7594 MATCH_LIST, /* matchlist() */
7595 MATCH_POS /* matchstrpos() */
7596} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007597
7598 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007599find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600{
7601 char_u *str = NULL;
7602 long len = 0;
7603 char_u *expr = NULL;
7604 char_u *pat;
7605 regmatch_T regmatch;
7606 char_u patbuf[NUMBUFLEN];
7607 char_u strbuf[NUMBUFLEN];
7608 char_u *save_cpo;
7609 long start = 0;
7610 long nth = 1;
7611 colnr_T startcol = 0;
7612 int match = 0;
7613 list_T *l = NULL;
7614 listitem_T *li = NULL;
7615 long idx = 0;
7616 char_u *tofree = NULL;
7617
7618 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7619 save_cpo = p_cpo;
7620 p_cpo = (char_u *)"";
7621
7622 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007623 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007624 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007625 /* type MATCH_LIST: return empty list when there are no matches.
7626 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 if (rettv_list_alloc(rettv) == FAIL)
7628 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007629 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 && (list_append_string(rettv->vval.v_list,
7631 (char_u *)"", 0) == FAIL
7632 || list_append_number(rettv->vval.v_list,
7633 (varnumber_T)-1) == FAIL
7634 || list_append_number(rettv->vval.v_list,
7635 (varnumber_T)-1) == FAIL
7636 || list_append_number(rettv->vval.v_list,
7637 (varnumber_T)-1) == FAIL))
7638 {
7639 list_free(rettv->vval.v_list);
7640 rettv->vval.v_list = NULL;
7641 goto theend;
7642 }
7643 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007644 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007645 {
7646 rettv->v_type = VAR_STRING;
7647 rettv->vval.v_string = NULL;
7648 }
7649
7650 if (argvars[0].v_type == VAR_LIST)
7651 {
7652 if ((l = argvars[0].vval.v_list) == NULL)
7653 goto theend;
7654 li = l->lv_first;
7655 }
7656 else
7657 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007658 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659 len = (long)STRLEN(str);
7660 }
7661
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007662 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007663 if (pat == NULL)
7664 goto theend;
7665
7666 if (argvars[2].v_type != VAR_UNKNOWN)
7667 {
7668 int error = FALSE;
7669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007670 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007671 if (error)
7672 goto theend;
7673 if (l != NULL)
7674 {
7675 li = list_find(l, start);
7676 if (li == NULL)
7677 goto theend;
7678 idx = l->lv_idx; /* use the cached index */
7679 }
7680 else
7681 {
7682 if (start < 0)
7683 start = 0;
7684 if (start > len)
7685 goto theend;
7686 /* When "count" argument is there ignore matches before "start",
7687 * otherwise skip part of the string. Differs when pattern is "^"
7688 * or "\<". */
7689 if (argvars[3].v_type != VAR_UNKNOWN)
7690 startcol = start;
7691 else
7692 {
7693 str += start;
7694 len -= start;
7695 }
7696 }
7697
7698 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007699 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007700 if (error)
7701 goto theend;
7702 }
7703
7704 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7705 if (regmatch.regprog != NULL)
7706 {
7707 regmatch.rm_ic = p_ic;
7708
7709 for (;;)
7710 {
7711 if (l != NULL)
7712 {
7713 if (li == NULL)
7714 {
7715 match = FALSE;
7716 break;
7717 }
7718 vim_free(tofree);
7719 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7720 if (str == NULL)
7721 break;
7722 }
7723
7724 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7725
7726 if (match && --nth <= 0)
7727 break;
7728 if (l == NULL && !match)
7729 break;
7730
7731 /* Advance to just after the match. */
7732 if (l != NULL)
7733 {
7734 li = li->li_next;
7735 ++idx;
7736 }
7737 else
7738 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007739 startcol = (colnr_T)(regmatch.startp[0]
7740 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 if (startcol > (colnr_T)len
7742 || str + startcol <= regmatch.startp[0])
7743 {
7744 match = FALSE;
7745 break;
7746 }
7747 }
7748 }
7749
7750 if (match)
7751 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007752 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007753 {
7754 listitem_T *li1 = rettv->vval.v_list->lv_first;
7755 listitem_T *li2 = li1->li_next;
7756 listitem_T *li3 = li2->li_next;
7757 listitem_T *li4 = li3->li_next;
7758
7759 vim_free(li1->li_tv.vval.v_string);
7760 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7761 (int)(regmatch.endp[0] - regmatch.startp[0]));
7762 li3->li_tv.vval.v_number =
7763 (varnumber_T)(regmatch.startp[0] - expr);
7764 li4->li_tv.vval.v_number =
7765 (varnumber_T)(regmatch.endp[0] - expr);
7766 if (l != NULL)
7767 li2->li_tv.vval.v_number = (varnumber_T)idx;
7768 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007769 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770 {
7771 int i;
7772
7773 /* return list with matched string and submatches */
7774 for (i = 0; i < NSUBEXP; ++i)
7775 {
7776 if (regmatch.endp[i] == NULL)
7777 {
7778 if (list_append_string(rettv->vval.v_list,
7779 (char_u *)"", 0) == FAIL)
7780 break;
7781 }
7782 else if (list_append_string(rettv->vval.v_list,
7783 regmatch.startp[i],
7784 (int)(regmatch.endp[i] - regmatch.startp[i]))
7785 == FAIL)
7786 break;
7787 }
7788 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007789 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007790 {
7791 /* return matched string */
7792 if (l != NULL)
7793 copy_tv(&li->li_tv, rettv);
7794 else
7795 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7796 (int)(regmatch.endp[0] - regmatch.startp[0]));
7797 }
7798 else if (l != NULL)
7799 rettv->vval.v_number = idx;
7800 else
7801 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007802 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007803 rettv->vval.v_number =
7804 (varnumber_T)(regmatch.startp[0] - str);
7805 else
7806 rettv->vval.v_number =
7807 (varnumber_T)(regmatch.endp[0] - str);
7808 rettv->vval.v_number += (varnumber_T)(str - expr);
7809 }
7810 }
7811 vim_regfree(regmatch.regprog);
7812 }
7813
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007814theend:
7815 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816 /* matchstrpos() without a list: drop the second item. */
7817 listitem_remove(rettv->vval.v_list,
7818 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007819 vim_free(tofree);
7820 p_cpo = save_cpo;
7821}
7822
7823/*
7824 * "match()" function
7825 */
7826 static void
7827f_match(typval_T *argvars, typval_T *rettv)
7828{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007829 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007830}
7831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832/*
7833 * "matchend()" function
7834 */
7835 static void
7836f_matchend(typval_T *argvars, typval_T *rettv)
7837{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007838 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007839}
7840
7841/*
7842 * "matchlist()" function
7843 */
7844 static void
7845f_matchlist(typval_T *argvars, typval_T *rettv)
7846{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007847 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848}
7849
7850/*
7851 * "matchstr()" function
7852 */
7853 static void
7854f_matchstr(typval_T *argvars, typval_T *rettv)
7855{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007856 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857}
7858
7859/*
7860 * "matchstrpos()" function
7861 */
7862 static void
7863f_matchstrpos(typval_T *argvars, typval_T *rettv)
7864{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007865 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866}
7867
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 static void
7869max_min(typval_T *argvars, typval_T *rettv, int domax)
7870{
7871 varnumber_T n = 0;
7872 varnumber_T i;
7873 int error = FALSE;
7874
7875 if (argvars[0].v_type == VAR_LIST)
7876 {
7877 list_T *l;
7878 listitem_T *li;
7879
7880 l = argvars[0].vval.v_list;
7881 if (l != NULL)
7882 {
7883 li = l->lv_first;
7884 if (li != NULL)
7885 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007886 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 for (;;)
7888 {
7889 li = li->li_next;
7890 if (li == NULL)
7891 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007892 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 if (domax ? i > n : i < n)
7894 n = i;
7895 }
7896 }
7897 }
7898 }
7899 else if (argvars[0].v_type == VAR_DICT)
7900 {
7901 dict_T *d;
7902 int first = TRUE;
7903 hashitem_T *hi;
7904 int todo;
7905
7906 d = argvars[0].vval.v_dict;
7907 if (d != NULL)
7908 {
7909 todo = (int)d->dv_hashtab.ht_used;
7910 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7911 {
7912 if (!HASHITEM_EMPTY(hi))
7913 {
7914 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007915 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007916 if (first)
7917 {
7918 n = i;
7919 first = FALSE;
7920 }
7921 else if (domax ? i > n : i < n)
7922 n = i;
7923 }
7924 }
7925 }
7926 }
7927 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007928 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929 rettv->vval.v_number = error ? 0 : n;
7930}
7931
7932/*
7933 * "max()" function
7934 */
7935 static void
7936f_max(typval_T *argvars, typval_T *rettv)
7937{
7938 max_min(argvars, rettv, TRUE);
7939}
7940
7941/*
7942 * "min()" function
7943 */
7944 static void
7945f_min(typval_T *argvars, typval_T *rettv)
7946{
7947 max_min(argvars, rettv, FALSE);
7948}
7949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950/*
7951 * Create the directory in which "dir" is located, and higher levels when
7952 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007953 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954 */
7955 static int
7956mkdir_recurse(char_u *dir, int prot)
7957{
7958 char_u *p;
7959 char_u *updir;
7960 int r = FAIL;
7961
7962 /* Get end of directory name in "dir".
7963 * We're done when it's "/" or "c:/". */
7964 p = gettail_sep(dir);
7965 if (p <= get_past_head(dir))
7966 return OK;
7967
7968 /* If the directory exists we're done. Otherwise: create it.*/
7969 updir = vim_strnsave(dir, (int)(p - dir));
7970 if (updir == NULL)
7971 return FAIL;
7972 if (mch_isdir(updir))
7973 r = OK;
7974 else if (mkdir_recurse(updir, prot) == OK)
7975 r = vim_mkdir_emsg(updir, prot);
7976 vim_free(updir);
7977 return r;
7978}
7979
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980/*
7981 * "mkdir()" function
7982 */
7983 static void
7984f_mkdir(typval_T *argvars, typval_T *rettv)
7985{
7986 char_u *dir;
7987 char_u buf[NUMBUFLEN];
7988 int prot = 0755;
7989
7990 rettv->vval.v_number = FAIL;
7991 if (check_restricted() || check_secure())
7992 return;
7993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007994 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007996 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007998 if (*gettail(dir) == NUL)
7999 /* remove trailing slashes */
8000 *gettail_sep(dir) = NUL;
8001
8002 if (argvars[1].v_type != VAR_UNKNOWN)
8003 {
8004 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008005 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008006 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008007 if (prot == -1)
8008 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008010 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008011 {
8012 if (mch_isdir(dir))
8013 {
8014 /* With the "p" flag it's OK if the dir already exists. */
8015 rettv->vval.v_number = OK;
8016 return;
8017 }
8018 mkdir_recurse(dir, prot);
8019 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008021 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023
8024/*
8025 * "mode()" function
8026 */
8027 static void
8028f_mode(typval_T *argvars, typval_T *rettv)
8029{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008030 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031
Bram Moolenaar612cc382018-07-29 15:34:26 +02008032 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033
8034 if (time_for_testing == 93784)
8035 {
8036 /* Testing the two-character code. */
8037 buf[0] = 'x';
8038 buf[1] = '!';
8039 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008040#ifdef FEAT_TERMINAL
8041 else if (term_use_loop())
8042 buf[0] = 't';
8043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008044 else if (VIsual_active)
8045 {
8046 if (VIsual_select)
8047 buf[0] = VIsual_mode + 's' - 'v';
8048 else
8049 buf[0] = VIsual_mode;
8050 }
8051 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8052 || State == CONFIRM)
8053 {
8054 buf[0] = 'r';
8055 if (State == ASKMORE)
8056 buf[1] = 'm';
8057 else if (State == CONFIRM)
8058 buf[1] = '?';
8059 }
8060 else if (State == EXTERNCMD)
8061 buf[0] = '!';
8062 else if (State & INSERT)
8063 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064 if (State & VREPLACE_FLAG)
8065 {
8066 buf[0] = 'R';
8067 buf[1] = 'v';
8068 }
8069 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008070 {
8071 if (State & REPLACE_FLAG)
8072 buf[0] = 'R';
8073 else
8074 buf[0] = 'i';
8075#ifdef FEAT_INS_EXPAND
8076 if (ins_compl_active())
8077 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008078 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008079 buf[1] = 'x';
8080#endif
8081 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008083 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 {
8085 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008086 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008088 else if (exmode_active == EXMODE_NORMAL)
8089 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008090 }
8091 else
8092 {
8093 buf[0] = 'n';
8094 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008095 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008097 // to be able to detect force-linewise/blockwise/characterwise operations
8098 buf[2] = motion_force;
8099 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008100 else if (restart_edit == 'I' || restart_edit == 'R'
8101 || restart_edit == 'V')
8102 {
8103 buf[1] = 'i';
8104 buf[2] = restart_edit;
8105 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 }
8107
8108 /* Clear out the minor mode when the argument is not a non-zero number or
8109 * non-empty string. */
8110 if (!non_zero_arg(&argvars[0]))
8111 buf[1] = NUL;
8112
8113 rettv->vval.v_string = vim_strsave(buf);
8114 rettv->v_type = VAR_STRING;
8115}
8116
8117#if defined(FEAT_MZSCHEME) || defined(PROTO)
8118/*
8119 * "mzeval()" function
8120 */
8121 static void
8122f_mzeval(typval_T *argvars, typval_T *rettv)
8123{
8124 char_u *str;
8125 char_u buf[NUMBUFLEN];
8126
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008127 if (check_restricted() || check_secure())
8128 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008129 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 do_mzeval(str, rettv);
8131}
8132
8133 void
8134mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8135{
8136 typval_T argvars[3];
8137
8138 argvars[0].v_type = VAR_STRING;
8139 argvars[0].vval.v_string = name;
8140 copy_tv(args, &argvars[1]);
8141 argvars[2].v_type = VAR_UNKNOWN;
8142 f_call(argvars, rettv);
8143 clear_tv(&argvars[1]);
8144}
8145#endif
8146
8147/*
8148 * "nextnonblank()" function
8149 */
8150 static void
8151f_nextnonblank(typval_T *argvars, typval_T *rettv)
8152{
8153 linenr_T lnum;
8154
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008155 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156 {
8157 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8158 {
8159 lnum = 0;
8160 break;
8161 }
8162 if (*skipwhite(ml_get(lnum)) != NUL)
8163 break;
8164 }
8165 rettv->vval.v_number = lnum;
8166}
8167
8168/*
8169 * "nr2char()" function
8170 */
8171 static void
8172f_nr2char(typval_T *argvars, typval_T *rettv)
8173{
8174 char_u buf[NUMBUFLEN];
8175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 if (has_mbyte)
8177 {
8178 int utf8 = 0;
8179
8180 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008181 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008183 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008185 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 }
8187 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008189 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 buf[1] = NUL;
8191 }
8192 rettv->v_type = VAR_STRING;
8193 rettv->vval.v_string = vim_strsave(buf);
8194}
8195
8196/*
8197 * "or(expr, expr)" function
8198 */
8199 static void
8200f_or(typval_T *argvars, typval_T *rettv)
8201{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008202 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8203 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204}
8205
8206/*
8207 * "pathshorten()" function
8208 */
8209 static void
8210f_pathshorten(typval_T *argvars, typval_T *rettv)
8211{
8212 char_u *p;
8213
8214 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008215 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216 if (p == NULL)
8217 rettv->vval.v_string = NULL;
8218 else
8219 {
8220 p = vim_strsave(p);
8221 rettv->vval.v_string = p;
8222 if (p != NULL)
8223 shorten_dir(p);
8224 }
8225}
8226
8227#ifdef FEAT_PERL
8228/*
8229 * "perleval()" function
8230 */
8231 static void
8232f_perleval(typval_T *argvars, typval_T *rettv)
8233{
8234 char_u *str;
8235 char_u buf[NUMBUFLEN];
8236
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008237 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 do_perleval(str, rettv);
8239}
8240#endif
8241
8242#ifdef FEAT_FLOAT
8243/*
8244 * "pow()" function
8245 */
8246 static void
8247f_pow(typval_T *argvars, typval_T *rettv)
8248{
8249 float_T fx = 0.0, fy = 0.0;
8250
8251 rettv->v_type = VAR_FLOAT;
8252 if (get_float_arg(argvars, &fx) == OK
8253 && get_float_arg(&argvars[1], &fy) == OK)
8254 rettv->vval.v_float = pow(fx, fy);
8255 else
8256 rettv->vval.v_float = 0.0;
8257}
8258#endif
8259
8260/*
8261 * "prevnonblank()" function
8262 */
8263 static void
8264f_prevnonblank(typval_T *argvars, typval_T *rettv)
8265{
8266 linenr_T lnum;
8267
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008268 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008269 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8270 lnum = 0;
8271 else
8272 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8273 --lnum;
8274 rettv->vval.v_number = lnum;
8275}
8276
8277/* This dummy va_list is here because:
8278 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8279 * - locally in the function results in a "used before set" warning
8280 * - using va_start() to initialize it gives "function with fixed args" error */
8281static va_list ap;
8282
8283/*
8284 * "printf()" function
8285 */
8286 static void
8287f_printf(typval_T *argvars, typval_T *rettv)
8288{
8289 char_u buf[NUMBUFLEN];
8290 int len;
8291 char_u *s;
8292 int saved_did_emsg = did_emsg;
8293 char *fmt;
8294
8295 rettv->v_type = VAR_STRING;
8296 rettv->vval.v_string = NULL;
8297
8298 /* Get the required length, allocate the buffer and do it for real. */
8299 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008300 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008301 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 if (!did_emsg)
8303 {
8304 s = alloc(len + 1);
8305 if (s != NULL)
8306 {
8307 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008308 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8309 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008310 }
8311 }
8312 did_emsg |= saved_did_emsg;
8313}
8314
8315/*
8316 * "pumvisible()" function
8317 */
8318 static void
8319f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8320{
8321#ifdef FEAT_INS_EXPAND
8322 if (pum_visible())
8323 rettv->vval.v_number = 1;
8324#endif
8325}
8326
8327#ifdef FEAT_PYTHON3
8328/*
8329 * "py3eval()" function
8330 */
8331 static void
8332f_py3eval(typval_T *argvars, typval_T *rettv)
8333{
8334 char_u *str;
8335 char_u buf[NUMBUFLEN];
8336
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008337 if (check_restricted() || check_secure())
8338 return;
8339
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008340 if (p_pyx == 0)
8341 p_pyx = 3;
8342
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008343 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008344 do_py3eval(str, rettv);
8345}
8346#endif
8347
8348#ifdef FEAT_PYTHON
8349/*
8350 * "pyeval()" function
8351 */
8352 static void
8353f_pyeval(typval_T *argvars, typval_T *rettv)
8354{
8355 char_u *str;
8356 char_u buf[NUMBUFLEN];
8357
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008358 if (check_restricted() || check_secure())
8359 return;
8360
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008361 if (p_pyx == 0)
8362 p_pyx = 2;
8363
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008364 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365 do_pyeval(str, rettv);
8366}
8367#endif
8368
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008369#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8370/*
8371 * "pyxeval()" function
8372 */
8373 static void
8374f_pyxeval(typval_T *argvars, typval_T *rettv)
8375{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008376 if (check_restricted() || check_secure())
8377 return;
8378
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008379# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8380 init_pyxversion();
8381 if (p_pyx == 2)
8382 f_pyeval(argvars, rettv);
8383 else
8384 f_py3eval(argvars, rettv);
8385# elif defined(FEAT_PYTHON)
8386 f_pyeval(argvars, rettv);
8387# elif defined(FEAT_PYTHON3)
8388 f_py3eval(argvars, rettv);
8389# endif
8390}
8391#endif
8392
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008393/*
8394 * "range()" function
8395 */
8396 static void
8397f_range(typval_T *argvars, typval_T *rettv)
8398{
8399 varnumber_T start;
8400 varnumber_T end;
8401 varnumber_T stride = 1;
8402 varnumber_T i;
8403 int error = FALSE;
8404
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008405 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008406 if (argvars[1].v_type == VAR_UNKNOWN)
8407 {
8408 end = start - 1;
8409 start = 0;
8410 }
8411 else
8412 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008413 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008414 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008415 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008416 }
8417
8418 if (error)
8419 return; /* type error; errmsg already given */
8420 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008421 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008422 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008423 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008424 else
8425 {
8426 if (rettv_list_alloc(rettv) == OK)
8427 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8428 if (list_append_number(rettv->vval.v_list,
8429 (varnumber_T)i) == FAIL)
8430 break;
8431 }
8432}
8433
8434/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008435 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008436 */
8437 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008438readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008439{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008440 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008441 typval_T save_val;
8442 typval_T rettv;
8443 typval_T argv[2];
8444 int retval = 0;
8445 int error = FALSE;
8446
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008447 if (expr->v_type == VAR_UNKNOWN)
8448 return 1;
8449
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008450 prepare_vimvar(VV_VAL, &save_val);
8451 set_vim_var_string(VV_VAL, name, -1);
8452 argv[0].v_type = VAR_STRING;
8453 argv[0].vval.v_string = name;
8454
8455 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8456 goto theend;
8457
8458 retval = tv_get_number_chk(&rettv, &error);
8459 if (error)
8460 retval = -1;
8461 clear_tv(&rettv);
8462
8463theend:
8464 set_vim_var_string(VV_VAL, NULL, 0);
8465 restore_vimvar(VV_VAL, &save_val);
8466 return retval;
8467}
8468
8469/*
8470 * "readdir()" function
8471 */
8472 static void
8473f_readdir(typval_T *argvars, typval_T *rettv)
8474{
8475 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008476 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008477 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008478 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008479 garray_T ga;
8480 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008481
8482 if (rettv_list_alloc(rettv) == FAIL)
8483 return;
8484 path = tv_get_string(&argvars[0]);
8485 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008486
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008487 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8488 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008489 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008490 for (i = 0; i < ga.ga_len; i++)
8491 {
8492 p = ((char_u **)ga.ga_data)[i];
8493 list_append_string(rettv->vval.v_list, p, -1);
8494 }
8495 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008496 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008497}
8498
8499/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008500 * "readfile()" function
8501 */
8502 static void
8503f_readfile(typval_T *argvars, typval_T *rettv)
8504{
8505 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008506 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008507 int failed = FALSE;
8508 char_u *fname;
8509 FILE *fd;
8510 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8511 int io_size = sizeof(buf);
8512 int readlen; /* size of last fread() */
8513 char_u *prev = NULL; /* previously read bytes, if any */
8514 long prevlen = 0; /* length of data in prev */
8515 long prevsize = 0; /* size of prev buffer */
8516 long maxline = MAXLNUM;
8517 long cnt = 0;
8518 char_u *p; /* position in buf */
8519 char_u *start; /* start of current line */
8520
8521 if (argvars[1].v_type != VAR_UNKNOWN)
8522 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008523 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008524 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008525 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8526 blob = TRUE;
8527
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008528 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008529 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530 }
8531
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008532 if (blob)
8533 {
8534 if (rettv_blob_alloc(rettv) == FAIL)
8535 return;
8536 }
8537 else
8538 {
8539 if (rettv_list_alloc(rettv) == FAIL)
8540 return;
8541 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008542
8543 /* Always open the file in binary mode, library functions have a mind of
8544 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008545 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008546 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8547 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008548 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008549 return;
8550 }
8551
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008552 if (blob)
8553 {
8554 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8555 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008556 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008557 blob_free(rettv->vval.v_blob);
8558 }
8559 fclose(fd);
8560 return;
8561 }
8562
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008563 while (cnt < maxline || maxline < 0)
8564 {
8565 readlen = (int)fread(buf, 1, io_size, fd);
8566
8567 /* This for loop processes what was read, but is also entered at end
8568 * of file so that either:
8569 * - an incomplete line gets written
8570 * - a "binary" file gets an empty line at the end if it ends in a
8571 * newline. */
8572 for (p = buf, start = buf;
8573 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8574 ++p)
8575 {
8576 if (*p == '\n' || readlen <= 0)
8577 {
8578 listitem_T *li;
8579 char_u *s = NULL;
8580 long_u len = p - start;
8581
8582 /* Finished a line. Remove CRs before NL. */
8583 if (readlen > 0 && !binary)
8584 {
8585 while (len > 0 && start[len - 1] == '\r')
8586 --len;
8587 /* removal may cross back to the "prev" string */
8588 if (len == 0)
8589 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8590 --prevlen;
8591 }
8592 if (prevlen == 0)
8593 s = vim_strnsave(start, (int)len);
8594 else
8595 {
8596 /* Change "prev" buffer to be the right size. This way
8597 * the bytes are only copied once, and very long lines are
8598 * allocated only once. */
8599 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8600 {
8601 mch_memmove(s + prevlen, start, len);
8602 s[prevlen + len] = NUL;
8603 prev = NULL; /* the list will own the string */
8604 prevlen = prevsize = 0;
8605 }
8606 }
8607 if (s == NULL)
8608 {
8609 do_outofmem_msg((long_u) prevlen + len + 1);
8610 failed = TRUE;
8611 break;
8612 }
8613
8614 if ((li = listitem_alloc()) == NULL)
8615 {
8616 vim_free(s);
8617 failed = TRUE;
8618 break;
8619 }
8620 li->li_tv.v_type = VAR_STRING;
8621 li->li_tv.v_lock = 0;
8622 li->li_tv.vval.v_string = s;
8623 list_append(rettv->vval.v_list, li);
8624
8625 start = p + 1; /* step over newline */
8626 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8627 break;
8628 }
8629 else if (*p == NUL)
8630 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008631 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8632 * when finding the BF and check the previous two bytes. */
8633 else if (*p == 0xbf && enc_utf8 && !binary)
8634 {
8635 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8636 * + 1, these may be in the "prev" string. */
8637 char_u back1 = p >= buf + 1 ? p[-1]
8638 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8639 char_u back2 = p >= buf + 2 ? p[-2]
8640 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8641 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8642
8643 if (back2 == 0xef && back1 == 0xbb)
8644 {
8645 char_u *dest = p - 2;
8646
8647 /* Usually a BOM is at the beginning of a file, and so at
8648 * the beginning of a line; then we can just step over it.
8649 */
8650 if (start == dest)
8651 start = p + 1;
8652 else
8653 {
8654 /* have to shuffle buf to close gap */
8655 int adjust_prevlen = 0;
8656
8657 if (dest < buf)
8658 {
8659 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8660 dest = buf;
8661 }
8662 if (readlen > p - buf + 1)
8663 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8664 readlen -= 3 - adjust_prevlen;
8665 prevlen -= adjust_prevlen;
8666 p = dest - 1;
8667 }
8668 }
8669 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008670 } /* for */
8671
8672 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8673 break;
8674 if (start < p)
8675 {
8676 /* There's part of a line in buf, store it in "prev". */
8677 if (p - start + prevlen >= prevsize)
8678 {
8679 /* need bigger "prev" buffer */
8680 char_u *newprev;
8681
8682 /* A common use case is ordinary text files and "prev" gets a
8683 * fragment of a line, so the first allocation is made
8684 * small, to avoid repeatedly 'allocing' large and
8685 * 'reallocing' small. */
8686 if (prevsize == 0)
8687 prevsize = (long)(p - start);
8688 else
8689 {
8690 long grow50pc = (prevsize * 3) / 2;
8691 long growmin = (long)((p - start) * 2 + prevlen);
8692 prevsize = grow50pc > growmin ? grow50pc : growmin;
8693 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008694 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695 if (newprev == NULL)
8696 {
8697 do_outofmem_msg((long_u)prevsize);
8698 failed = TRUE;
8699 break;
8700 }
8701 prev = newprev;
8702 }
8703 /* Add the line part to end of "prev". */
8704 mch_memmove(prev + prevlen, start, p - start);
8705 prevlen += (long)(p - start);
8706 }
8707 } /* while */
8708
8709 /*
8710 * For a negative line count use only the lines at the end of the file,
8711 * free the rest.
8712 */
8713 if (!failed && maxline < 0)
8714 while (cnt > -maxline)
8715 {
8716 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8717 --cnt;
8718 }
8719
8720 if (failed)
8721 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008722 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008723 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008724 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725 }
8726
8727 vim_free(prev);
8728 fclose(fd);
8729}
8730
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008731 static void
8732return_register(int regname, typval_T *rettv)
8733{
8734 char_u buf[2] = {0, 0};
8735
8736 buf[0] = (char_u)regname;
8737 rettv->v_type = VAR_STRING;
8738 rettv->vval.v_string = vim_strsave(buf);
8739}
8740
8741/*
8742 * "reg_executing()" function
8743 */
8744 static void
8745f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8746{
8747 return_register(reg_executing, rettv);
8748}
8749
8750/*
8751 * "reg_recording()" function
8752 */
8753 static void
8754f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8755{
8756 return_register(reg_recording, rettv);
8757}
8758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008759#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760/*
8761 * Convert a List to proftime_T.
8762 * Return FAIL when there is something wrong.
8763 */
8764 static int
8765list2proftime(typval_T *arg, proftime_T *tm)
8766{
8767 long n1, n2;
8768 int error = FALSE;
8769
8770 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8771 || arg->vval.v_list->lv_len != 2)
8772 return FAIL;
8773 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8774 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008775# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008776 tm->HighPart = n1;
8777 tm->LowPart = n2;
8778# else
8779 tm->tv_sec = n1;
8780 tm->tv_usec = n2;
8781# endif
8782 return error ? FAIL : OK;
8783}
8784#endif /* FEAT_RELTIME */
8785
8786/*
8787 * "reltime()" function
8788 */
8789 static void
8790f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8791{
8792#ifdef FEAT_RELTIME
8793 proftime_T res;
8794 proftime_T start;
8795
8796 if (argvars[0].v_type == VAR_UNKNOWN)
8797 {
8798 /* No arguments: get current time. */
8799 profile_start(&res);
8800 }
8801 else if (argvars[1].v_type == VAR_UNKNOWN)
8802 {
8803 if (list2proftime(&argvars[0], &res) == FAIL)
8804 return;
8805 profile_end(&res);
8806 }
8807 else
8808 {
8809 /* Two arguments: compute the difference. */
8810 if (list2proftime(&argvars[0], &start) == FAIL
8811 || list2proftime(&argvars[1], &res) == FAIL)
8812 return;
8813 profile_sub(&res, &start);
8814 }
8815
8816 if (rettv_list_alloc(rettv) == OK)
8817 {
8818 long n1, n2;
8819
Bram Moolenaar4f974752019-02-17 17:44:42 +01008820# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008821 n1 = res.HighPart;
8822 n2 = res.LowPart;
8823# else
8824 n1 = res.tv_sec;
8825 n2 = res.tv_usec;
8826# endif
8827 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8828 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8829 }
8830#endif
8831}
8832
8833#ifdef FEAT_FLOAT
8834/*
8835 * "reltimefloat()" function
8836 */
8837 static void
8838f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8839{
8840# ifdef FEAT_RELTIME
8841 proftime_T tm;
8842# endif
8843
8844 rettv->v_type = VAR_FLOAT;
8845 rettv->vval.v_float = 0;
8846# ifdef FEAT_RELTIME
8847 if (list2proftime(&argvars[0], &tm) == OK)
8848 rettv->vval.v_float = profile_float(&tm);
8849# endif
8850}
8851#endif
8852
8853/*
8854 * "reltimestr()" function
8855 */
8856 static void
8857f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8858{
8859#ifdef FEAT_RELTIME
8860 proftime_T tm;
8861#endif
8862
8863 rettv->v_type = VAR_STRING;
8864 rettv->vval.v_string = NULL;
8865#ifdef FEAT_RELTIME
8866 if (list2proftime(&argvars[0], &tm) == OK)
8867 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8868#endif
8869}
8870
8871#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008872 static void
8873make_connection(void)
8874{
8875 if (X_DISPLAY == NULL
8876# ifdef FEAT_GUI
8877 && !gui.in_use
8878# endif
8879 )
8880 {
8881 x_force_connect = TRUE;
8882 setup_term_clip();
8883 x_force_connect = FALSE;
8884 }
8885}
8886
8887 static int
8888check_connection(void)
8889{
8890 make_connection();
8891 if (X_DISPLAY == NULL)
8892 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008893 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008894 return FAIL;
8895 }
8896 return OK;
8897}
8898#endif
8899
8900#ifdef FEAT_CLIENTSERVER
8901 static void
8902remote_common(typval_T *argvars, typval_T *rettv, int expr)
8903{
8904 char_u *server_name;
8905 char_u *keys;
8906 char_u *r = NULL;
8907 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008908 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008909# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008910 HWND w;
8911# else
8912 Window w;
8913# endif
8914
8915 if (check_restricted() || check_secure())
8916 return;
8917
8918# ifdef FEAT_X11
8919 if (check_connection() == FAIL)
8920 return;
8921# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008922 if (argvars[2].v_type != VAR_UNKNOWN
8923 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008924 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008926 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008927 if (server_name == NULL)
8928 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008929 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008930# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008931 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008932# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008933 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8934 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008935# endif
8936 {
8937 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008938 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008939 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008940 vim_free(r);
8941 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008943 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008944 return;
8945 }
8946
8947 rettv->vval.v_string = r;
8948
8949 if (argvars[2].v_type != VAR_UNKNOWN)
8950 {
8951 dictitem_T v;
8952 char_u str[30];
8953 char_u *idvar;
8954
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008955 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008956 if (idvar != NULL && *idvar != NUL)
8957 {
8958 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8959 v.di_tv.v_type = VAR_STRING;
8960 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008961 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008962 vim_free(v.di_tv.vval.v_string);
8963 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008964 }
8965}
8966#endif
8967
8968/*
8969 * "remote_expr()" function
8970 */
8971 static void
8972f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8973{
8974 rettv->v_type = VAR_STRING;
8975 rettv->vval.v_string = NULL;
8976#ifdef FEAT_CLIENTSERVER
8977 remote_common(argvars, rettv, TRUE);
8978#endif
8979}
8980
8981/*
8982 * "remote_foreground()" function
8983 */
8984 static void
8985f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8986{
8987#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008988# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008989 /* On Win32 it's done in this application. */
8990 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008991 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008992
8993 if (server_name != NULL)
8994 serverForeground(server_name);
8995 }
8996# else
8997 /* Send a foreground() expression to the server. */
8998 argvars[1].v_type = VAR_STRING;
8999 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9000 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009001 rettv->v_type = VAR_STRING;
9002 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009003 remote_common(argvars, rettv, TRUE);
9004 vim_free(argvars[1].vval.v_string);
9005# endif
9006#endif
9007}
9008
9009 static void
9010f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9011{
9012#ifdef FEAT_CLIENTSERVER
9013 dictitem_T v;
9014 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009015# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009016 long_u n = 0;
9017# endif
9018 char_u *serverid;
9019
9020 if (check_restricted() || check_secure())
9021 {
9022 rettv->vval.v_number = -1;
9023 return;
9024 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009025 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 if (serverid == NULL)
9027 {
9028 rettv->vval.v_number = -1;
9029 return; /* type error; errmsg already given */
9030 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009031# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009032 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9033 if (n == 0)
9034 rettv->vval.v_number = -1;
9035 else
9036 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009037 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009038 rettv->vval.v_number = (s != NULL);
9039 }
9040# else
9041 if (check_connection() == FAIL)
9042 return;
9043
9044 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9045 serverStrToWin(serverid), &s);
9046# endif
9047
9048 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9049 {
9050 char_u *retvar;
9051
9052 v.di_tv.v_type = VAR_STRING;
9053 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009054 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009055 if (retvar != NULL)
9056 set_var(retvar, &v.di_tv, FALSE);
9057 vim_free(v.di_tv.vval.v_string);
9058 }
9059#else
9060 rettv->vval.v_number = -1;
9061#endif
9062}
9063
9064 static void
9065f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9066{
9067 char_u *r = NULL;
9068
9069#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009070 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009071
9072 if (serverid != NULL && !check_restricted() && !check_secure())
9073 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009074 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009075# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009076 /* The server's HWND is encoded in the 'id' parameter */
9077 long_u n = 0;
9078# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009079
9080 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009081 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009082
Bram Moolenaar4f974752019-02-17 17:44:42 +01009083# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009084 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9085 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009086 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009087 if (r == NULL)
9088# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009089 if (check_connection() == FAIL
9090 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9091 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009092# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009093 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009094 }
9095#endif
9096 rettv->v_type = VAR_STRING;
9097 rettv->vval.v_string = r;
9098}
9099
9100/*
9101 * "remote_send()" function
9102 */
9103 static void
9104f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9105{
9106 rettv->v_type = VAR_STRING;
9107 rettv->vval.v_string = NULL;
9108#ifdef FEAT_CLIENTSERVER
9109 remote_common(argvars, rettv, FALSE);
9110#endif
9111}
9112
9113/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009114 * "remote_startserver()" function
9115 */
9116 static void
9117f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9118{
9119#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009120 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009121
9122 if (server == NULL)
9123 return; /* type error; errmsg already given */
9124 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009125 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009126 else
9127 {
9128# ifdef FEAT_X11
9129 if (check_connection() == OK)
9130 serverRegisterName(X_DISPLAY, server);
9131# else
9132 serverSetName(server);
9133# endif
9134 }
9135#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009136 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009137#endif
9138}
9139
9140/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009141 * "remove()" function
9142 */
9143 static void
9144f_remove(typval_T *argvars, typval_T *rettv)
9145{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009146 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9147
9148 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009149 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009150 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009151 blob_remove(argvars, rettv);
9152 else if (argvars[0].v_type == VAR_LIST)
9153 list_remove(argvars, rettv, arg_errmsg);
9154 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009155 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009156}
9157
9158/*
9159 * "rename({from}, {to})" function
9160 */
9161 static void
9162f_rename(typval_T *argvars, typval_T *rettv)
9163{
9164 char_u buf[NUMBUFLEN];
9165
9166 if (check_restricted() || check_secure())
9167 rettv->vval.v_number = -1;
9168 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009169 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9170 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009171}
9172
9173/*
9174 * "repeat()" function
9175 */
9176 static void
9177f_repeat(typval_T *argvars, typval_T *rettv)
9178{
9179 char_u *p;
9180 int n;
9181 int slen;
9182 int len;
9183 char_u *r;
9184 int i;
9185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009186 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009187 if (argvars[0].v_type == VAR_LIST)
9188 {
9189 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9190 while (n-- > 0)
9191 if (list_extend(rettv->vval.v_list,
9192 argvars[0].vval.v_list, NULL) == FAIL)
9193 break;
9194 }
9195 else
9196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009197 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009198 rettv->v_type = VAR_STRING;
9199 rettv->vval.v_string = NULL;
9200
9201 slen = (int)STRLEN(p);
9202 len = slen * n;
9203 if (len <= 0)
9204 return;
9205
9206 r = alloc(len + 1);
9207 if (r != NULL)
9208 {
9209 for (i = 0; i < n; i++)
9210 mch_memmove(r + i * slen, p, (size_t)slen);
9211 r[len] = NUL;
9212 }
9213
9214 rettv->vval.v_string = r;
9215 }
9216}
9217
9218/*
9219 * "resolve()" function
9220 */
9221 static void
9222f_resolve(typval_T *argvars, typval_T *rettv)
9223{
9224 char_u *p;
9225#ifdef HAVE_READLINK
9226 char_u *buf = NULL;
9227#endif
9228
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009229 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009230#ifdef FEAT_SHORTCUT
9231 {
9232 char_u *v = NULL;
9233
Bram Moolenaardce1e892019-02-10 23:18:53 +01009234 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009235 if (v != NULL)
9236 rettv->vval.v_string = v;
9237 else
9238 rettv->vval.v_string = vim_strsave(p);
9239 }
9240#else
9241# ifdef HAVE_READLINK
9242 {
9243 char_u *cpy;
9244 int len;
9245 char_u *remain = NULL;
9246 char_u *q;
9247 int is_relative_to_current = FALSE;
9248 int has_trailing_pathsep = FALSE;
9249 int limit = 100;
9250
9251 p = vim_strsave(p);
9252
9253 if (p[0] == '.' && (vim_ispathsep(p[1])
9254 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9255 is_relative_to_current = TRUE;
9256
9257 len = STRLEN(p);
9258 if (len > 0 && after_pathsep(p, p + len))
9259 {
9260 has_trailing_pathsep = TRUE;
9261 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9262 }
9263
9264 q = getnextcomp(p);
9265 if (*q != NUL)
9266 {
9267 /* Separate the first path component in "p", and keep the
9268 * remainder (beginning with the path separator). */
9269 remain = vim_strsave(q - 1);
9270 q[-1] = NUL;
9271 }
9272
9273 buf = alloc(MAXPATHL + 1);
9274 if (buf == NULL)
9275 goto fail;
9276
9277 for (;;)
9278 {
9279 for (;;)
9280 {
9281 len = readlink((char *)p, (char *)buf, MAXPATHL);
9282 if (len <= 0)
9283 break;
9284 buf[len] = NUL;
9285
9286 if (limit-- == 0)
9287 {
9288 vim_free(p);
9289 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009290 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291 rettv->vval.v_string = NULL;
9292 goto fail;
9293 }
9294
9295 /* Ensure that the result will have a trailing path separator
9296 * if the argument has one. */
9297 if (remain == NULL && has_trailing_pathsep)
9298 add_pathsep(buf);
9299
9300 /* Separate the first path component in the link value and
9301 * concatenate the remainders. */
9302 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9303 if (*q != NUL)
9304 {
9305 if (remain == NULL)
9306 remain = vim_strsave(q - 1);
9307 else
9308 {
9309 cpy = concat_str(q - 1, remain);
9310 if (cpy != NULL)
9311 {
9312 vim_free(remain);
9313 remain = cpy;
9314 }
9315 }
9316 q[-1] = NUL;
9317 }
9318
9319 q = gettail(p);
9320 if (q > p && *q == NUL)
9321 {
9322 /* Ignore trailing path separator. */
9323 q[-1] = NUL;
9324 q = gettail(p);
9325 }
9326 if (q > p && !mch_isFullName(buf))
9327 {
9328 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009329 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009330 if (cpy != NULL)
9331 {
9332 STRCPY(cpy, p);
9333 STRCPY(gettail(cpy), buf);
9334 vim_free(p);
9335 p = cpy;
9336 }
9337 }
9338 else
9339 {
9340 vim_free(p);
9341 p = vim_strsave(buf);
9342 }
9343 }
9344
9345 if (remain == NULL)
9346 break;
9347
9348 /* Append the first path component of "remain" to "p". */
9349 q = getnextcomp(remain + 1);
9350 len = q - remain - (*q != NUL);
9351 cpy = vim_strnsave(p, STRLEN(p) + len);
9352 if (cpy != NULL)
9353 {
9354 STRNCAT(cpy, remain, len);
9355 vim_free(p);
9356 p = cpy;
9357 }
9358 /* Shorten "remain". */
9359 if (*q != NUL)
9360 STRMOVE(remain, q - 1);
9361 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009362 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009363 }
9364
9365 /* If the result is a relative path name, make it explicitly relative to
9366 * the current directory if and only if the argument had this form. */
9367 if (!vim_ispathsep(*p))
9368 {
9369 if (is_relative_to_current
9370 && *p != NUL
9371 && !(p[0] == '.'
9372 && (p[1] == NUL
9373 || vim_ispathsep(p[1])
9374 || (p[1] == '.'
9375 && (p[2] == NUL
9376 || vim_ispathsep(p[2]))))))
9377 {
9378 /* Prepend "./". */
9379 cpy = concat_str((char_u *)"./", p);
9380 if (cpy != NULL)
9381 {
9382 vim_free(p);
9383 p = cpy;
9384 }
9385 }
9386 else if (!is_relative_to_current)
9387 {
9388 /* Strip leading "./". */
9389 q = p;
9390 while (q[0] == '.' && vim_ispathsep(q[1]))
9391 q += 2;
9392 if (q > p)
9393 STRMOVE(p, p + 2);
9394 }
9395 }
9396
9397 /* Ensure that the result will have no trailing path separator
9398 * if the argument had none. But keep "/" or "//". */
9399 if (!has_trailing_pathsep)
9400 {
9401 q = p + STRLEN(p);
9402 if (after_pathsep(p, q))
9403 *gettail_sep(p) = NUL;
9404 }
9405
9406 rettv->vval.v_string = p;
9407 }
9408# else
9409 rettv->vval.v_string = vim_strsave(p);
9410# endif
9411#endif
9412
9413 simplify_filename(rettv->vval.v_string);
9414
9415#ifdef HAVE_READLINK
9416fail:
9417 vim_free(buf);
9418#endif
9419 rettv->v_type = VAR_STRING;
9420}
9421
9422/*
9423 * "reverse({list})" function
9424 */
9425 static void
9426f_reverse(typval_T *argvars, typval_T *rettv)
9427{
9428 list_T *l;
9429 listitem_T *li, *ni;
9430
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009431 if (argvars[0].v_type == VAR_BLOB)
9432 {
9433 blob_T *b = argvars[0].vval.v_blob;
9434 int i, len = blob_len(b);
9435
9436 for (i = 0; i < len / 2; i++)
9437 {
9438 int tmp = blob_get(b, i);
9439
9440 blob_set(b, i, blob_get(b, len - i - 1));
9441 blob_set(b, len - i - 1, tmp);
9442 }
9443 rettv_blob_set(rettv, b);
9444 return;
9445 }
9446
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009447 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009448 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009449 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009450 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009451 (char_u *)N_("reverse() argument"), TRUE))
9452 {
9453 li = l->lv_last;
9454 l->lv_first = l->lv_last = NULL;
9455 l->lv_len = 0;
9456 while (li != NULL)
9457 {
9458 ni = li->li_prev;
9459 list_append(l, li);
9460 li = ni;
9461 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009462 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009463 l->lv_idx = l->lv_len - l->lv_idx - 1;
9464 }
9465}
9466
9467#define SP_NOMOVE 0x01 /* don't move cursor */
9468#define SP_REPEAT 0x02 /* repeat to find outer pair */
9469#define SP_RETCOUNT 0x04 /* return matchcount */
9470#define SP_SETPCMARK 0x08 /* set previous context mark */
9471#define SP_START 0x10 /* accept match at start position */
9472#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9473#define SP_END 0x40 /* leave cursor at end of match */
9474#define SP_COLUMN 0x80 /* start at cursor column */
9475
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009476/*
9477 * Get flags for a search function.
9478 * Possibly sets "p_ws".
9479 * Returns BACKWARD, FORWARD or zero (for an error).
9480 */
9481 static int
9482get_search_arg(typval_T *varp, int *flagsp)
9483{
9484 int dir = FORWARD;
9485 char_u *flags;
9486 char_u nbuf[NUMBUFLEN];
9487 int mask;
9488
9489 if (varp->v_type != VAR_UNKNOWN)
9490 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009491 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492 if (flags == NULL)
9493 return 0; /* type error; errmsg already given */
9494 while (*flags != NUL)
9495 {
9496 switch (*flags)
9497 {
9498 case 'b': dir = BACKWARD; break;
9499 case 'w': p_ws = TRUE; break;
9500 case 'W': p_ws = FALSE; break;
9501 default: mask = 0;
9502 if (flagsp != NULL)
9503 switch (*flags)
9504 {
9505 case 'c': mask = SP_START; break;
9506 case 'e': mask = SP_END; break;
9507 case 'm': mask = SP_RETCOUNT; break;
9508 case 'n': mask = SP_NOMOVE; break;
9509 case 'p': mask = SP_SUBPAT; break;
9510 case 'r': mask = SP_REPEAT; break;
9511 case 's': mask = SP_SETPCMARK; break;
9512 case 'z': mask = SP_COLUMN; break;
9513 }
9514 if (mask == 0)
9515 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009516 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009517 dir = 0;
9518 }
9519 else
9520 *flagsp |= mask;
9521 }
9522 if (dir == 0)
9523 break;
9524 ++flags;
9525 }
9526 }
9527 return dir;
9528}
9529
9530/*
9531 * Shared by search() and searchpos() functions.
9532 */
9533 static int
9534search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9535{
9536 int flags;
9537 char_u *pat;
9538 pos_T pos;
9539 pos_T save_cursor;
9540 int save_p_ws = p_ws;
9541 int dir;
9542 int retval = 0; /* default: FAIL */
9543 long lnum_stop = 0;
9544 proftime_T tm;
9545#ifdef FEAT_RELTIME
9546 long time_limit = 0;
9547#endif
9548 int options = SEARCH_KEEP;
9549 int subpatnum;
9550
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009551 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009552 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9553 if (dir == 0)
9554 goto theend;
9555 flags = *flagsp;
9556 if (flags & SP_START)
9557 options |= SEARCH_START;
9558 if (flags & SP_END)
9559 options |= SEARCH_END;
9560 if (flags & SP_COLUMN)
9561 options |= SEARCH_COL;
9562
9563 /* Optional arguments: line number to stop searching and timeout. */
9564 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9565 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009566 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009567 if (lnum_stop < 0)
9568 goto theend;
9569#ifdef FEAT_RELTIME
9570 if (argvars[3].v_type != VAR_UNKNOWN)
9571 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009572 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009573 if (time_limit < 0)
9574 goto theend;
9575 }
9576#endif
9577 }
9578
9579#ifdef FEAT_RELTIME
9580 /* Set the time limit, if there is one. */
9581 profile_setlimit(time_limit, &tm);
9582#endif
9583
9584 /*
9585 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9586 * Check to make sure only those flags are set.
9587 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9588 * flags cannot be set. Check for that condition also.
9589 */
9590 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9591 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9592 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009593 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009594 goto theend;
9595 }
9596
9597 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009598 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009599 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009600 if (subpatnum != FAIL)
9601 {
9602 if (flags & SP_SUBPAT)
9603 retval = subpatnum;
9604 else
9605 retval = pos.lnum;
9606 if (flags & SP_SETPCMARK)
9607 setpcmark();
9608 curwin->w_cursor = pos;
9609 if (match_pos != NULL)
9610 {
9611 /* Store the match cursor position */
9612 match_pos->lnum = pos.lnum;
9613 match_pos->col = pos.col + 1;
9614 }
9615 /* "/$" will put the cursor after the end of the line, may need to
9616 * correct that here */
9617 check_cursor();
9618 }
9619
9620 /* If 'n' flag is used: restore cursor position. */
9621 if (flags & SP_NOMOVE)
9622 curwin->w_cursor = save_cursor;
9623 else
9624 curwin->w_set_curswant = TRUE;
9625theend:
9626 p_ws = save_p_ws;
9627
9628 return retval;
9629}
9630
9631#ifdef FEAT_FLOAT
9632
9633/*
9634 * round() is not in C90, use ceil() or floor() instead.
9635 */
9636 float_T
9637vim_round(float_T f)
9638{
9639 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9640}
9641
9642/*
9643 * "round({float})" function
9644 */
9645 static void
9646f_round(typval_T *argvars, typval_T *rettv)
9647{
9648 float_T f = 0.0;
9649
9650 rettv->v_type = VAR_FLOAT;
9651 if (get_float_arg(argvars, &f) == OK)
9652 rettv->vval.v_float = vim_round(f);
9653 else
9654 rettv->vval.v_float = 0.0;
9655}
9656#endif
9657
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009658#ifdef FEAT_RUBY
9659/*
9660 * "rubyeval()" function
9661 */
9662 static void
9663f_rubyeval(typval_T *argvars, typval_T *rettv)
9664{
9665 char_u *str;
9666 char_u buf[NUMBUFLEN];
9667
9668 str = tv_get_string_buf(&argvars[0], buf);
9669 do_rubyeval(str, rettv);
9670}
9671#endif
9672
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009673/*
9674 * "screenattr()" function
9675 */
9676 static void
9677f_screenattr(typval_T *argvars, typval_T *rettv)
9678{
9679 int row;
9680 int col;
9681 int c;
9682
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009683 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9684 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009685 if (row < 0 || row >= screen_Rows
9686 || col < 0 || col >= screen_Columns)
9687 c = -1;
9688 else
9689 c = ScreenAttrs[LineOffset[row] + col];
9690 rettv->vval.v_number = c;
9691}
9692
9693/*
9694 * "screenchar()" function
9695 */
9696 static void
9697f_screenchar(typval_T *argvars, typval_T *rettv)
9698{
9699 int row;
9700 int col;
9701 int off;
9702 int c;
9703
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009704 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9705 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009706 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009707 c = -1;
9708 else
9709 {
9710 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009711 if (enc_utf8 && ScreenLinesUC[off] != 0)
9712 c = ScreenLinesUC[off];
9713 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009714 c = ScreenLines[off];
9715 }
9716 rettv->vval.v_number = c;
9717}
9718
9719/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009720 * "screenchars()" function
9721 */
9722 static void
9723f_screenchars(typval_T *argvars, typval_T *rettv)
9724{
9725 int row;
9726 int col;
9727 int off;
9728 int c;
9729 int i;
9730
9731 if (rettv_list_alloc(rettv) == FAIL)
9732 return;
9733 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9734 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9735 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9736 return;
9737
9738 off = LineOffset[row] + col;
9739 if (enc_utf8 && ScreenLinesUC[off] != 0)
9740 c = ScreenLinesUC[off];
9741 else
9742 c = ScreenLines[off];
9743 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9744
9745 if (enc_utf8)
9746
9747 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9748 list_append_number(rettv->vval.v_list,
9749 (varnumber_T)ScreenLinesC[i][off]);
9750}
9751
9752/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009753 * "screencol()" function
9754 *
9755 * First column is 1 to be consistent with virtcol().
9756 */
9757 static void
9758f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9759{
9760 rettv->vval.v_number = screen_screencol() + 1;
9761}
9762
9763/*
9764 * "screenrow()" function
9765 */
9766 static void
9767f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9768{
9769 rettv->vval.v_number = screen_screenrow() + 1;
9770}
9771
9772/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009773 * "screenstring()" function
9774 */
9775 static void
9776f_screenstring(typval_T *argvars, typval_T *rettv)
9777{
9778 int row;
9779 int col;
9780 int off;
9781 int c;
9782 int i;
9783 char_u buf[MB_MAXBYTES + 1];
9784 int buflen = 0;
9785
9786 rettv->vval.v_string = NULL;
9787 rettv->v_type = VAR_STRING;
9788
9789 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9790 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9791 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9792 return;
9793
9794 off = LineOffset[row] + col;
9795 if (enc_utf8 && ScreenLinesUC[off] != 0)
9796 c = ScreenLinesUC[off];
9797 else
9798 c = ScreenLines[off];
9799 buflen += mb_char2bytes(c, buf);
9800
9801 if (enc_utf8)
9802 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9803 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9804
9805 buf[buflen] = NUL;
9806 rettv->vval.v_string = vim_strsave(buf);
9807}
9808
9809/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009810 * "search()" function
9811 */
9812 static void
9813f_search(typval_T *argvars, typval_T *rettv)
9814{
9815 int flags = 0;
9816
9817 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9818}
9819
9820/*
9821 * "searchdecl()" function
9822 */
9823 static void
9824f_searchdecl(typval_T *argvars, typval_T *rettv)
9825{
9826 int locally = 1;
9827 int thisblock = 0;
9828 int error = FALSE;
9829 char_u *name;
9830
9831 rettv->vval.v_number = 1; /* default: FAIL */
9832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009833 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009834 if (argvars[1].v_type != VAR_UNKNOWN)
9835 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009836 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009837 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009838 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009839 }
9840 if (!error && name != NULL)
9841 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9842 locally, thisblock, SEARCH_KEEP) == FAIL;
9843}
9844
9845/*
9846 * Used by searchpair() and searchpairpos()
9847 */
9848 static int
9849searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9850{
9851 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009852 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009853 int save_p_ws = p_ws;
9854 int dir;
9855 int flags = 0;
9856 char_u nbuf1[NUMBUFLEN];
9857 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009858 int retval = 0; /* default: FAIL */
9859 long lnum_stop = 0;
9860 long time_limit = 0;
9861
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009862 /* Get the three pattern arguments: start, middle, end. Will result in an
9863 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009864 spat = tv_get_string_chk(&argvars[0]);
9865 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9866 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009867 if (spat == NULL || mpat == NULL || epat == NULL)
9868 goto theend; /* type error */
9869
9870 /* Handle the optional fourth argument: flags */
9871 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9872 if (dir == 0)
9873 goto theend;
9874
9875 /* Don't accept SP_END or SP_SUBPAT.
9876 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9877 */
9878 if ((flags & (SP_END | SP_SUBPAT)) != 0
9879 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9880 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009881 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009882 goto theend;
9883 }
9884
9885 /* Using 'r' implies 'W', otherwise it doesn't work. */
9886 if (flags & SP_REPEAT)
9887 p_ws = FALSE;
9888
9889 /* Optional fifth argument: skip expression */
9890 if (argvars[3].v_type == VAR_UNKNOWN
9891 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009892 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009893 else
9894 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009895 skip = &argvars[4];
9896 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9897 && skip->v_type != VAR_STRING)
9898 {
9899 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009900 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009901 goto theend;
9902 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009903 if (argvars[5].v_type != VAR_UNKNOWN)
9904 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009905 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009906 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009907 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009908 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009909 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009910 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009911#ifdef FEAT_RELTIME
9912 if (argvars[6].v_type != VAR_UNKNOWN)
9913 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009914 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009915 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009916 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009917 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009918 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009919 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009920 }
9921#endif
9922 }
9923 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009924
9925 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9926 match_pos, lnum_stop, time_limit);
9927
9928theend:
9929 p_ws = save_p_ws;
9930
9931 return retval;
9932}
9933
9934/*
9935 * "searchpair()" function
9936 */
9937 static void
9938f_searchpair(typval_T *argvars, typval_T *rettv)
9939{
9940 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9941}
9942
9943/*
9944 * "searchpairpos()" function
9945 */
9946 static void
9947f_searchpairpos(typval_T *argvars, typval_T *rettv)
9948{
9949 pos_T match_pos;
9950 int lnum = 0;
9951 int col = 0;
9952
9953 if (rettv_list_alloc(rettv) == FAIL)
9954 return;
9955
9956 if (searchpair_cmn(argvars, &match_pos) > 0)
9957 {
9958 lnum = match_pos.lnum;
9959 col = match_pos.col;
9960 }
9961
9962 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9963 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9964}
9965
9966/*
9967 * Search for a start/middle/end thing.
9968 * Used by searchpair(), see its documentation for the details.
9969 * Returns 0 or -1 for no match,
9970 */
9971 long
9972do_searchpair(
9973 char_u *spat, /* start pattern */
9974 char_u *mpat, /* middle pattern */
9975 char_u *epat, /* end pattern */
9976 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009977 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009978 int flags, /* SP_SETPCMARK and other SP_ values */
9979 pos_T *match_pos,
9980 linenr_T lnum_stop, /* stop at this line if not zero */
9981 long time_limit UNUSED) /* stop after this many msec */
9982{
9983 char_u *save_cpo;
9984 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9985 long retval = 0;
9986 pos_T pos;
9987 pos_T firstpos;
9988 pos_T foundpos;
9989 pos_T save_cursor;
9990 pos_T save_pos;
9991 int n;
9992 int r;
9993 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009994 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009995 int err;
9996 int options = SEARCH_KEEP;
9997 proftime_T tm;
9998
9999 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10000 save_cpo = p_cpo;
10001 p_cpo = empty_option;
10002
10003#ifdef FEAT_RELTIME
10004 /* Set the time limit, if there is one. */
10005 profile_setlimit(time_limit, &tm);
10006#endif
10007
10008 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10009 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +020010010 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
10011 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010012 if (pat2 == NULL || pat3 == NULL)
10013 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010014 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010015 if (*mpat == NUL)
10016 STRCPY(pat3, pat2);
10017 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010018 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019 spat, epat, mpat);
10020 if (flags & SP_START)
10021 options |= SEARCH_START;
10022
Bram Moolenaar48570482017-10-30 21:48:41 +010010023 if (skip != NULL)
10024 {
10025 /* Empty string means to not use the skip expression. */
10026 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10027 use_skip = skip->vval.v_string != NULL
10028 && *skip->vval.v_string != NUL;
10029 }
10030
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010031 save_cursor = curwin->w_cursor;
10032 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010033 CLEAR_POS(&firstpos);
10034 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010035 pat = pat3;
10036 for (;;)
10037 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010038 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010039 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010040 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010041 /* didn't find it or found the first match again: FAIL */
10042 break;
10043
10044 if (firstpos.lnum == 0)
10045 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010046 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010047 {
10048 /* Found the same position again. Can happen with a pattern that
10049 * has "\zs" at the end and searching backwards. Advance one
10050 * character and try again. */
10051 if (dir == BACKWARD)
10052 decl(&pos);
10053 else
10054 incl(&pos);
10055 }
10056 foundpos = pos;
10057
10058 /* clear the start flag to avoid getting stuck here */
10059 options &= ~SEARCH_START;
10060
10061 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010062 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010063 {
10064 save_pos = curwin->w_cursor;
10065 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010066 err = FALSE;
10067 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010068 curwin->w_cursor = save_pos;
10069 if (err)
10070 {
10071 /* Evaluating {skip} caused an error, break here. */
10072 curwin->w_cursor = save_cursor;
10073 retval = -1;
10074 break;
10075 }
10076 if (r)
10077 continue;
10078 }
10079
10080 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10081 {
10082 /* Found end when searching backwards or start when searching
10083 * forward: nested pair. */
10084 ++nest;
10085 pat = pat2; /* nested, don't search for middle */
10086 }
10087 else
10088 {
10089 /* Found end when searching forward or start when searching
10090 * backward: end of (nested) pair; or found middle in outer pair. */
10091 if (--nest == 1)
10092 pat = pat3; /* outer level, search for middle */
10093 }
10094
10095 if (nest == 0)
10096 {
10097 /* Found the match: return matchcount or line number. */
10098 if (flags & SP_RETCOUNT)
10099 ++retval;
10100 else
10101 retval = pos.lnum;
10102 if (flags & SP_SETPCMARK)
10103 setpcmark();
10104 curwin->w_cursor = pos;
10105 if (!(flags & SP_REPEAT))
10106 break;
10107 nest = 1; /* search for next unmatched */
10108 }
10109 }
10110
10111 if (match_pos != NULL)
10112 {
10113 /* Store the match cursor position */
10114 match_pos->lnum = curwin->w_cursor.lnum;
10115 match_pos->col = curwin->w_cursor.col + 1;
10116 }
10117
10118 /* If 'n' flag is used or search failed: restore cursor position. */
10119 if ((flags & SP_NOMOVE) || retval == 0)
10120 curwin->w_cursor = save_cursor;
10121
10122theend:
10123 vim_free(pat2);
10124 vim_free(pat3);
10125 if (p_cpo == empty_option)
10126 p_cpo = save_cpo;
10127 else
10128 /* Darn, evaluating the {skip} expression changed the value. */
10129 free_string_option(save_cpo);
10130
10131 return retval;
10132}
10133
10134/*
10135 * "searchpos()" function
10136 */
10137 static void
10138f_searchpos(typval_T *argvars, typval_T *rettv)
10139{
10140 pos_T match_pos;
10141 int lnum = 0;
10142 int col = 0;
10143 int n;
10144 int flags = 0;
10145
10146 if (rettv_list_alloc(rettv) == FAIL)
10147 return;
10148
10149 n = search_cmn(argvars, &match_pos, &flags);
10150 if (n > 0)
10151 {
10152 lnum = match_pos.lnum;
10153 col = match_pos.col;
10154 }
10155
10156 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10157 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10158 if (flags & SP_SUBPAT)
10159 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10160}
10161
10162 static void
10163f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10164{
10165#ifdef FEAT_CLIENTSERVER
10166 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010167 char_u *server = tv_get_string_chk(&argvars[0]);
10168 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010169
10170 rettv->vval.v_number = -1;
10171 if (server == NULL || reply == NULL)
10172 return;
10173 if (check_restricted() || check_secure())
10174 return;
10175# ifdef FEAT_X11
10176 if (check_connection() == FAIL)
10177 return;
10178# endif
10179
10180 if (serverSendReply(server, reply) < 0)
10181 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010182 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010183 return;
10184 }
10185 rettv->vval.v_number = 0;
10186#else
10187 rettv->vval.v_number = -1;
10188#endif
10189}
10190
10191 static void
10192f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10193{
10194 char_u *r = NULL;
10195
10196#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010197# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010198 r = serverGetVimNames();
10199# else
10200 make_connection();
10201 if (X_DISPLAY != NULL)
10202 r = serverGetVimNames(X_DISPLAY);
10203# endif
10204#endif
10205 rettv->v_type = VAR_STRING;
10206 rettv->vval.v_string = r;
10207}
10208
10209/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010210 * "setbufline()" function
10211 */
10212 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010213f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010214{
10215 linenr_T lnum;
10216 buf_T *buf;
10217
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010218 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010219 if (buf == NULL)
10220 rettv->vval.v_number = 1; /* FAIL */
10221 else
10222 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010223 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010224 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010225 }
10226}
10227
10228/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010229 * "setbufvar()" function
10230 */
10231 static void
10232f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10233{
10234 buf_T *buf;
10235 char_u *varname, *bufvarname;
10236 typval_T *varp;
10237 char_u nbuf[NUMBUFLEN];
10238
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010239 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010240 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010241 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10242 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010243 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 varp = &argvars[2];
10245
10246 if (buf != NULL && varname != NULL && varp != NULL)
10247 {
10248 if (*varname == '&')
10249 {
10250 long numval;
10251 char_u *strval;
10252 int error = FALSE;
10253 aco_save_T aco;
10254
10255 /* set curbuf to be our buf, temporarily */
10256 aucmd_prepbuf(&aco, buf);
10257
10258 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010259 numval = (long)tv_get_number_chk(varp, &error);
10260 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010261 if (!error && strval != NULL)
10262 set_option_value(varname, numval, strval, OPT_LOCAL);
10263
10264 /* reset notion of buffer */
10265 aucmd_restbuf(&aco);
10266 }
10267 else
10268 {
10269 buf_T *save_curbuf = curbuf;
10270
Bram Moolenaar964b3742019-05-24 18:54:09 +020010271 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010272 if (bufvarname != NULL)
10273 {
10274 curbuf = buf;
10275 STRCPY(bufvarname, "b:");
10276 STRCPY(bufvarname + 2, varname);
10277 set_var(bufvarname, varp, TRUE);
10278 vim_free(bufvarname);
10279 curbuf = save_curbuf;
10280 }
10281 }
10282 }
10283}
10284
10285 static void
10286f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10287{
10288 dict_T *d;
10289 dictitem_T *di;
10290 char_u *csearch;
10291
10292 if (argvars[0].v_type != VAR_DICT)
10293 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010294 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010295 return;
10296 }
10297
10298 if ((d = argvars[0].vval.v_dict) != NULL)
10299 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010300 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010301 if (csearch != NULL)
10302 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010303 if (enc_utf8)
10304 {
10305 int pcc[MAX_MCO];
10306 int c = utfc_ptr2char(csearch, pcc);
10307
10308 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10309 }
10310 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010311 set_last_csearch(PTR2CHAR(csearch),
10312 csearch, MB_PTR2LEN(csearch));
10313 }
10314
10315 di = dict_find(d, (char_u *)"forward", -1);
10316 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010317 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010318 ? FORWARD : BACKWARD);
10319
10320 di = dict_find(d, (char_u *)"until", -1);
10321 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010322 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010323 }
10324}
10325
10326/*
10327 * "setcmdpos()" function
10328 */
10329 static void
10330f_setcmdpos(typval_T *argvars, typval_T *rettv)
10331{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010332 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010333
10334 if (pos >= 0)
10335 rettv->vval.v_number = set_cmdline_pos(pos);
10336}
10337
10338/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010339 * "setenv()" function
10340 */
10341 static void
10342f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10343{
10344 char_u namebuf[NUMBUFLEN];
10345 char_u valbuf[NUMBUFLEN];
10346 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10347
10348 if (argvars[1].v_type == VAR_SPECIAL
10349 && argvars[1].vval.v_number == VVAL_NULL)
10350 vim_unsetenv(name);
10351 else
10352 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10353}
10354
10355/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010356 * "setfperm({fname}, {mode})" function
10357 */
10358 static void
10359f_setfperm(typval_T *argvars, typval_T *rettv)
10360{
10361 char_u *fname;
10362 char_u modebuf[NUMBUFLEN];
10363 char_u *mode_str;
10364 int i;
10365 int mask;
10366 int mode = 0;
10367
10368 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010369 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010370 if (fname == NULL)
10371 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010372 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010373 if (mode_str == NULL)
10374 return;
10375 if (STRLEN(mode_str) != 9)
10376 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010377 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010378 return;
10379 }
10380
10381 mask = 1;
10382 for (i = 8; i >= 0; --i)
10383 {
10384 if (mode_str[i] != '-')
10385 mode |= mask;
10386 mask = mask << 1;
10387 }
10388 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10389}
10390
10391/*
10392 * "setline()" function
10393 */
10394 static void
10395f_setline(typval_T *argvars, typval_T *rettv)
10396{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010397 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010398
Bram Moolenaarca851592018-06-06 21:04:07 +020010399 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400}
10401
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010402/*
10403 * Used by "setqflist()" and "setloclist()" functions
10404 */
10405 static void
10406set_qf_ll_list(
10407 win_T *wp UNUSED,
10408 typval_T *list_arg UNUSED,
10409 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010410 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010411 typval_T *rettv)
10412{
10413#ifdef FEAT_QUICKFIX
10414 static char *e_invact = N_("E927: Invalid action: '%s'");
10415 char_u *act;
10416 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010417 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010418#endif
10419
10420 rettv->vval.v_number = -1;
10421
10422#ifdef FEAT_QUICKFIX
10423 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010424 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010425 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010426 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010427 else
10428 {
10429 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010430 dict_T *d = NULL;
10431 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010432
10433 if (action_arg->v_type == VAR_STRING)
10434 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010435 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010436 if (act == NULL)
10437 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010438 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10439 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010440 action = *act;
10441 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010442 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010443 }
10444 else if (action_arg->v_type == VAR_UNKNOWN)
10445 action = ' ';
10446 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010447 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010448
Bram Moolenaard823fa92016-08-12 16:29:27 +020010449 if (action_arg->v_type != VAR_UNKNOWN
10450 && what_arg->v_type != VAR_UNKNOWN)
10451 {
10452 if (what_arg->v_type == VAR_DICT)
10453 d = what_arg->vval.v_dict;
10454 else
10455 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010456 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010457 valid_dict = FALSE;
10458 }
10459 }
10460
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010461 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010462 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010463 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10464 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010465 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010466 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010467 }
10468#endif
10469}
10470
10471/*
10472 * "setloclist()" function
10473 */
10474 static void
10475f_setloclist(typval_T *argvars, typval_T *rettv)
10476{
10477 win_T *win;
10478
10479 rettv->vval.v_number = -1;
10480
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010481 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010482 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010483 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010484}
10485
10486/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010487 * "setpos()" function
10488 */
10489 static void
10490f_setpos(typval_T *argvars, typval_T *rettv)
10491{
10492 pos_T pos;
10493 int fnum;
10494 char_u *name;
10495 colnr_T curswant = -1;
10496
10497 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010498 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010499 if (name != NULL)
10500 {
10501 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10502 {
10503 if (--pos.col < 0)
10504 pos.col = 0;
10505 if (name[0] == '.' && name[1] == NUL)
10506 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010507 /* set cursor; "fnum" is ignored */
10508 curwin->w_cursor = pos;
10509 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010510 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010511 curwin->w_curswant = curswant - 1;
10512 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010513 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010514 check_cursor();
10515 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010516 }
10517 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10518 {
10519 /* set mark */
10520 if (setmark_pos(name[1], &pos, fnum) == OK)
10521 rettv->vval.v_number = 0;
10522 }
10523 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010524 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010525 }
10526 }
10527}
10528
10529/*
10530 * "setqflist()" function
10531 */
10532 static void
10533f_setqflist(typval_T *argvars, typval_T *rettv)
10534{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010535 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010536}
10537
10538/*
10539 * "setreg()" function
10540 */
10541 static void
10542f_setreg(typval_T *argvars, typval_T *rettv)
10543{
10544 int regname;
10545 char_u *strregname;
10546 char_u *stropt;
10547 char_u *strval;
10548 int append;
10549 char_u yank_type;
10550 long block_len;
10551
10552 block_len = -1;
10553 yank_type = MAUTO;
10554 append = FALSE;
10555
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010556 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010557 rettv->vval.v_number = 1; /* FAIL is default */
10558
10559 if (strregname == NULL)
10560 return; /* type error; errmsg already given */
10561 regname = *strregname;
10562 if (regname == 0 || regname == '@')
10563 regname = '"';
10564
10565 if (argvars[2].v_type != VAR_UNKNOWN)
10566 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010567 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010568 if (stropt == NULL)
10569 return; /* type error */
10570 for (; *stropt != NUL; ++stropt)
10571 switch (*stropt)
10572 {
10573 case 'a': case 'A': /* append */
10574 append = TRUE;
10575 break;
10576 case 'v': case 'c': /* character-wise selection */
10577 yank_type = MCHAR;
10578 break;
10579 case 'V': case 'l': /* line-wise selection */
10580 yank_type = MLINE;
10581 break;
10582 case 'b': case Ctrl_V: /* block-wise selection */
10583 yank_type = MBLOCK;
10584 if (VIM_ISDIGIT(stropt[1]))
10585 {
10586 ++stropt;
10587 block_len = getdigits(&stropt) - 1;
10588 --stropt;
10589 }
10590 break;
10591 }
10592 }
10593
10594 if (argvars[1].v_type == VAR_LIST)
10595 {
10596 char_u **lstval;
10597 char_u **allocval;
10598 char_u buf[NUMBUFLEN];
10599 char_u **curval;
10600 char_u **curallocval;
10601 list_T *ll = argvars[1].vval.v_list;
10602 listitem_T *li;
10603 int len;
10604
10605 /* If the list is NULL handle like an empty list. */
10606 len = ll == NULL ? 0 : ll->lv_len;
10607
10608 /* First half: use for pointers to result lines; second half: use for
10609 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010610 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010611 if (lstval == NULL)
10612 return;
10613 curval = lstval;
10614 allocval = lstval + len + 2;
10615 curallocval = allocval;
10616
10617 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10618 li = li->li_next)
10619 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010620 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010621 if (strval == NULL)
10622 goto free_lstval;
10623 if (strval == buf)
10624 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010625 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010626 * overwrite the string. */
10627 strval = vim_strsave(buf);
10628 if (strval == NULL)
10629 goto free_lstval;
10630 *curallocval++ = strval;
10631 }
10632 *curval++ = strval;
10633 }
10634 *curval++ = NULL;
10635
10636 write_reg_contents_lst(regname, lstval, -1,
10637 append, yank_type, block_len);
10638free_lstval:
10639 while (curallocval > allocval)
10640 vim_free(*--curallocval);
10641 vim_free(lstval);
10642 }
10643 else
10644 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010645 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010646 if (strval == NULL)
10647 return;
10648 write_reg_contents_ex(regname, strval, -1,
10649 append, yank_type, block_len);
10650 }
10651 rettv->vval.v_number = 0;
10652}
10653
10654/*
10655 * "settabvar()" function
10656 */
10657 static void
10658f_settabvar(typval_T *argvars, typval_T *rettv)
10659{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660 tabpage_T *save_curtab;
10661 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010662 char_u *varname, *tabvarname;
10663 typval_T *varp;
10664
10665 rettv->vval.v_number = 0;
10666
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010667 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668 return;
10669
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010670 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10671 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010672 varp = &argvars[2];
10673
Bram Moolenaar4033c552017-09-16 20:54:51 +020010674 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010676 save_curtab = curtab;
10677 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010678
Bram Moolenaar964b3742019-05-24 18:54:09 +020010679 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010680 if (tabvarname != NULL)
10681 {
10682 STRCPY(tabvarname, "t:");
10683 STRCPY(tabvarname + 2, varname);
10684 set_var(tabvarname, varp, TRUE);
10685 vim_free(tabvarname);
10686 }
10687
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010688 /* Restore current tabpage */
10689 if (valid_tabpage(save_curtab))
10690 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010691 }
10692}
10693
10694/*
10695 * "settabwinvar()" function
10696 */
10697 static void
10698f_settabwinvar(typval_T *argvars, typval_T *rettv)
10699{
10700 setwinvar(argvars, rettv, 1);
10701}
10702
10703/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010704 * "settagstack()" function
10705 */
10706 static void
10707f_settagstack(typval_T *argvars, typval_T *rettv)
10708{
10709 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10710 win_T *wp;
10711 dict_T *d;
10712 int action = 'r';
10713
10714 rettv->vval.v_number = -1;
10715
10716 // first argument: window number or id
10717 wp = find_win_by_nr_or_id(&argvars[0]);
10718 if (wp == NULL)
10719 return;
10720
10721 // second argument: dict with items to set in the tag stack
10722 if (argvars[1].v_type != VAR_DICT)
10723 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010724 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010725 return;
10726 }
10727 d = argvars[1].vval.v_dict;
10728 if (d == NULL)
10729 return;
10730
10731 // third argument: action - 'a' for append and 'r' for replace.
10732 // default is to replace the stack.
10733 if (argvars[2].v_type == VAR_UNKNOWN)
10734 action = 'r';
10735 else if (argvars[2].v_type == VAR_STRING)
10736 {
10737 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010738 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010739 if (actstr == NULL)
10740 return;
10741 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10742 action = *actstr;
10743 else
10744 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010745 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010746 return;
10747 }
10748 }
10749 else
10750 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010751 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010752 return;
10753 }
10754
10755 if (set_tagstack(wp, d, action) == OK)
10756 rettv->vval.v_number = 0;
10757}
10758
10759/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010760 * "setwinvar()" function
10761 */
10762 static void
10763f_setwinvar(typval_T *argvars, typval_T *rettv)
10764{
10765 setwinvar(argvars, rettv, 0);
10766}
10767
10768#ifdef FEAT_CRYPT
10769/*
10770 * "sha256({string})" function
10771 */
10772 static void
10773f_sha256(typval_T *argvars, typval_T *rettv)
10774{
10775 char_u *p;
10776
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010777 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010778 rettv->vval.v_string = vim_strsave(
10779 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10780 rettv->v_type = VAR_STRING;
10781}
10782#endif /* FEAT_CRYPT */
10783
10784/*
10785 * "shellescape({string})" function
10786 */
10787 static void
10788f_shellescape(typval_T *argvars, typval_T *rettv)
10789{
Bram Moolenaar20615522017-06-05 18:46:26 +020010790 int do_special = non_zero_arg(&argvars[1]);
10791
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010792 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010793 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010794 rettv->v_type = VAR_STRING;
10795}
10796
10797/*
10798 * shiftwidth() function
10799 */
10800 static void
10801f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10802{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010803 rettv->vval.v_number = 0;
10804
10805 if (argvars[0].v_type != VAR_UNKNOWN)
10806 {
10807 long col;
10808
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010809 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010810 if (col < 0)
10811 return; // type error; errmsg already given
10812#ifdef FEAT_VARTABS
10813 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10814 return;
10815#endif
10816 }
10817
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010818 rettv->vval.v_number = get_sw_value(curbuf);
10819}
10820
10821/*
10822 * "simplify()" function
10823 */
10824 static void
10825f_simplify(typval_T *argvars, typval_T *rettv)
10826{
10827 char_u *p;
10828
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010829 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 rettv->vval.v_string = vim_strsave(p);
10831 simplify_filename(rettv->vval.v_string); /* simplify in place */
10832 rettv->v_type = VAR_STRING;
10833}
10834
10835#ifdef FEAT_FLOAT
10836/*
10837 * "sin()" function
10838 */
10839 static void
10840f_sin(typval_T *argvars, typval_T *rettv)
10841{
10842 float_T f = 0.0;
10843
10844 rettv->v_type = VAR_FLOAT;
10845 if (get_float_arg(argvars, &f) == OK)
10846 rettv->vval.v_float = sin(f);
10847 else
10848 rettv->vval.v_float = 0.0;
10849}
10850
10851/*
10852 * "sinh()" function
10853 */
10854 static void
10855f_sinh(typval_T *argvars, typval_T *rettv)
10856{
10857 float_T f = 0.0;
10858
10859 rettv->v_type = VAR_FLOAT;
10860 if (get_float_arg(argvars, &f) == OK)
10861 rettv->vval.v_float = sinh(f);
10862 else
10863 rettv->vval.v_float = 0.0;
10864}
10865#endif
10866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010867/*
10868 * "soundfold({word})" function
10869 */
10870 static void
10871f_soundfold(typval_T *argvars, typval_T *rettv)
10872{
10873 char_u *s;
10874
10875 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010876 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010877#ifdef FEAT_SPELL
10878 rettv->vval.v_string = eval_soundfold(s);
10879#else
10880 rettv->vval.v_string = vim_strsave(s);
10881#endif
10882}
10883
10884/*
10885 * "spellbadword()" function
10886 */
10887 static void
10888f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10889{
10890 char_u *word = (char_u *)"";
10891 hlf_T attr = HLF_COUNT;
10892 int len = 0;
10893
10894 if (rettv_list_alloc(rettv) == FAIL)
10895 return;
10896
10897#ifdef FEAT_SPELL
10898 if (argvars[0].v_type == VAR_UNKNOWN)
10899 {
10900 /* Find the start and length of the badly spelled word. */
10901 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10902 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010903 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010904 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010905 curwin->w_set_curswant = TRUE;
10906 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010907 }
10908 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10909 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010910 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010911 int capcol = -1;
10912
10913 if (str != NULL)
10914 {
10915 /* Check the argument for spelling. */
10916 while (*str != NUL)
10917 {
10918 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10919 if (attr != HLF_COUNT)
10920 {
10921 word = str;
10922 break;
10923 }
10924 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010925 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010926 }
10927 }
10928 }
10929#endif
10930
10931 list_append_string(rettv->vval.v_list, word, len);
10932 list_append_string(rettv->vval.v_list, (char_u *)(
10933 attr == HLF_SPB ? "bad" :
10934 attr == HLF_SPR ? "rare" :
10935 attr == HLF_SPL ? "local" :
10936 attr == HLF_SPC ? "caps" :
10937 ""), -1);
10938}
10939
10940/*
10941 * "spellsuggest()" function
10942 */
10943 static void
10944f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10945{
10946#ifdef FEAT_SPELL
10947 char_u *str;
10948 int typeerr = FALSE;
10949 int maxcount;
10950 garray_T ga;
10951 int i;
10952 listitem_T *li;
10953 int need_capital = FALSE;
10954#endif
10955
10956 if (rettv_list_alloc(rettv) == FAIL)
10957 return;
10958
10959#ifdef FEAT_SPELL
10960 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10961 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010962 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010963 if (argvars[1].v_type != VAR_UNKNOWN)
10964 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010965 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010966 if (maxcount <= 0)
10967 return;
10968 if (argvars[2].v_type != VAR_UNKNOWN)
10969 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010970 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010971 if (typeerr)
10972 return;
10973 }
10974 }
10975 else
10976 maxcount = 25;
10977
10978 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10979
10980 for (i = 0; i < ga.ga_len; ++i)
10981 {
10982 str = ((char_u **)ga.ga_data)[i];
10983
10984 li = listitem_alloc();
10985 if (li == NULL)
10986 vim_free(str);
10987 else
10988 {
10989 li->li_tv.v_type = VAR_STRING;
10990 li->li_tv.v_lock = 0;
10991 li->li_tv.vval.v_string = str;
10992 list_append(rettv->vval.v_list, li);
10993 }
10994 }
10995 ga_clear(&ga);
10996 }
10997#endif
10998}
10999
11000 static void
11001f_split(typval_T *argvars, typval_T *rettv)
11002{
11003 char_u *str;
11004 char_u *end;
11005 char_u *pat = NULL;
11006 regmatch_T regmatch;
11007 char_u patbuf[NUMBUFLEN];
11008 char_u *save_cpo;
11009 int match;
11010 colnr_T col = 0;
11011 int keepempty = FALSE;
11012 int typeerr = FALSE;
11013
11014 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
11015 save_cpo = p_cpo;
11016 p_cpo = (char_u *)"";
11017
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011018 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011019 if (argvars[1].v_type != VAR_UNKNOWN)
11020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011021 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011022 if (pat == NULL)
11023 typeerr = TRUE;
11024 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011025 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011026 }
11027 if (pat == NULL || *pat == NUL)
11028 pat = (char_u *)"[\\x01- ]\\+";
11029
11030 if (rettv_list_alloc(rettv) == FAIL)
11031 return;
11032 if (typeerr)
11033 return;
11034
11035 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11036 if (regmatch.regprog != NULL)
11037 {
11038 regmatch.rm_ic = FALSE;
11039 while (*str != NUL || keepempty)
11040 {
11041 if (*str == NUL)
11042 match = FALSE; /* empty item at the end */
11043 else
11044 match = vim_regexec_nl(&regmatch, str, col);
11045 if (match)
11046 end = regmatch.startp[0];
11047 else
11048 end = str + STRLEN(str);
11049 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11050 && *str != NUL && match && end < regmatch.endp[0]))
11051 {
11052 if (list_append_string(rettv->vval.v_list, str,
11053 (int)(end - str)) == FAIL)
11054 break;
11055 }
11056 if (!match)
11057 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010011058 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011059 if (regmatch.endp[0] > str)
11060 col = 0;
11061 else
Bram Moolenaar13505972019-01-24 15:04:48 +010011062 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011064 str = regmatch.endp[0];
11065 }
11066
11067 vim_regfree(regmatch.regprog);
11068 }
11069
11070 p_cpo = save_cpo;
11071}
11072
11073#ifdef FEAT_FLOAT
11074/*
11075 * "sqrt()" function
11076 */
11077 static void
11078f_sqrt(typval_T *argvars, typval_T *rettv)
11079{
11080 float_T f = 0.0;
11081
11082 rettv->v_type = VAR_FLOAT;
11083 if (get_float_arg(argvars, &f) == OK)
11084 rettv->vval.v_float = sqrt(f);
11085 else
11086 rettv->vval.v_float = 0.0;
11087}
11088
11089/*
11090 * "str2float()" function
11091 */
11092 static void
11093f_str2float(typval_T *argvars, typval_T *rettv)
11094{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011095 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011096 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011097
Bram Moolenaar08243d22017-01-10 16:12:29 +010011098 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011099 p = skipwhite(p + 1);
11100 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011101 if (isneg)
11102 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011103 rettv->v_type = VAR_FLOAT;
11104}
11105#endif
11106
11107/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020011108 * "str2list()" function
11109 */
11110 static void
11111f_str2list(typval_T *argvars, typval_T *rettv)
11112{
11113 char_u *p;
11114 int utf8 = FALSE;
11115
11116 if (rettv_list_alloc(rettv) == FAIL)
11117 return;
11118
11119 if (argvars[1].v_type != VAR_UNKNOWN)
11120 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
11121
11122 p = tv_get_string(&argvars[0]);
11123
11124 if (has_mbyte || utf8)
11125 {
11126 int (*ptr2len)(char_u *);
11127 int (*ptr2char)(char_u *);
11128
11129 if (utf8 || enc_utf8)
11130 {
11131 ptr2len = utf_ptr2len;
11132 ptr2char = utf_ptr2char;
11133 }
11134 else
11135 {
11136 ptr2len = mb_ptr2len;
11137 ptr2char = mb_ptr2char;
11138 }
11139
11140 for ( ; *p != NUL; p += (*ptr2len)(p))
11141 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
11142 }
11143 else
11144 for ( ; *p != NUL; ++p)
11145 list_append_number(rettv->vval.v_list, *p);
11146}
11147
11148/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011149 * "str2nr()" function
11150 */
11151 static void
11152f_str2nr(typval_T *argvars, typval_T *rettv)
11153{
11154 int base = 10;
11155 char_u *p;
11156 varnumber_T n;
11157 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011158 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011159
11160 if (argvars[1].v_type != VAR_UNKNOWN)
11161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011162 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011163 if (base != 2 && base != 8 && base != 10 && base != 16)
11164 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011165 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011166 return;
11167 }
11168 }
11169
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011170 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011171 isneg = (*p == '-');
11172 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011173 p = skipwhite(p + 1);
11174 switch (base)
11175 {
11176 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11177 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11178 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11179 default: what = 0;
11180 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020011181 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
11182 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010011183 if (isneg)
11184 rettv->vval.v_number = -n;
11185 else
11186 rettv->vval.v_number = n;
11187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011188}
11189
11190#ifdef HAVE_STRFTIME
11191/*
11192 * "strftime({format}[, {time}])" function
11193 */
11194 static void
11195f_strftime(typval_T *argvars, typval_T *rettv)
11196{
11197 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020011198 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011199 struct tm *curtime;
11200 time_t seconds;
11201 char_u *p;
11202
11203 rettv->v_type = VAR_STRING;
11204
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011205 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011206 if (argvars[1].v_type == VAR_UNKNOWN)
11207 seconds = time(NULL);
11208 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011209 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020011210 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011211 /* MSVC returns NULL for an invalid value of seconds. */
11212 if (curtime == NULL)
11213 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11214 else
11215 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011216 vimconv_T conv;
11217 char_u *enc;
11218
11219 conv.vc_type = CONV_NONE;
11220 enc = enc_locale();
11221 convert_setup(&conv, p_enc, enc);
11222 if (conv.vc_type != CONV_NONE)
11223 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011224 if (p != NULL)
11225 (void)strftime((char *)result_buf, sizeof(result_buf),
11226 (char *)p, curtime);
11227 else
11228 result_buf[0] = NUL;
11229
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011230 if (conv.vc_type != CONV_NONE)
11231 vim_free(p);
11232 convert_setup(&conv, enc, p_enc);
11233 if (conv.vc_type != CONV_NONE)
11234 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11235 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236 rettv->vval.v_string = vim_strsave(result_buf);
11237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011238 /* Release conversion descriptors */
11239 convert_setup(&conv, NULL, NULL);
11240 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011241 }
11242}
11243#endif
11244
11245/*
11246 * "strgetchar()" function
11247 */
11248 static void
11249f_strgetchar(typval_T *argvars, typval_T *rettv)
11250{
11251 char_u *str;
11252 int len;
11253 int error = FALSE;
11254 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011255 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011256
11257 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011258 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011259 if (str == NULL)
11260 return;
11261 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011262 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011263 if (error)
11264 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011265
Bram Moolenaar13505972019-01-24 15:04:48 +010011266 while (charidx >= 0 && byteidx < len)
11267 {
11268 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011269 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011270 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11271 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011272 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011273 --charidx;
11274 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011275 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011276}
11277
11278/*
11279 * "stridx()" function
11280 */
11281 static void
11282f_stridx(typval_T *argvars, typval_T *rettv)
11283{
11284 char_u buf[NUMBUFLEN];
11285 char_u *needle;
11286 char_u *haystack;
11287 char_u *save_haystack;
11288 char_u *pos;
11289 int start_idx;
11290
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011291 needle = tv_get_string_chk(&argvars[1]);
11292 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011293 rettv->vval.v_number = -1;
11294 if (needle == NULL || haystack == NULL)
11295 return; /* type error; errmsg already given */
11296
11297 if (argvars[2].v_type != VAR_UNKNOWN)
11298 {
11299 int error = FALSE;
11300
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011301 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011302 if (error || start_idx >= (int)STRLEN(haystack))
11303 return;
11304 if (start_idx >= 0)
11305 haystack += start_idx;
11306 }
11307
11308 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11309 if (pos != NULL)
11310 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11311}
11312
11313/*
11314 * "string()" function
11315 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011316 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011317f_string(typval_T *argvars, typval_T *rettv)
11318{
11319 char_u *tofree;
11320 char_u numbuf[NUMBUFLEN];
11321
11322 rettv->v_type = VAR_STRING;
11323 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11324 get_copyID());
11325 /* Make a copy if we have a value but it's not in allocated memory. */
11326 if (rettv->vval.v_string != NULL && tofree == NULL)
11327 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11328}
11329
11330/*
11331 * "strlen()" function
11332 */
11333 static void
11334f_strlen(typval_T *argvars, typval_T *rettv)
11335{
11336 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011337 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011338}
11339
11340/*
11341 * "strchars()" function
11342 */
11343 static void
11344f_strchars(typval_T *argvars, typval_T *rettv)
11345{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011346 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011347 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348 varnumber_T len = 0;
11349 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011350
11351 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011352 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011353 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011354 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011355 else
11356 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011357 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11358 while (*s != NUL)
11359 {
11360 func_mb_ptr2char_adv(&s);
11361 ++len;
11362 }
11363 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011364 }
11365}
11366
11367/*
11368 * "strdisplaywidth()" function
11369 */
11370 static void
11371f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11372{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011373 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011374 int col = 0;
11375
11376 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011377 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011378
11379 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11380}
11381
11382/*
11383 * "strwidth()" function
11384 */
11385 static void
11386f_strwidth(typval_T *argvars, typval_T *rettv)
11387{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011388 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011389
Bram Moolenaar13505972019-01-24 15:04:48 +010011390 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011391}
11392
11393/*
11394 * "strcharpart()" function
11395 */
11396 static void
11397f_strcharpart(typval_T *argvars, typval_T *rettv)
11398{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011399 char_u *p;
11400 int nchar;
11401 int nbyte = 0;
11402 int charlen;
11403 int len = 0;
11404 int slen;
11405 int error = FALSE;
11406
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011407 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011408 slen = (int)STRLEN(p);
11409
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011410 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011411 if (!error)
11412 {
11413 if (nchar > 0)
11414 while (nchar > 0 && nbyte < slen)
11415 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011416 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011417 --nchar;
11418 }
11419 else
11420 nbyte = nchar;
11421 if (argvars[2].v_type != VAR_UNKNOWN)
11422 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011423 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011424 while (charlen > 0 && nbyte + len < slen)
11425 {
11426 int off = nbyte + len;
11427
11428 if (off < 0)
11429 len += 1;
11430 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011431 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011432 --charlen;
11433 }
11434 }
11435 else
11436 len = slen - nbyte; /* default: all bytes that are available. */
11437 }
11438
11439 /*
11440 * Only return the overlap between the specified part and the actual
11441 * string.
11442 */
11443 if (nbyte < 0)
11444 {
11445 len += nbyte;
11446 nbyte = 0;
11447 }
11448 else if (nbyte > slen)
11449 nbyte = slen;
11450 if (len < 0)
11451 len = 0;
11452 else if (nbyte + len > slen)
11453 len = slen - nbyte;
11454
11455 rettv->v_type = VAR_STRING;
11456 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011457}
11458
11459/*
11460 * "strpart()" function
11461 */
11462 static void
11463f_strpart(typval_T *argvars, typval_T *rettv)
11464{
11465 char_u *p;
11466 int n;
11467 int len;
11468 int slen;
11469 int error = FALSE;
11470
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011471 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011472 slen = (int)STRLEN(p);
11473
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011474 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011475 if (error)
11476 len = 0;
11477 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011478 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011479 else
11480 len = slen - n; /* default len: all bytes that are available. */
11481
11482 /*
11483 * Only return the overlap between the specified part and the actual
11484 * string.
11485 */
11486 if (n < 0)
11487 {
11488 len += n;
11489 n = 0;
11490 }
11491 else if (n > slen)
11492 n = slen;
11493 if (len < 0)
11494 len = 0;
11495 else if (n + len > slen)
11496 len = slen - n;
11497
11498 rettv->v_type = VAR_STRING;
11499 rettv->vval.v_string = vim_strnsave(p + n, len);
11500}
11501
11502/*
11503 * "strridx()" function
11504 */
11505 static void
11506f_strridx(typval_T *argvars, typval_T *rettv)
11507{
11508 char_u buf[NUMBUFLEN];
11509 char_u *needle;
11510 char_u *haystack;
11511 char_u *rest;
11512 char_u *lastmatch = NULL;
11513 int haystack_len, end_idx;
11514
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011515 needle = tv_get_string_chk(&argvars[1]);
11516 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011517
11518 rettv->vval.v_number = -1;
11519 if (needle == NULL || haystack == NULL)
11520 return; /* type error; errmsg already given */
11521
11522 haystack_len = (int)STRLEN(haystack);
11523 if (argvars[2].v_type != VAR_UNKNOWN)
11524 {
11525 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011526 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011527 if (end_idx < 0)
11528 return; /* can never find a match */
11529 }
11530 else
11531 end_idx = haystack_len;
11532
11533 if (*needle == NUL)
11534 {
11535 /* Empty string matches past the end. */
11536 lastmatch = haystack + end_idx;
11537 }
11538 else
11539 {
11540 for (rest = haystack; *rest != '\0'; ++rest)
11541 {
11542 rest = (char_u *)strstr((char *)rest, (char *)needle);
11543 if (rest == NULL || rest > haystack + end_idx)
11544 break;
11545 lastmatch = rest;
11546 }
11547 }
11548
11549 if (lastmatch == NULL)
11550 rettv->vval.v_number = -1;
11551 else
11552 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11553}
11554
11555/*
11556 * "strtrans()" function
11557 */
11558 static void
11559f_strtrans(typval_T *argvars, typval_T *rettv)
11560{
11561 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011562 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011563}
11564
11565/*
11566 * "submatch()" function
11567 */
11568 static void
11569f_submatch(typval_T *argvars, typval_T *rettv)
11570{
11571 int error = FALSE;
11572 int no;
11573 int retList = 0;
11574
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011575 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011576 if (error)
11577 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011578 if (no < 0 || no >= NSUBEXP)
11579 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011580 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011581 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011582 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011583 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011584 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011585 if (error)
11586 return;
11587
11588 if (retList == 0)
11589 {
11590 rettv->v_type = VAR_STRING;
11591 rettv->vval.v_string = reg_submatch(no);
11592 }
11593 else
11594 {
11595 rettv->v_type = VAR_LIST;
11596 rettv->vval.v_list = reg_submatch_list(no);
11597 }
11598}
11599
11600/*
11601 * "substitute()" function
11602 */
11603 static void
11604f_substitute(typval_T *argvars, typval_T *rettv)
11605{
11606 char_u patbuf[NUMBUFLEN];
11607 char_u subbuf[NUMBUFLEN];
11608 char_u flagsbuf[NUMBUFLEN];
11609
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011610 char_u *str = tv_get_string_chk(&argvars[0]);
11611 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011612 char_u *sub = NULL;
11613 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011614 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011615
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011616 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11617 expr = &argvars[2];
11618 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011619 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011620
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011621 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011622 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11623 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011624 rettv->vval.v_string = NULL;
11625 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011626 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011627}
11628
11629/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011630 * "swapinfo(swap_filename)" function
11631 */
11632 static void
11633f_swapinfo(typval_T *argvars, typval_T *rettv)
11634{
11635 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011636 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011637}
11638
11639/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011640 * "swapname(expr)" function
11641 */
11642 static void
11643f_swapname(typval_T *argvars, typval_T *rettv)
11644{
11645 buf_T *buf;
11646
11647 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011648 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011649 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11650 || buf->b_ml.ml_mfp->mf_fname == NULL)
11651 rettv->vval.v_string = NULL;
11652 else
11653 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11654}
11655
11656/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011657 * "synID(lnum, col, trans)" function
11658 */
11659 static void
11660f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11661{
11662 int id = 0;
11663#ifdef FEAT_SYN_HL
11664 linenr_T lnum;
11665 colnr_T col;
11666 int trans;
11667 int transerr = FALSE;
11668
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011669 lnum = tv_get_lnum(argvars); /* -1 on type error */
11670 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11671 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011672
11673 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11674 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11675 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11676#endif
11677
11678 rettv->vval.v_number = id;
11679}
11680
11681/*
11682 * "synIDattr(id, what [, mode])" function
11683 */
11684 static void
11685f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11686{
11687 char_u *p = NULL;
11688#ifdef FEAT_SYN_HL
11689 int id;
11690 char_u *what;
11691 char_u *mode;
11692 char_u modebuf[NUMBUFLEN];
11693 int modec;
11694
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011695 id = (int)tv_get_number(&argvars[0]);
11696 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011697 if (argvars[2].v_type != VAR_UNKNOWN)
11698 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011699 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011700 modec = TOLOWER_ASC(mode[0]);
11701 if (modec != 't' && modec != 'c' && modec != 'g')
11702 modec = 0; /* replace invalid with current */
11703 }
11704 else
11705 {
11706#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11707 if (USE_24BIT)
11708 modec = 'g';
11709 else
11710#endif
11711 if (t_colors > 1)
11712 modec = 'c';
11713 else
11714 modec = 't';
11715 }
11716
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011717 switch (TOLOWER_ASC(what[0]))
11718 {
11719 case 'b':
11720 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11721 p = highlight_color(id, what, modec);
11722 else /* bold */
11723 p = highlight_has_attr(id, HL_BOLD, modec);
11724 break;
11725
11726 case 'f': /* fg[#] or font */
11727 p = highlight_color(id, what, modec);
11728 break;
11729
11730 case 'i':
11731 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11732 p = highlight_has_attr(id, HL_INVERSE, modec);
11733 else /* italic */
11734 p = highlight_has_attr(id, HL_ITALIC, modec);
11735 break;
11736
11737 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011738 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011739 break;
11740
11741 case 'r': /* reverse */
11742 p = highlight_has_attr(id, HL_INVERSE, modec);
11743 break;
11744
11745 case 's':
11746 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11747 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011748 /* strikeout */
11749 else if (TOLOWER_ASC(what[1]) == 't' &&
11750 TOLOWER_ASC(what[2]) == 'r')
11751 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011752 else /* standout */
11753 p = highlight_has_attr(id, HL_STANDOUT, modec);
11754 break;
11755
11756 case 'u':
11757 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11758 /* underline */
11759 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11760 else
11761 /* undercurl */
11762 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11763 break;
11764 }
11765
11766 if (p != NULL)
11767 p = vim_strsave(p);
11768#endif
11769 rettv->v_type = VAR_STRING;
11770 rettv->vval.v_string = p;
11771}
11772
11773/*
11774 * "synIDtrans(id)" function
11775 */
11776 static void
11777f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11778{
11779 int id;
11780
11781#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011782 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011783
11784 if (id > 0)
11785 id = syn_get_final_id(id);
11786 else
11787#endif
11788 id = 0;
11789
11790 rettv->vval.v_number = id;
11791}
11792
11793/*
11794 * "synconcealed(lnum, col)" function
11795 */
11796 static void
11797f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11798{
11799#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11800 linenr_T lnum;
11801 colnr_T col;
11802 int syntax_flags = 0;
11803 int cchar;
11804 int matchid = 0;
11805 char_u str[NUMBUFLEN];
11806#endif
11807
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011808 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011809
11810#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011811 lnum = tv_get_lnum(argvars); /* -1 on type error */
11812 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011813
11814 vim_memset(str, NUL, sizeof(str));
11815
11816 if (rettv_list_alloc(rettv) != FAIL)
11817 {
11818 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11819 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11820 && curwin->w_p_cole > 0)
11821 {
11822 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11823 syntax_flags = get_syntax_info(&matchid);
11824
11825 /* get the conceal character */
11826 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11827 {
11828 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011829 if (cchar == NUL && curwin->w_p_cole == 1)
11830 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011831 if (cchar != NUL)
11832 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011833 if (has_mbyte)
11834 (*mb_char2bytes)(cchar, str);
11835 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011836 str[0] = cchar;
11837 }
11838 }
11839 }
11840
11841 list_append_number(rettv->vval.v_list,
11842 (syntax_flags & HL_CONCEAL) != 0);
11843 /* -1 to auto-determine strlen */
11844 list_append_string(rettv->vval.v_list, str, -1);
11845 list_append_number(rettv->vval.v_list, matchid);
11846 }
11847#endif
11848}
11849
11850/*
11851 * "synstack(lnum, col)" function
11852 */
11853 static void
11854f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11855{
11856#ifdef FEAT_SYN_HL
11857 linenr_T lnum;
11858 colnr_T col;
11859 int i;
11860 int id;
11861#endif
11862
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011863 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011864
11865#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011866 lnum = tv_get_lnum(argvars); /* -1 on type error */
11867 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011868
11869 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11870 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11871 && rettv_list_alloc(rettv) != FAIL)
11872 {
11873 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11874 for (i = 0; ; ++i)
11875 {
11876 id = syn_get_stack_item(i);
11877 if (id < 0)
11878 break;
11879 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11880 break;
11881 }
11882 }
11883#endif
11884}
11885
11886 static void
11887get_cmd_output_as_rettv(
11888 typval_T *argvars,
11889 typval_T *rettv,
11890 int retlist)
11891{
11892 char_u *res = NULL;
11893 char_u *p;
11894 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011895 int err = FALSE;
11896 FILE *fd;
11897 list_T *list = NULL;
11898 int flags = SHELL_SILENT;
11899
11900 rettv->v_type = VAR_STRING;
11901 rettv->vval.v_string = NULL;
11902 if (check_restricted() || check_secure())
11903 goto errret;
11904
11905 if (argvars[1].v_type != VAR_UNKNOWN)
11906 {
11907 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011908 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011909 * command.
11910 */
11911 if ((infile = vim_tempname('i', TRUE)) == NULL)
11912 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011913 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011914 goto errret;
11915 }
11916
11917 fd = mch_fopen((char *)infile, WRITEBIN);
11918 if (fd == NULL)
11919 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011920 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011921 goto errret;
11922 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011923 if (argvars[1].v_type == VAR_NUMBER)
11924 {
11925 linenr_T lnum;
11926 buf_T *buf;
11927
11928 buf = buflist_findnr(argvars[1].vval.v_number);
11929 if (buf == NULL)
11930 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011931 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011932 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011933 goto errret;
11934 }
11935
11936 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11937 {
11938 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11939 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11940 {
11941 err = TRUE;
11942 break;
11943 }
11944 if (putc(NL, fd) == EOF)
11945 {
11946 err = TRUE;
11947 break;
11948 }
11949 }
11950 }
11951 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011952 {
11953 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11954 err = TRUE;
11955 }
11956 else
11957 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011958 size_t len;
11959 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011960
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011961 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011962 if (p == NULL)
11963 {
11964 fclose(fd);
11965 goto errret; /* type error; errmsg already given */
11966 }
11967 len = STRLEN(p);
11968 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11969 err = TRUE;
11970 }
11971 if (fclose(fd) != 0)
11972 err = TRUE;
11973 if (err)
11974 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011975 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011976 goto errret;
11977 }
11978 }
11979
11980 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11981 * echoes typeahead, that messes up the display. */
11982 if (!msg_silent)
11983 flags += SHELL_COOKED;
11984
11985 if (retlist)
11986 {
11987 int len;
11988 listitem_T *li;
11989 char_u *s = NULL;
11990 char_u *start;
11991 char_u *end;
11992 int i;
11993
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011994 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011995 if (res == NULL)
11996 goto errret;
11997
11998 list = list_alloc();
11999 if (list == NULL)
12000 goto errret;
12001
12002 for (i = 0; i < len; ++i)
12003 {
12004 start = res + i;
12005 while (i < len && res[i] != NL)
12006 ++i;
12007 end = res + i;
12008
Bram Moolenaar964b3742019-05-24 18:54:09 +020012009 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012010 if (s == NULL)
12011 goto errret;
12012
12013 for (p = s; start < end; ++p, ++start)
12014 *p = *start == NUL ? NL : *start;
12015 *p = NUL;
12016
12017 li = listitem_alloc();
12018 if (li == NULL)
12019 {
12020 vim_free(s);
12021 goto errret;
12022 }
12023 li->li_tv.v_type = VAR_STRING;
12024 li->li_tv.v_lock = 0;
12025 li->li_tv.vval.v_string = s;
12026 list_append(list, li);
12027 }
12028
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012029 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012030 list = NULL;
12031 }
12032 else
12033 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012034 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010012035#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012036 /* translate <CR><NL> into <NL> */
12037 if (res != NULL)
12038 {
12039 char_u *s, *d;
12040
12041 d = res;
12042 for (s = res; *s; ++s)
12043 {
12044 if (s[0] == CAR && s[1] == NL)
12045 ++s;
12046 *d++ = *s;
12047 }
12048 *d = NUL;
12049 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012050#endif
12051 rettv->vval.v_string = res;
12052 res = NULL;
12053 }
12054
12055errret:
12056 if (infile != NULL)
12057 {
12058 mch_remove(infile);
12059 vim_free(infile);
12060 }
12061 if (res != NULL)
12062 vim_free(res);
12063 if (list != NULL)
12064 list_free(list);
12065}
12066
12067/*
12068 * "system()" function
12069 */
12070 static void
12071f_system(typval_T *argvars, typval_T *rettv)
12072{
12073 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12074}
12075
12076/*
12077 * "systemlist()" function
12078 */
12079 static void
12080f_systemlist(typval_T *argvars, typval_T *rettv)
12081{
12082 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12083}
12084
12085/*
12086 * "tabpagebuflist()" function
12087 */
12088 static void
12089f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12090{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012091 tabpage_T *tp;
12092 win_T *wp = NULL;
12093
12094 if (argvars[0].v_type == VAR_UNKNOWN)
12095 wp = firstwin;
12096 else
12097 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012098 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012099 if (tp != NULL)
12100 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12101 }
12102 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12103 {
12104 for (; wp != NULL; wp = wp->w_next)
12105 if (list_append_number(rettv->vval.v_list,
12106 wp->w_buffer->b_fnum) == FAIL)
12107 break;
12108 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012109}
12110
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012111/*
12112 * "tabpagenr()" function
12113 */
12114 static void
12115f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12116{
12117 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012118 char_u *arg;
12119
12120 if (argvars[0].v_type != VAR_UNKNOWN)
12121 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012122 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012123 nr = 0;
12124 if (arg != NULL)
12125 {
12126 if (STRCMP(arg, "$") == 0)
12127 nr = tabpage_index(NULL) - 1;
12128 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012129 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012130 }
12131 }
12132 else
12133 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012134 rettv->vval.v_number = nr;
12135}
12136
12137
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012138/*
12139 * Common code for tabpagewinnr() and winnr().
12140 */
12141 static int
12142get_winnr(tabpage_T *tp, typval_T *argvar)
12143{
12144 win_T *twin;
12145 int nr = 1;
12146 win_T *wp;
12147 char_u *arg;
12148
12149 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12150 if (argvar->v_type != VAR_UNKNOWN)
12151 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012152 int invalid_arg = FALSE;
12153
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012154 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012155 if (arg == NULL)
12156 nr = 0; /* type error; errmsg already given */
12157 else if (STRCMP(arg, "$") == 0)
12158 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12159 else if (STRCMP(arg, "#") == 0)
12160 {
12161 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12162 if (twin == NULL)
12163 nr = 0;
12164 }
12165 else
12166 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012167 long count;
12168 char_u *endp;
12169
12170 // Extract the window count (if specified). e.g. winnr('3j')
12171 count = strtol((char *)arg, (char **)&endp, 10);
12172 if (count <= 0)
12173 count = 1; // if count is not specified, default to 1
12174 if (endp != NULL && *endp != '\0')
12175 {
12176 if (STRCMP(endp, "j") == 0)
12177 twin = win_vert_neighbor(tp, twin, FALSE, count);
12178 else if (STRCMP(endp, "k") == 0)
12179 twin = win_vert_neighbor(tp, twin, TRUE, count);
12180 else if (STRCMP(endp, "h") == 0)
12181 twin = win_horz_neighbor(tp, twin, TRUE, count);
12182 else if (STRCMP(endp, "l") == 0)
12183 twin = win_horz_neighbor(tp, twin, FALSE, count);
12184 else
12185 invalid_arg = TRUE;
12186 }
12187 else
12188 invalid_arg = TRUE;
12189 }
12190
12191 if (invalid_arg)
12192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012193 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012194 nr = 0;
12195 }
12196 }
12197
12198 if (nr > 0)
12199 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12200 wp != twin; wp = wp->w_next)
12201 {
12202 if (wp == NULL)
12203 {
12204 /* didn't find it in this tabpage */
12205 nr = 0;
12206 break;
12207 }
12208 ++nr;
12209 }
12210 return nr;
12211}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012212
12213/*
12214 * "tabpagewinnr()" function
12215 */
12216 static void
12217f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12218{
12219 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012220 tabpage_T *tp;
12221
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012222 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012223 if (tp == NULL)
12224 nr = 0;
12225 else
12226 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012227 rettv->vval.v_number = nr;
12228}
12229
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012230/*
12231 * "tagfiles()" function
12232 */
12233 static void
12234f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12235{
12236 char_u *fname;
12237 tagname_T tn;
12238 int first;
12239
12240 if (rettv_list_alloc(rettv) == FAIL)
12241 return;
12242 fname = alloc(MAXPATHL);
12243 if (fname == NULL)
12244 return;
12245
12246 for (first = TRUE; ; first = FALSE)
12247 if (get_tagfname(&tn, first, fname) == FAIL
12248 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12249 break;
12250 tagname_free(&tn);
12251 vim_free(fname);
12252}
12253
12254/*
12255 * "taglist()" function
12256 */
12257 static void
12258f_taglist(typval_T *argvars, typval_T *rettv)
12259{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012260 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012261 char_u *tag_pattern;
12262
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012263 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012264
12265 rettv->vval.v_number = FALSE;
12266 if (*tag_pattern == NUL)
12267 return;
12268
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012269 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012270 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012271 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012272 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012273}
12274
12275/*
12276 * "tempname()" function
12277 */
12278 static void
12279f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12280{
12281 static int x = 'A';
12282
12283 rettv->v_type = VAR_STRING;
12284 rettv->vval.v_string = vim_tempname(x, FALSE);
12285
12286 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12287 * names. Skip 'I' and 'O', they are used for shell redirection. */
12288 do
12289 {
12290 if (x == 'Z')
12291 x = '0';
12292 else if (x == '9')
12293 x = 'A';
12294 else
12295 {
12296#ifdef EBCDIC
12297 if (x == 'I')
12298 x = 'J';
12299 else if (x == 'R')
12300 x = 'S';
12301 else
12302#endif
12303 ++x;
12304 }
12305 } while (x == 'I' || x == 'O');
12306}
12307
12308#ifdef FEAT_FLOAT
12309/*
12310 * "tan()" function
12311 */
12312 static void
12313f_tan(typval_T *argvars, typval_T *rettv)
12314{
12315 float_T f = 0.0;
12316
12317 rettv->v_type = VAR_FLOAT;
12318 if (get_float_arg(argvars, &f) == OK)
12319 rettv->vval.v_float = tan(f);
12320 else
12321 rettv->vval.v_float = 0.0;
12322}
12323
12324/*
12325 * "tanh()" function
12326 */
12327 static void
12328f_tanh(typval_T *argvars, typval_T *rettv)
12329{
12330 float_T f = 0.0;
12331
12332 rettv->v_type = VAR_FLOAT;
12333 if (get_float_arg(argvars, &f) == OK)
12334 rettv->vval.v_float = tanh(f);
12335 else
12336 rettv->vval.v_float = 0.0;
12337}
12338#endif
12339
12340/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012341 * Get a callback from "arg". It can be a Funcref or a function name.
12342 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012343 * "cb_name" is not allocated.
12344 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012345 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012346 callback_T
12347get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012348{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012349 callback_T res;
12350
12351 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012352 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12353 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012354 res.cb_partial = arg->vval.v_partial;
12355 ++res.cb_partial->pt_refcount;
12356 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012358 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012359 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012360 res.cb_partial = NULL;
12361 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12362 {
12363 // Note that we don't make a copy of the string.
12364 res.cb_name = arg->vval.v_string;
12365 func_ref(res.cb_name);
12366 }
12367 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12368 {
12369 res.cb_name = (char_u *)"";
12370 }
12371 else
12372 {
12373 emsg(_("E921: Invalid callback argument"));
12374 res.cb_name = NULL;
12375 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012376 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012377 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012378}
12379
12380/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012381 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382 */
12383 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012384put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012385{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012386 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012387 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012388 tv->v_type = VAR_PARTIAL;
12389 tv->vval.v_partial = cb->cb_partial;
12390 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012391 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012392 else
12393 {
12394 tv->v_type = VAR_FUNC;
12395 tv->vval.v_string = vim_strsave(cb->cb_name);
12396 func_ref(cb->cb_name);
12397 }
12398}
12399
12400/*
12401 * Make a copy of "src" into "dest", allocating the function name if needed,
12402 * without incrementing the refcount.
12403 */
12404 void
12405set_callback(callback_T *dest, callback_T *src)
12406{
12407 if (src->cb_partial == NULL)
12408 {
12409 // just a function name, make a copy
12410 dest->cb_name = vim_strsave(src->cb_name);
12411 dest->cb_free_name = TRUE;
12412 }
12413 else
12414 {
12415 // cb_name is a pointer into cb_partial
12416 dest->cb_name = src->cb_name;
12417 dest->cb_free_name = FALSE;
12418 }
12419 dest->cb_partial = src->cb_partial;
12420}
12421
12422/*
12423 * Unref/free "callback" returned by get_callback() or set_callback().
12424 */
12425 void
12426free_callback(callback_T *callback)
12427{
12428 if (callback->cb_partial != NULL)
12429 {
12430 partial_unref(callback->cb_partial);
12431 callback->cb_partial = NULL;
12432 }
12433 else if (callback->cb_name != NULL)
12434 func_unref(callback->cb_name);
12435 if (callback->cb_free_name)
12436 {
12437 vim_free(callback->cb_name);
12438 callback->cb_free_name = FALSE;
12439 }
12440 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012441}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012442
12443#ifdef FEAT_TIMERS
12444/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012445 * "timer_info([timer])" function
12446 */
12447 static void
12448f_timer_info(typval_T *argvars, typval_T *rettv)
12449{
12450 timer_T *timer = NULL;
12451
12452 if (rettv_list_alloc(rettv) != OK)
12453 return;
12454 if (argvars[0].v_type != VAR_UNKNOWN)
12455 {
12456 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012457 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012458 else
12459 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012460 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012461 if (timer != NULL)
12462 add_timer_info(rettv, timer);
12463 }
12464 }
12465 else
12466 add_timer_info_all(rettv);
12467}
12468
12469/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012470 * "timer_pause(timer, paused)" function
12471 */
12472 static void
12473f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12474{
12475 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012476 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012477
12478 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012479 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012480 else
12481 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012482 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012483 if (timer != NULL)
12484 timer->tr_paused = paused;
12485 }
12486}
12487
12488/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012489 * "timer_start(time, callback [, options])" function
12490 */
12491 static void
12492f_timer_start(typval_T *argvars, typval_T *rettv)
12493{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012494 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012495 timer_T *timer;
12496 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012497 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012498 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012499
Bram Moolenaar75537a92016-09-05 22:45:28 +020012500 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012501 if (check_secure())
12502 return;
12503 if (argvars[2].v_type != VAR_UNKNOWN)
12504 {
12505 if (argvars[2].v_type != VAR_DICT
12506 || (dict = argvars[2].vval.v_dict) == NULL)
12507 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012508 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012509 return;
12510 }
12511 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012512 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012513 }
12514
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012515 callback = get_callback(&argvars[1]);
12516 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012517 return;
12518
12519 timer = create_timer(msec, repeat);
12520 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012521 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012522 else
12523 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012524 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012525 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012526 }
12527}
12528
12529/*
12530 * "timer_stop(timer)" function
12531 */
12532 static void
12533f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12534{
12535 timer_T *timer;
12536
12537 if (argvars[0].v_type != VAR_NUMBER)
12538 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012539 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012540 return;
12541 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012542 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012543 if (timer != NULL)
12544 stop_timer(timer);
12545}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012546
12547/*
12548 * "timer_stopall()" function
12549 */
12550 static void
12551f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12552{
12553 stop_all_timers();
12554}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012555#endif
12556
12557/*
12558 * "tolower(string)" function
12559 */
12560 static void
12561f_tolower(typval_T *argvars, typval_T *rettv)
12562{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012563 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012564 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012565}
12566
12567/*
12568 * "toupper(string)" function
12569 */
12570 static void
12571f_toupper(typval_T *argvars, typval_T *rettv)
12572{
12573 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012574 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575}
12576
12577/*
12578 * "tr(string, fromstr, tostr)" function
12579 */
12580 static void
12581f_tr(typval_T *argvars, typval_T *rettv)
12582{
12583 char_u *in_str;
12584 char_u *fromstr;
12585 char_u *tostr;
12586 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012587 int inlen;
12588 int fromlen;
12589 int tolen;
12590 int idx;
12591 char_u *cpstr;
12592 int cplen;
12593 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012594 char_u buf[NUMBUFLEN];
12595 char_u buf2[NUMBUFLEN];
12596 garray_T ga;
12597
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012598 in_str = tv_get_string(&argvars[0]);
12599 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12600 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012601
12602 /* Default return value: empty string. */
12603 rettv->v_type = VAR_STRING;
12604 rettv->vval.v_string = NULL;
12605 if (fromstr == NULL || tostr == NULL)
12606 return; /* type error; errmsg already given */
12607 ga_init2(&ga, (int)sizeof(char), 80);
12608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012609 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012610 /* not multi-byte: fromstr and tostr must be the same length */
12611 if (STRLEN(fromstr) != STRLEN(tostr))
12612 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012613error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012614 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012615 ga_clear(&ga);
12616 return;
12617 }
12618
12619 /* fromstr and tostr have to contain the same number of chars */
12620 while (*in_str != NUL)
12621 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012622 if (has_mbyte)
12623 {
12624 inlen = (*mb_ptr2len)(in_str);
12625 cpstr = in_str;
12626 cplen = inlen;
12627 idx = 0;
12628 for (p = fromstr; *p != NUL; p += fromlen)
12629 {
12630 fromlen = (*mb_ptr2len)(p);
12631 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12632 {
12633 for (p = tostr; *p != NUL; p += tolen)
12634 {
12635 tolen = (*mb_ptr2len)(p);
12636 if (idx-- == 0)
12637 {
12638 cplen = tolen;
12639 cpstr = p;
12640 break;
12641 }
12642 }
12643 if (*p == NUL) /* tostr is shorter than fromstr */
12644 goto error;
12645 break;
12646 }
12647 ++idx;
12648 }
12649
12650 if (first && cpstr == in_str)
12651 {
12652 /* Check that fromstr and tostr have the same number of
12653 * (multi-byte) characters. Done only once when a character
12654 * of in_str doesn't appear in fromstr. */
12655 first = FALSE;
12656 for (p = tostr; *p != NUL; p += tolen)
12657 {
12658 tolen = (*mb_ptr2len)(p);
12659 --idx;
12660 }
12661 if (idx != 0)
12662 goto error;
12663 }
12664
12665 (void)ga_grow(&ga, cplen);
12666 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12667 ga.ga_len += cplen;
12668
12669 in_str += inlen;
12670 }
12671 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672 {
12673 /* When not using multi-byte chars we can do it faster. */
12674 p = vim_strchr(fromstr, *in_str);
12675 if (p != NULL)
12676 ga_append(&ga, tostr[p - fromstr]);
12677 else
12678 ga_append(&ga, *in_str);
12679 ++in_str;
12680 }
12681 }
12682
12683 /* add a terminating NUL */
12684 (void)ga_grow(&ga, 1);
12685 ga_append(&ga, NUL);
12686
12687 rettv->vval.v_string = ga.ga_data;
12688}
12689
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012690/*
12691 * "trim({expr})" function
12692 */
12693 static void
12694f_trim(typval_T *argvars, typval_T *rettv)
12695{
12696 char_u buf1[NUMBUFLEN];
12697 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012698 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012699 char_u *mask = NULL;
12700 char_u *tail;
12701 char_u *prev;
12702 char_u *p;
12703 int c1;
12704
12705 rettv->v_type = VAR_STRING;
12706 if (head == NULL)
12707 {
12708 rettv->vval.v_string = NULL;
12709 return;
12710 }
12711
12712 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012713 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012714
12715 while (*head != NUL)
12716 {
12717 c1 = PTR2CHAR(head);
12718 if (mask == NULL)
12719 {
12720 if (c1 > ' ' && c1 != 0xa0)
12721 break;
12722 }
12723 else
12724 {
12725 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12726 if (c1 == PTR2CHAR(p))
12727 break;
12728 if (*p == NUL)
12729 break;
12730 }
12731 MB_PTR_ADV(head);
12732 }
12733
12734 for (tail = head + STRLEN(head); tail > head; tail = prev)
12735 {
12736 prev = tail;
12737 MB_PTR_BACK(head, prev);
12738 c1 = PTR2CHAR(prev);
12739 if (mask == NULL)
12740 {
12741 if (c1 > ' ' && c1 != 0xa0)
12742 break;
12743 }
12744 else
12745 {
12746 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12747 if (c1 == PTR2CHAR(p))
12748 break;
12749 if (*p == NUL)
12750 break;
12751 }
12752 }
12753 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12754}
12755
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012756#ifdef FEAT_FLOAT
12757/*
12758 * "trunc({float})" function
12759 */
12760 static void
12761f_trunc(typval_T *argvars, typval_T *rettv)
12762{
12763 float_T f = 0.0;
12764
12765 rettv->v_type = VAR_FLOAT;
12766 if (get_float_arg(argvars, &f) == OK)
12767 /* trunc() is not in C90, use floor() or ceil() instead. */
12768 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12769 else
12770 rettv->vval.v_float = 0.0;
12771}
12772#endif
12773
12774/*
12775 * "type(expr)" function
12776 */
12777 static void
12778f_type(typval_T *argvars, typval_T *rettv)
12779{
12780 int n = -1;
12781
12782 switch (argvars[0].v_type)
12783 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012784 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12785 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012786 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012787 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12788 case VAR_LIST: n = VAR_TYPE_LIST; break;
12789 case VAR_DICT: n = VAR_TYPE_DICT; break;
12790 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791 case VAR_SPECIAL:
12792 if (argvars[0].vval.v_number == VVAL_FALSE
12793 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012794 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012795 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012796 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012797 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012798 case VAR_JOB: n = VAR_TYPE_JOB; break;
12799 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012800 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012801 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012802 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012803 n = -1;
12804 break;
12805 }
12806 rettv->vval.v_number = n;
12807}
12808
12809/*
12810 * "undofile(name)" function
12811 */
12812 static void
12813f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12814{
12815 rettv->v_type = VAR_STRING;
12816#ifdef FEAT_PERSISTENT_UNDO
12817 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012818 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012819
12820 if (*fname == NUL)
12821 {
12822 /* If there is no file name there will be no undo file. */
12823 rettv->vval.v_string = NULL;
12824 }
12825 else
12826 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012827 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012828
12829 if (ffname != NULL)
12830 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12831 vim_free(ffname);
12832 }
12833 }
12834#else
12835 rettv->vval.v_string = NULL;
12836#endif
12837}
12838
12839/*
12840 * "undotree()" function
12841 */
12842 static void
12843f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12844{
12845 if (rettv_dict_alloc(rettv) == OK)
12846 {
12847 dict_T *dict = rettv->vval.v_dict;
12848 list_T *list;
12849
Bram Moolenaare0be1672018-07-08 16:50:37 +020012850 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12851 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12852 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12853 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12854 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12855 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012856
12857 list = list_alloc();
12858 if (list != NULL)
12859 {
12860 u_eval_tree(curbuf->b_u_oldhead, list);
12861 dict_add_list(dict, "entries", list);
12862 }
12863 }
12864}
12865
12866/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012867 * "virtcol(string)" function
12868 */
12869 static void
12870f_virtcol(typval_T *argvars, typval_T *rettv)
12871{
12872 colnr_T vcol = 0;
12873 pos_T *fp;
12874 int fnum = curbuf->b_fnum;
12875
12876 fp = var2fpos(&argvars[0], FALSE, &fnum);
12877 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12878 && fnum == curbuf->b_fnum)
12879 {
12880 getvvcol(curwin, fp, NULL, NULL, &vcol);
12881 ++vcol;
12882 }
12883
12884 rettv->vval.v_number = vcol;
12885}
12886
12887/*
12888 * "visualmode()" function
12889 */
12890 static void
12891f_visualmode(typval_T *argvars, typval_T *rettv)
12892{
12893 char_u str[2];
12894
12895 rettv->v_type = VAR_STRING;
12896 str[0] = curbuf->b_visual_mode_eval;
12897 str[1] = NUL;
12898 rettv->vval.v_string = vim_strsave(str);
12899
12900 /* A non-zero number or non-empty string argument: reset mode. */
12901 if (non_zero_arg(&argvars[0]))
12902 curbuf->b_visual_mode_eval = NUL;
12903}
12904
12905/*
12906 * "wildmenumode()" function
12907 */
12908 static void
12909f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12910{
12911#ifdef FEAT_WILDMENU
12912 if (wild_menu_showing)
12913 rettv->vval.v_number = 1;
12914#endif
12915}
12916
12917/*
12918 * "winbufnr(nr)" function
12919 */
12920 static void
12921f_winbufnr(typval_T *argvars, typval_T *rettv)
12922{
12923 win_T *wp;
12924
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012925 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012926 if (wp == NULL)
12927 rettv->vval.v_number = -1;
12928 else
12929 rettv->vval.v_number = wp->w_buffer->b_fnum;
12930}
12931
12932/*
12933 * "wincol()" function
12934 */
12935 static void
12936f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12937{
12938 validate_cursor();
12939 rettv->vval.v_number = curwin->w_wcol + 1;
12940}
12941
12942/*
12943 * "winheight(nr)" function
12944 */
12945 static void
12946f_winheight(typval_T *argvars, typval_T *rettv)
12947{
12948 win_T *wp;
12949
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012950 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012951 if (wp == NULL)
12952 rettv->vval.v_number = -1;
12953 else
12954 rettv->vval.v_number = wp->w_height;
12955}
12956
12957/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012958 * "winlayout()" function
12959 */
12960 static void
12961f_winlayout(typval_T *argvars, typval_T *rettv)
12962{
12963 tabpage_T *tp;
12964
12965 if (rettv_list_alloc(rettv) != OK)
12966 return;
12967
12968 if (argvars[0].v_type == VAR_UNKNOWN)
12969 tp = curtab;
12970 else
12971 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012972 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012973 if (tp == NULL)
12974 return;
12975 }
12976
12977 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12978}
12979
12980/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012981 * "winline()" function
12982 */
12983 static void
12984f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12985{
12986 validate_cursor();
12987 rettv->vval.v_number = curwin->w_wrow + 1;
12988}
12989
12990/*
12991 * "winnr()" function
12992 */
12993 static void
12994f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12995{
12996 int nr = 1;
12997
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012998 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012999 rettv->vval.v_number = nr;
13000}
13001
13002/*
13003 * "winrestcmd()" function
13004 */
13005 static void
13006f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
13007{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013008 win_T *wp;
13009 int winnr = 1;
13010 garray_T ga;
13011 char_u buf[50];
13012
13013 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020013014 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013015 {
13016 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
13017 ga_concat(&ga, buf);
13018 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
13019 ga_concat(&ga, buf);
13020 ++winnr;
13021 }
13022 ga_append(&ga, NUL);
13023
13024 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013025 rettv->v_type = VAR_STRING;
13026}
13027
13028/*
13029 * "winrestview()" function
13030 */
13031 static void
13032f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13033{
13034 dict_T *dict;
13035
13036 if (argvars[0].v_type != VAR_DICT
13037 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013038 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013039 else
13040 {
13041 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013042 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013043 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013044 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013045 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013046 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013047 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13048 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010013049 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013050 curwin->w_set_curswant = FALSE;
13051 }
13052
13053 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013054 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013055#ifdef FEAT_DIFF
13056 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013057 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013058#endif
13059 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013060 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013061 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013062 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013063
13064 check_cursor();
13065 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013066 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013067 changed_window_setting();
13068
13069 if (curwin->w_topline <= 0)
13070 curwin->w_topline = 1;
13071 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13072 curwin->w_topline = curbuf->b_ml.ml_line_count;
13073#ifdef FEAT_DIFF
13074 check_topfill(curwin, TRUE);
13075#endif
13076 }
13077}
13078
13079/*
13080 * "winsaveview()" function
13081 */
13082 static void
13083f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13084{
13085 dict_T *dict;
13086
13087 if (rettv_dict_alloc(rettv) == FAIL)
13088 return;
13089 dict = rettv->vval.v_dict;
13090
Bram Moolenaare0be1672018-07-08 16:50:37 +020013091 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13092 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020013093 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013094 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013095 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013096
Bram Moolenaare0be1672018-07-08 16:50:37 +020013097 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013098#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013099 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013100#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013101 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13102 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013103}
13104
13105/*
13106 * "winwidth(nr)" function
13107 */
13108 static void
13109f_winwidth(typval_T *argvars, typval_T *rettv)
13110{
13111 win_T *wp;
13112
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013113 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013114 if (wp == NULL)
13115 rettv->vval.v_number = -1;
13116 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013117 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013118}
13119
13120/*
13121 * "wordcount()" function
13122 */
13123 static void
13124f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13125{
13126 if (rettv_dict_alloc(rettv) == FAIL)
13127 return;
13128 cursor_pos_info(rettv->vval.v_dict);
13129}
13130
13131/*
13132 * "writefile()" function
13133 */
13134 static void
13135f_writefile(typval_T *argvars, typval_T *rettv)
13136{
13137 int binary = FALSE;
13138 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013139#ifdef HAVE_FSYNC
13140 int do_fsync = p_fs;
13141#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013142 char_u *fname;
13143 FILE *fd;
13144 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013145 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013146 list_T *list = NULL;
13147 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013148
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013149 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010013150 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013151 return;
13152
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013153 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013154 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013155 list = argvars[0].vval.v_list;
13156 if (list == NULL)
13157 return;
13158 for (li = list->lv_first; li != NULL; li = li->li_next)
13159 if (tv_get_string_chk(&li->li_tv) == NULL)
13160 return;
13161 }
13162 else if (argvars[0].v_type == VAR_BLOB)
13163 {
13164 blob = argvars[0].vval.v_blob;
13165 if (blob == NULL)
13166 return;
13167 }
13168 else
13169 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013170 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013171 return;
13172 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013173
13174 if (argvars[2].v_type != VAR_UNKNOWN)
13175 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013176 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013177
13178 if (arg2 == NULL)
13179 return;
13180 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013181 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013182 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013183 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013184#ifdef HAVE_FSYNC
13185 if (vim_strchr(arg2, 's') != NULL)
13186 do_fsync = TRUE;
13187 else if (vim_strchr(arg2, 'S') != NULL)
13188 do_fsync = FALSE;
13189#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013190 }
13191
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013192 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013193 if (fname == NULL)
13194 return;
13195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013196 /* Always open the file in binary mode, library functions have a mind of
13197 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013198 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13199 append ? APPENDBIN : WRITEBIN)) == NULL)
13200 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013201 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013202 ret = -1;
13203 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013204 else if (blob)
13205 {
13206 if (write_blob(fd, blob) == FAIL)
13207 ret = -1;
13208#ifdef HAVE_FSYNC
13209 else if (do_fsync)
13210 // Ignore the error, the user wouldn't know what to do about it.
13211 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010013212 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013213#endif
13214 fclose(fd);
13215 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013216 else
13217 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013218 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013219 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013220#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013221 else if (do_fsync)
13222 /* Ignore the error, the user wouldn't know what to do about it.
13223 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010013224 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013225#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013226 fclose(fd);
13227 }
13228
13229 rettv->vval.v_number = ret;
13230}
13231
13232/*
13233 * "xor(expr, expr)" function
13234 */
13235 static void
13236f_xor(typval_T *argvars, typval_T *rettv)
13237{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013238 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13239 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013240}
13241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013242#endif /* FEAT_EVAL */