blob: 449bc67b412b9b15b8a90f99a026ebb94d3147e1 [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);
234#ifdef vim_mkdir
235static void f_mkdir(typval_T *argvars, typval_T *rettv);
236#endif
237static void f_mode(typval_T *argvars, typval_T *rettv);
238#ifdef FEAT_MZSCHEME
239static void f_mzeval(typval_T *argvars, typval_T *rettv);
240#endif
241static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
242static void f_nr2char(typval_T *argvars, typval_T *rettv);
243static void f_or(typval_T *argvars, typval_T *rettv);
244static void f_pathshorten(typval_T *argvars, typval_T *rettv);
245#ifdef FEAT_PERL
246static void f_perleval(typval_T *argvars, typval_T *rettv);
247#endif
248#ifdef FEAT_FLOAT
249static void f_pow(typval_T *argvars, typval_T *rettv);
250#endif
251static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
252static void f_printf(typval_T *argvars, typval_T *rettv);
253static void f_pumvisible(typval_T *argvars, typval_T *rettv);
254#ifdef FEAT_PYTHON3
255static void f_py3eval(typval_T *argvars, typval_T *rettv);
256#endif
257#ifdef FEAT_PYTHON
258static void f_pyeval(typval_T *argvars, typval_T *rettv);
259#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100260#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
261static void f_pyxeval(typval_T *argvars, typval_T *rettv);
262#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200263static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200264static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200265static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200266static void f_reg_executing(typval_T *argvars, typval_T *rettv);
267static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_reltime(typval_T *argvars, typval_T *rettv);
269#ifdef FEAT_FLOAT
270static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
271#endif
272static void f_reltimestr(typval_T *argvars, typval_T *rettv);
273static void f_remote_expr(typval_T *argvars, typval_T *rettv);
274static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
275static void f_remote_peek(typval_T *argvars, typval_T *rettv);
276static void f_remote_read(typval_T *argvars, typval_T *rettv);
277static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100278static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200279static void f_remove(typval_T *argvars, typval_T *rettv);
280static void f_rename(typval_T *argvars, typval_T *rettv);
281static void f_repeat(typval_T *argvars, typval_T *rettv);
282static void f_resolve(typval_T *argvars, typval_T *rettv);
283static void f_reverse(typval_T *argvars, typval_T *rettv);
284#ifdef FEAT_FLOAT
285static void f_round(typval_T *argvars, typval_T *rettv);
286#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100287#ifdef FEAT_RUBY
288static void f_rubyeval(typval_T *argvars, typval_T *rettv);
289#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290static void f_screenattr(typval_T *argvars, typval_T *rettv);
291static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100292static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200293static void f_screencol(typval_T *argvars, typval_T *rettv);
294static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100295static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296static void f_search(typval_T *argvars, typval_T *rettv);
297static void f_searchdecl(typval_T *argvars, typval_T *rettv);
298static void f_searchpair(typval_T *argvars, typval_T *rettv);
299static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
300static void f_searchpos(typval_T *argvars, typval_T *rettv);
301static void f_server2client(typval_T *argvars, typval_T *rettv);
302static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200303static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200304static void f_setbufvar(typval_T *argvars, typval_T *rettv);
305static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
306static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200307static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200308static void f_setfperm(typval_T *argvars, typval_T *rettv);
309static void f_setline(typval_T *argvars, typval_T *rettv);
310static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311static void f_setpos(typval_T *argvars, typval_T *rettv);
312static void f_setqflist(typval_T *argvars, typval_T *rettv);
313static void f_setreg(typval_T *argvars, typval_T *rettv);
314static void f_settabvar(typval_T *argvars, typval_T *rettv);
315static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100316static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317static void f_setwinvar(typval_T *argvars, typval_T *rettv);
318#ifdef FEAT_CRYPT
319static void f_sha256(typval_T *argvars, typval_T *rettv);
320#endif /* FEAT_CRYPT */
321static void f_shellescape(typval_T *argvars, typval_T *rettv);
322static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
323static void f_simplify(typval_T *argvars, typval_T *rettv);
324#ifdef FEAT_FLOAT
325static void f_sin(typval_T *argvars, typval_T *rettv);
326static void f_sinh(typval_T *argvars, typval_T *rettv);
327#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200328static void f_soundfold(typval_T *argvars, typval_T *rettv);
329static void f_spellbadword(typval_T *argvars, typval_T *rettv);
330static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
331static void f_split(typval_T *argvars, typval_T *rettv);
332#ifdef FEAT_FLOAT
333static void f_sqrt(typval_T *argvars, typval_T *rettv);
334static void f_str2float(typval_T *argvars, typval_T *rettv);
335#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200336static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337static void f_str2nr(typval_T *argvars, typval_T *rettv);
338static void f_strchars(typval_T *argvars, typval_T *rettv);
339#ifdef HAVE_STRFTIME
340static void f_strftime(typval_T *argvars, typval_T *rettv);
341#endif
342static void f_strgetchar(typval_T *argvars, typval_T *rettv);
343static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200344static void f_strlen(typval_T *argvars, typval_T *rettv);
345static void f_strcharpart(typval_T *argvars, typval_T *rettv);
346static void f_strpart(typval_T *argvars, typval_T *rettv);
347static void f_strridx(typval_T *argvars, typval_T *rettv);
348static void f_strtrans(typval_T *argvars, typval_T *rettv);
349static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
350static void f_strwidth(typval_T *argvars, typval_T *rettv);
351static void f_submatch(typval_T *argvars, typval_T *rettv);
352static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200353static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200354static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355static void f_synID(typval_T *argvars, typval_T *rettv);
356static void f_synIDattr(typval_T *argvars, typval_T *rettv);
357static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
358static void f_synstack(typval_T *argvars, typval_T *rettv);
359static void f_synconcealed(typval_T *argvars, typval_T *rettv);
360static void f_system(typval_T *argvars, typval_T *rettv);
361static void f_systemlist(typval_T *argvars, typval_T *rettv);
362static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
363static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
364static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
365static void f_taglist(typval_T *argvars, typval_T *rettv);
366static void f_tagfiles(typval_T *argvars, typval_T *rettv);
367static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200368#ifdef FEAT_FLOAT
369static void f_tan(typval_T *argvars, typval_T *rettv);
370static void f_tanh(typval_T *argvars, typval_T *rettv);
371#endif
372#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200373static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200374static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200375static void f_timer_start(typval_T *argvars, typval_T *rettv);
376static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200377static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378#endif
379static void f_tolower(typval_T *argvars, typval_T *rettv);
380static void f_toupper(typval_T *argvars, typval_T *rettv);
381static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100382static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200383#ifdef FEAT_FLOAT
384static void f_trunc(typval_T *argvars, typval_T *rettv);
385#endif
386static void f_type(typval_T *argvars, typval_T *rettv);
387static void f_undofile(typval_T *argvars, typval_T *rettv);
388static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200389static void f_virtcol(typval_T *argvars, typval_T *rettv);
390static void f_visualmode(typval_T *argvars, typval_T *rettv);
391static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200392static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200393static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
394static void f_win_getid(typval_T *argvars, typval_T *rettv);
395static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
396static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
397static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100398static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200399static void f_winbufnr(typval_T *argvars, typval_T *rettv);
400static void f_wincol(typval_T *argvars, typval_T *rettv);
401static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200402static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200403static void f_winline(typval_T *argvars, typval_T *rettv);
404static void f_winnr(typval_T *argvars, typval_T *rettv);
405static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
406static void f_winrestview(typval_T *argvars, typval_T *rettv);
407static void f_winsaveview(typval_T *argvars, typval_T *rettv);
408static void f_winwidth(typval_T *argvars, typval_T *rettv);
409static void f_writefile(typval_T *argvars, typval_T *rettv);
410static void f_wordcount(typval_T *argvars, typval_T *rettv);
411static void f_xor(typval_T *argvars, typval_T *rettv);
412
413/*
414 * Array with names and number of arguments of all internal functions
415 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
416 */
417static struct fst
418{
419 char *f_name; /* function name */
420 char f_min_argc; /* minimal number of arguments */
421 char f_max_argc; /* maximal number of arguments */
422 void (*f_func)(typval_T *args, typval_T *rvar);
423 /* implementation of function */
424} functions[] =
425{
426#ifdef FEAT_FLOAT
427 {"abs", 1, 1, f_abs},
428 {"acos", 1, 1, f_acos}, /* WJMc */
429#endif
430 {"add", 2, 2, f_add},
431 {"and", 2, 2, f_and},
432 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200433 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200434 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435 {"argidx", 0, 0, f_argidx},
436 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200437 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200438#ifdef FEAT_FLOAT
439 {"asin", 1, 1, f_asin}, /* WJMc */
440#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100441 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100443 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200445 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200446 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100447 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200448 {"assert_match", 2, 3, f_assert_match},
449 {"assert_notequal", 2, 3, f_assert_notequal},
450 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100451 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200452 {"assert_true", 1, 2, f_assert_true},
453#ifdef FEAT_FLOAT
454 {"atan", 1, 1, f_atan},
455 {"atan2", 2, 2, f_atan2},
456#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100457#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +0200458 {"balloon_gettext", 0, 0, f_balloon_gettext},
Bram Moolenaar59716a22017-03-01 20:32:44 +0100459 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100460# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100461 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100462# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100463#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464 {"browse", 4, 4, f_browse},
465 {"browsedir", 2, 2, f_browsedir},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200466 {"bufadd", 1, 1, f_bufadd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467 {"bufexists", 1, 1, f_bufexists},
468 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
469 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
470 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
471 {"buflisted", 1, 1, f_buflisted},
Bram Moolenaar15e248e2019-06-30 20:21:37 +0200472 {"bufload", 1, 1, f_bufload},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473 {"bufloaded", 1, 1, f_bufloaded},
474 {"bufname", 1, 1, f_bufname},
475 {"bufnr", 1, 2, f_bufnr},
476 {"bufwinid", 1, 1, f_bufwinid},
477 {"bufwinnr", 1, 1, f_bufwinnr},
478 {"byte2line", 1, 1, f_byte2line},
479 {"byteidx", 2, 2, f_byteidx},
480 {"byteidxcomp", 2, 2, f_byteidxcomp},
481 {"call", 2, 3, f_call},
482#ifdef FEAT_FLOAT
483 {"ceil", 1, 1, f_ceil},
484#endif
485#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100486 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200488 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200489 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
490 {"ch_evalraw", 2, 3, f_ch_evalraw},
491 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
492 {"ch_getjob", 1, 1, f_ch_getjob},
493 {"ch_info", 1, 1, f_ch_info},
494 {"ch_log", 1, 2, f_ch_log},
495 {"ch_logfile", 1, 2, f_ch_logfile},
496 {"ch_open", 1, 2, f_ch_open},
497 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100498 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200499 {"ch_readraw", 1, 2, f_ch_readraw},
500 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
501 {"ch_sendraw", 2, 3, f_ch_sendraw},
502 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200503 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200504#endif
505 {"changenr", 0, 0, f_changenr},
506 {"char2nr", 1, 2, f_char2nr},
Bram Moolenaar1063f3d2019-05-07 22:06:52 +0200507 {"chdir", 1, 1, f_chdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100509 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200510 {"col", 1, 1, f_col},
511#if defined(FEAT_INS_EXPAND)
512 {"complete", 2, 2, f_complete},
513 {"complete_add", 1, 1, f_complete_add},
514 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100515 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#endif
517 {"confirm", 1, 4, f_confirm},
518 {"copy", 1, 1, f_copy},
519#ifdef FEAT_FLOAT
520 {"cos", 1, 1, f_cos},
521 {"cosh", 1, 1, f_cosh},
522#endif
523 {"count", 2, 4, f_count},
524 {"cscope_connection",0,3, f_cscope_connection},
525 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100526#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200527 {"debugbreak", 1, 1, f_debugbreak},
528#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529 {"deepcopy", 1, 2, f_deepcopy},
530 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200531 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200532 {"did_filetype", 0, 0, f_did_filetype},
533 {"diff_filler", 1, 1, f_diff_filler},
534 {"diff_hlID", 2, 2, f_diff_hlID},
535 {"empty", 1, 1, f_empty},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200536 {"environ", 0, 0, f_environ},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537 {"escape", 2, 2, f_escape},
538 {"eval", 1, 1, f_eval},
539 {"eventhandler", 0, 0, f_eventhandler},
540 {"executable", 1, 1, f_executable},
541 {"execute", 1, 2, f_execute},
542 {"exepath", 1, 1, f_exepath},
543 {"exists", 1, 1, f_exists},
544#ifdef FEAT_FLOAT
545 {"exp", 1, 1, f_exp},
546#endif
547 {"expand", 1, 3, f_expand},
Bram Moolenaar80dad482019-06-09 17:22:31 +0200548 {"expandcmd", 1, 1, f_expandcmd},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200549 {"extend", 2, 3, f_extend},
550 {"feedkeys", 1, 2, f_feedkeys},
551 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
552 {"filereadable", 1, 1, f_filereadable},
553 {"filewritable", 1, 1, f_filewritable},
554 {"filter", 2, 2, f_filter},
555 {"finddir", 1, 3, f_finddir},
556 {"findfile", 1, 3, f_findfile},
557#ifdef FEAT_FLOAT
558 {"float2nr", 1, 1, f_float2nr},
559 {"floor", 1, 1, f_floor},
560 {"fmod", 2, 2, f_fmod},
561#endif
562 {"fnameescape", 1, 1, f_fnameescape},
563 {"fnamemodify", 2, 2, f_fnamemodify},
564 {"foldclosed", 1, 1, f_foldclosed},
565 {"foldclosedend", 1, 1, f_foldclosedend},
566 {"foldlevel", 1, 1, f_foldlevel},
567 {"foldtext", 0, 0, f_foldtext},
568 {"foldtextresult", 1, 1, f_foldtextresult},
569 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200570 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200571 {"function", 1, 3, f_function},
572 {"garbagecollect", 0, 1, f_garbagecollect},
573 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200574 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575 {"getbufline", 2, 3, f_getbufline},
576 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100577 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578 {"getchar", 0, 1, f_getchar},
579 {"getcharmod", 0, 0, f_getcharmod},
580 {"getcharsearch", 0, 0, f_getcharsearch},
581 {"getcmdline", 0, 0, f_getcmdline},
582 {"getcmdpos", 0, 0, f_getcmdpos},
583 {"getcmdtype", 0, 0, f_getcmdtype},
584 {"getcmdwintype", 0, 0, f_getcmdwintype},
585#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200586 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200587#endif
588 {"getcurpos", 0, 0, f_getcurpos},
589 {"getcwd", 0, 2, f_getcwd},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200590 {"getenv", 1, 1, f_getenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200591 {"getfontname", 0, 1, f_getfontname},
592 {"getfperm", 1, 1, f_getfperm},
593 {"getfsize", 1, 1, f_getfsize},
594 {"getftime", 1, 1, f_getftime},
595 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100596 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200597 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200598 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100599 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600 {"getpid", 0, 0, f_getpid},
601 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200602 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603 {"getreg", 0, 3, f_getreg},
604 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200605 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200606 {"gettabvar", 2, 3, f_gettabvar},
607 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100608 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200609 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100610 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200611 {"getwinposx", 0, 0, f_getwinposx},
612 {"getwinposy", 0, 0, f_getwinposy},
613 {"getwinvar", 2, 3, f_getwinvar},
614 {"glob", 1, 4, f_glob},
615 {"glob2regpat", 1, 1, f_glob2regpat},
616 {"globpath", 2, 5, f_globpath},
617 {"has", 1, 1, f_has},
618 {"has_key", 2, 2, f_has_key},
619 {"haslocaldir", 0, 2, f_haslocaldir},
620 {"hasmapto", 1, 3, f_hasmapto},
621 {"highlightID", 1, 1, f_hlID}, /* obsolete */
622 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
623 {"histadd", 2, 2, f_histadd},
624 {"histdel", 1, 2, f_histdel},
625 {"histget", 1, 2, f_histget},
626 {"histnr", 1, 1, f_histnr},
627 {"hlID", 1, 1, f_hlID},
628 {"hlexists", 1, 1, f_hlexists},
629 {"hostname", 0, 0, f_hostname},
630 {"iconv", 3, 3, f_iconv},
631 {"indent", 1, 1, f_indent},
632 {"index", 2, 4, f_index},
633 {"input", 1, 3, f_input},
634 {"inputdialog", 1, 3, f_inputdialog},
635 {"inputlist", 1, 1, f_inputlist},
636 {"inputrestore", 0, 0, f_inputrestore},
637 {"inputsave", 0, 0, f_inputsave},
638 {"inputsecret", 1, 2, f_inputsecret},
639 {"insert", 2, 3, f_insert},
640 {"invert", 1, 1, f_invert},
641 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200642#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
643 {"isinf", 1, 1, f_isinf},
644#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645 {"islocked", 1, 1, f_islocked},
646#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
647 {"isnan", 1, 1, f_isnan},
648#endif
649 {"items", 1, 1, f_items},
650#ifdef FEAT_JOB_CHANNEL
651 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200652 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653 {"job_setoptions", 2, 2, f_job_setoptions},
654 {"job_start", 1, 2, f_job_start},
655 {"job_status", 1, 1, f_job_status},
656 {"job_stop", 1, 2, f_job_stop},
657#endif
658 {"join", 1, 2, f_join},
659 {"js_decode", 1, 1, f_js_decode},
660 {"js_encode", 1, 1, f_js_encode},
661 {"json_decode", 1, 1, f_json_decode},
662 {"json_encode", 1, 1, f_json_encode},
663 {"keys", 1, 1, f_keys},
664 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
665 {"len", 1, 1, f_len},
666 {"libcall", 3, 3, f_libcall},
667 {"libcallnr", 3, 3, f_libcallnr},
668 {"line", 1, 1, f_line},
669 {"line2byte", 1, 1, f_line2byte},
670 {"lispindent", 1, 1, f_lispindent},
Bram Moolenaar9d401282019-04-06 13:18:12 +0200671 {"list2str", 1, 2, f_list2str},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200672 {"listener_add", 1, 2, f_listener_add},
Bram Moolenaarfe1ade02019-05-14 21:20:36 +0200673 {"listener_flush", 0, 1, f_listener_flush},
Bram Moolenaar6ed88192019-05-11 18:37:44 +0200674 {"listener_remove", 1, 1, f_listener_remove},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200675 {"localtime", 0, 0, f_localtime},
676#ifdef FEAT_FLOAT
677 {"log", 1, 1, f_log},
678 {"log10", 1, 1, f_log10},
679#endif
680#ifdef FEAT_LUA
681 {"luaeval", 1, 2, f_luaeval},
682#endif
683 {"map", 2, 2, f_map},
684 {"maparg", 1, 4, f_maparg},
685 {"mapcheck", 1, 3, f_mapcheck},
686 {"match", 2, 4, f_match},
687 {"matchadd", 2, 5, f_matchadd},
688 {"matchaddpos", 2, 5, f_matchaddpos},
689 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100690 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200691 {"matchend", 2, 4, f_matchend},
692 {"matchlist", 2, 4, f_matchlist},
693 {"matchstr", 2, 4, f_matchstr},
694 {"matchstrpos", 2, 4, f_matchstrpos},
695 {"max", 1, 1, f_max},
696 {"min", 1, 1, f_min},
697#ifdef vim_mkdir
698 {"mkdir", 1, 3, f_mkdir},
699#endif
700 {"mode", 0, 1, f_mode},
701#ifdef FEAT_MZSCHEME
702 {"mzeval", 1, 1, f_mzeval},
703#endif
704 {"nextnonblank", 1, 1, f_nextnonblank},
705 {"nr2char", 1, 2, f_nr2char},
706 {"or", 2, 2, f_or},
707 {"pathshorten", 1, 1, f_pathshorten},
708#ifdef FEAT_PERL
709 {"perleval", 1, 1, f_perleval},
710#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200711#ifdef FEAT_TEXT_PROP
Bram Moolenaarcc31ad92019-05-30 19:25:06 +0200712 {"popup_atcursor", 2, 2, f_popup_atcursor},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200713 {"popup_beval", 2, 2, f_popup_beval},
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200714 {"popup_clear", 0, 0, f_popup_clear},
Bram Moolenaar9eaac892019-06-01 22:49:29 +0200715 {"popup_close", 1, 2, f_popup_close},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200716 {"popup_create", 2, 2, f_popup_create},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200717 {"popup_dialog", 2, 2, f_popup_dialog},
Bram Moolenaara730e552019-06-16 19:05:31 +0200718 {"popup_filter_menu", 2, 2, f_popup_filter_menu},
Bram Moolenaara42d9452019-06-15 21:46:30 +0200719 {"popup_filter_yesno", 2, 2, f_popup_filter_yesno},
Bram Moolenaar8c2a6002019-05-30 14:29:45 +0200720 {"popup_getoptions", 1, 1, f_popup_getoptions},
Bram Moolenaarccd6e342019-05-30 22:35:18 +0200721 {"popup_getpos", 1, 1, f_popup_getpos},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200722 {"popup_hide", 1, 1, f_popup_hide},
Bram Moolenaarb4f06282019-07-12 21:07:54 +0200723 {"popup_locate", 2, 2, f_popup_locate},
Bram Moolenaara730e552019-06-16 19:05:31 +0200724 {"popup_menu", 2, 2, f_popup_menu},
Bram Moolenaar60cdb302019-05-27 21:54:10 +0200725 {"popup_move", 2, 2, f_popup_move},
Bram Moolenaar68d48f42019-06-12 22:42:41 +0200726 {"popup_notification", 2, 2, f_popup_notification},
Bram Moolenaarae943152019-06-16 22:54:14 +0200727 {"popup_setoptions", 2, 2, f_popup_setoptions},
Bram Moolenaardc2ce582019-06-16 15:32:14 +0200728 {"popup_settext", 2, 2, f_popup_settext},
Bram Moolenaar2cd0dce2019-05-26 22:17:52 +0200729 {"popup_show", 1, 1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200730#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200731#ifdef FEAT_FLOAT
732 {"pow", 2, 2, f_pow},
733#endif
734 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100735 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200736#ifdef FEAT_JOB_CHANNEL
737 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200738 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200739 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
740#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100741#ifdef FEAT_TEXT_PROP
742 {"prop_add", 3, 3, f_prop_add},
743 {"prop_clear", 1, 3, f_prop_clear},
744 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100745 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100746 {"prop_type_add", 2, 2, f_prop_type_add},
747 {"prop_type_change", 2, 2, f_prop_type_change},
748 {"prop_type_delete", 1, 2, f_prop_type_delete},
749 {"prop_type_get", 1, 2, f_prop_type_get},
750 {"prop_type_list", 0, 1, f_prop_type_list},
751#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200752 {"pumvisible", 0, 0, f_pumvisible},
753#ifdef FEAT_PYTHON3
754 {"py3eval", 1, 1, f_py3eval},
755#endif
756#ifdef FEAT_PYTHON
757 {"pyeval", 1, 1, f_pyeval},
758#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100759#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
760 {"pyxeval", 1, 1, f_pyxeval},
761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762 {"range", 1, 3, f_range},
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200763 {"readdir", 1, 2, f_readdir},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200764 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200765 {"reg_executing", 0, 0, f_reg_executing},
766 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200767 {"reltime", 0, 2, f_reltime},
768#ifdef FEAT_FLOAT
769 {"reltimefloat", 1, 1, f_reltimefloat},
770#endif
771 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100772 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200773 {"remote_foreground", 1, 1, f_remote_foreground},
774 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100775 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100777 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778 {"remove", 2, 3, f_remove},
779 {"rename", 2, 2, f_rename},
780 {"repeat", 2, 2, f_repeat},
781 {"resolve", 1, 1, f_resolve},
782 {"reverse", 1, 1, f_reverse},
783#ifdef FEAT_FLOAT
784 {"round", 1, 1, f_round},
785#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100786#ifdef FEAT_RUBY
787 {"rubyeval", 1, 1, f_rubyeval},
788#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200789 {"screenattr", 2, 2, f_screenattr},
790 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100791 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200792 {"screencol", 0, 0, f_screencol},
Bram Moolenaarb3d17a22019-07-07 18:28:14 +0200793 {"screenpos", 3, 3, f_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200794 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100795 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200796 {"search", 1, 4, f_search},
797 {"searchdecl", 1, 3, f_searchdecl},
798 {"searchpair", 3, 7, f_searchpair},
799 {"searchpairpos", 3, 7, f_searchpairpos},
800 {"searchpos", 1, 4, f_searchpos},
801 {"server2client", 2, 2, f_server2client},
802 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200803 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804 {"setbufvar", 3, 3, f_setbufvar},
805 {"setcharsearch", 1, 1, f_setcharsearch},
806 {"setcmdpos", 1, 1, f_setcmdpos},
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200807 {"setenv", 2, 2, f_setenv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808 {"setfperm", 2, 2, f_setfperm},
809 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200810 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100811 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200812 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200813 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814 {"setreg", 2, 3, f_setreg},
815 {"settabvar", 3, 3, f_settabvar},
816 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100817 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200818 {"setwinvar", 3, 3, f_setwinvar},
819#ifdef FEAT_CRYPT
820 {"sha256", 1, 1, f_sha256},
821#endif
822 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100823 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100824#ifdef FEAT_SIGNS
825 {"sign_define", 1, 2, f_sign_define},
826 {"sign_getdefined", 0, 1, f_sign_getdefined},
827 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100828 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100829 {"sign_place", 4, 5, f_sign_place},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200830 {"sign_placelist", 1, 1, f_sign_placelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100831 {"sign_undefine", 0, 1, f_sign_undefine},
832 {"sign_unplace", 1, 2, f_sign_unplace},
Bram Moolenaar809ce4d2019-07-13 21:21:40 +0200833 {"sign_unplacelist", 1, 2, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100834#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835 {"simplify", 1, 1, f_simplify},
836#ifdef FEAT_FLOAT
837 {"sin", 1, 1, f_sin},
838 {"sinh", 1, 1, f_sinh},
839#endif
840 {"sort", 1, 3, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200841#ifdef FEAT_SOUND
Bram Moolenaar3ff5f0f2019-06-10 13:11:22 +0200842 {"sound_clear", 0, 0, f_sound_clear},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200843 {"sound_playevent", 1, 2, f_sound_playevent},
844 {"sound_playfile", 1, 2, f_sound_playfile},
845 {"sound_stop", 1, 1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200846#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847 {"soundfold", 1, 1, f_soundfold},
848 {"spellbadword", 0, 1, f_spellbadword},
849 {"spellsuggest", 1, 3, f_spellsuggest},
850 {"split", 1, 3, f_split},
851#ifdef FEAT_FLOAT
852 {"sqrt", 1, 1, f_sqrt},
853 {"str2float", 1, 1, f_str2float},
854#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200855 {"str2list", 1, 2, f_str2list},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856 {"str2nr", 1, 2, f_str2nr},
857 {"strcharpart", 2, 3, f_strcharpart},
858 {"strchars", 1, 2, f_strchars},
859 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
860#ifdef HAVE_STRFTIME
861 {"strftime", 1, 2, f_strftime},
862#endif
863 {"strgetchar", 2, 2, f_strgetchar},
864 {"stridx", 2, 3, f_stridx},
865 {"string", 1, 1, f_string},
866 {"strlen", 1, 1, f_strlen},
867 {"strpart", 2, 3, f_strpart},
868 {"strridx", 2, 3, f_strridx},
869 {"strtrans", 1, 1, f_strtrans},
870 {"strwidth", 1, 1, f_strwidth},
871 {"submatch", 1, 2, f_submatch},
872 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200873 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200874 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200875 {"synID", 3, 3, f_synID},
876 {"synIDattr", 2, 3, f_synIDattr},
877 {"synIDtrans", 1, 1, f_synIDtrans},
878 {"synconcealed", 2, 2, f_synconcealed},
879 {"synstack", 2, 2, f_synstack},
880 {"system", 1, 2, f_system},
881 {"systemlist", 1, 2, f_systemlist},
882 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
883 {"tabpagenr", 0, 1, f_tabpagenr},
884 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
885 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100886 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887#ifdef FEAT_FLOAT
888 {"tan", 1, 1, f_tan},
889 {"tanh", 1, 1, f_tanh},
890#endif
891 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200892#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100893 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
894 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100895 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200896 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200897# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
898 {"term_getansicolors", 1, 1, f_term_getansicolors},
899# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200900 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200901 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200902 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200903 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200904 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200905 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200906 {"term_getstatus", 1, 1, f_term_getstatus},
907 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200908 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200909 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200910 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200911 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200912# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
913 {"term_setansicolors", 2, 2, f_term_setansicolors},
914# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100915 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100916 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200917 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200918 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200919 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200920#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
922 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200923 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200924 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaaradc67142019-06-22 01:40:42 +0200925 {"test_garbagecollect_soon", 0, 0, f_test_garbagecollect_soon},
Bram Moolenaareda65222019-05-16 20:29:44 +0200926 {"test_getvalue", 1, 1, f_test_getvalue},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100927 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100928 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#ifdef FEAT_JOB_CHANNEL
930 {"test_null_channel", 0, 0, f_test_null_channel},
931#endif
932 {"test_null_dict", 0, 0, f_test_null_dict},
933#ifdef FEAT_JOB_CHANNEL
934 {"test_null_job", 0, 0, f_test_null_job},
935#endif
936 {"test_null_list", 0, 0, f_test_null_list},
937 {"test_null_partial", 0, 0, f_test_null_partial},
938 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200939 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100940 {"test_override", 2, 2, f_test_override},
941 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200942#ifdef FEAT_GUI
943 {"test_scrollbar", 3, 3, f_test_scrollbar},
944#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200945#ifdef FEAT_MOUSE
Bram Moolenaarbb8476b2019-05-04 15:47:48 +0200946 {"test_setmouse", 2, 2, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200947#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948 {"test_settime", 1, 1, f_test_settime},
949#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200950 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200951 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200952 {"timer_start", 2, 3, f_timer_start},
953 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200954 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955#endif
956 {"tolower", 1, 1, f_tolower},
957 {"toupper", 1, 1, f_toupper},
958 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100959 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200960#ifdef FEAT_FLOAT
961 {"trunc", 1, 1, f_trunc},
962#endif
963 {"type", 1, 1, f_type},
964 {"undofile", 1, 1, f_undofile},
965 {"undotree", 0, 0, f_undotree},
966 {"uniq", 1, 3, f_uniq},
967 {"values", 1, 1, f_values},
968 {"virtcol", 1, 1, f_virtcol},
969 {"visualmode", 0, 1, f_visualmode},
970 {"wildmenumode", 0, 0, f_wildmenumode},
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200971 {"win_execute", 2, 3, f_win_execute},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200972 {"win_findbuf", 1, 1, f_win_findbuf},
973 {"win_getid", 0, 2, f_win_getid},
974 {"win_gotoid", 1, 1, f_win_gotoid},
975 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
976 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100977 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978 {"winbufnr", 1, 1, f_winbufnr},
979 {"wincol", 0, 0, f_wincol},
980 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200981 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200982 {"winline", 0, 0, f_winline},
983 {"winnr", 0, 1, f_winnr},
984 {"winrestcmd", 0, 0, f_winrestcmd},
985 {"winrestview", 1, 1, f_winrestview},
986 {"winsaveview", 0, 0, f_winsaveview},
987 {"winwidth", 1, 1, f_winwidth},
988 {"wordcount", 0, 0, f_wordcount},
989 {"writefile", 2, 3, f_writefile},
990 {"xor", 2, 2, f_xor},
991};
992
993#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
994
995/*
996 * Function given to ExpandGeneric() to obtain the list of internal
997 * or user defined function names.
998 */
999 char_u *
1000get_function_name(expand_T *xp, int idx)
1001{
1002 static int intidx = -1;
1003 char_u *name;
1004
1005 if (idx == 0)
1006 intidx = -1;
1007 if (intidx < 0)
1008 {
1009 name = get_user_func_name(xp, idx);
1010 if (name != NULL)
1011 return name;
1012 }
1013 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1014 {
1015 STRCPY(IObuff, functions[intidx].f_name);
1016 STRCAT(IObuff, "(");
1017 if (functions[intidx].f_max_argc == 0)
1018 STRCAT(IObuff, ")");
1019 return IObuff;
1020 }
1021
1022 return NULL;
1023}
1024
1025/*
1026 * Function given to ExpandGeneric() to obtain the list of internal or
1027 * user defined variable or function names.
1028 */
1029 char_u *
1030get_expr_name(expand_T *xp, int idx)
1031{
1032 static int intidx = -1;
1033 char_u *name;
1034
1035 if (idx == 0)
1036 intidx = -1;
1037 if (intidx < 0)
1038 {
1039 name = get_function_name(xp, idx);
1040 if (name != NULL)
1041 return name;
1042 }
1043 return get_user_var_name(xp, ++intidx);
1044}
1045
1046#endif /* FEAT_CMDL_COMPL */
1047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048/*
1049 * Find internal function in table above.
1050 * Return index, or -1 if not found
1051 */
1052 int
1053find_internal_func(
1054 char_u *name) /* name of the function */
1055{
1056 int first = 0;
1057 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1058 int cmp;
1059 int x;
1060
1061 /*
1062 * Find the function name in the table. Binary search.
1063 */
1064 while (first <= last)
1065 {
1066 x = first + ((unsigned)(last - first) >> 1);
1067 cmp = STRCMP(name, functions[x].f_name);
1068 if (cmp < 0)
1069 last = x - 1;
1070 else if (cmp > 0)
1071 first = x + 1;
1072 else
1073 return x;
1074 }
1075 return -1;
1076}
1077
1078 int
1079call_internal_func(
1080 char_u *name,
1081 int argcount,
1082 typval_T *argvars,
1083 typval_T *rettv)
1084{
1085 int i;
1086
1087 i = find_internal_func(name);
1088 if (i < 0)
1089 return ERROR_UNKNOWN;
1090 if (argcount < functions[i].f_min_argc)
1091 return ERROR_TOOFEW;
1092 if (argcount > functions[i].f_max_argc)
1093 return ERROR_TOOMANY;
1094 argvars[argcount].v_type = VAR_UNKNOWN;
1095 functions[i].f_func(argvars, rettv);
1096 return ERROR_NONE;
1097}
1098
1099/*
1100 * Return TRUE for a non-zero Number and a non-empty String.
1101 */
1102 static int
1103non_zero_arg(typval_T *argvars)
1104{
1105 return ((argvars[0].v_type == VAR_NUMBER
1106 && argvars[0].vval.v_number != 0)
1107 || (argvars[0].v_type == VAR_SPECIAL
1108 && argvars[0].vval.v_number == VVAL_TRUE)
1109 || (argvars[0].v_type == VAR_STRING
1110 && argvars[0].vval.v_string != NULL
1111 && *argvars[0].vval.v_string != NUL));
1112}
1113
1114/*
1115 * Get the lnum from the first argument.
1116 * Also accepts ".", "$", etc., but that only works for the current buffer.
1117 * Returns -1 on error.
1118 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001119 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001120tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001121{
1122 typval_T rettv;
1123 linenr_T lnum;
1124
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001125 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001126 if (lnum == 0) /* no valid number, try using line() */
1127 {
1128 rettv.v_type = VAR_NUMBER;
1129 f_line(argvars, &rettv);
1130 lnum = (linenr_T)rettv.vval.v_number;
1131 clear_tv(&rettv);
1132 }
1133 return lnum;
1134}
1135
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001136/*
1137 * Get the lnum from the first argument.
1138 * Also accepts "$", then "buf" is used.
1139 * Returns 0 on error.
1140 */
1141 static linenr_T
1142tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1143{
1144 if (argvars[0].v_type == VAR_STRING
1145 && argvars[0].vval.v_string != NULL
1146 && argvars[0].vval.v_string[0] == '$'
1147 && buf != NULL)
1148 return buf->b_ml.ml_line_count;
1149 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1150}
1151
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001152#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001153/*
1154 * Get the float value of "argvars[0]" into "f".
1155 * Returns FAIL when the argument is not a Number or Float.
1156 */
1157 static int
1158get_float_arg(typval_T *argvars, float_T *f)
1159{
1160 if (argvars[0].v_type == VAR_FLOAT)
1161 {
1162 *f = argvars[0].vval.v_float;
1163 return OK;
1164 }
1165 if (argvars[0].v_type == VAR_NUMBER)
1166 {
1167 *f = (float_T)argvars[0].vval.v_number;
1168 return OK;
1169 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001170 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001171 return FAIL;
1172}
1173
1174/*
1175 * "abs(expr)" function
1176 */
1177 static void
1178f_abs(typval_T *argvars, typval_T *rettv)
1179{
1180 if (argvars[0].v_type == VAR_FLOAT)
1181 {
1182 rettv->v_type = VAR_FLOAT;
1183 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1184 }
1185 else
1186 {
1187 varnumber_T n;
1188 int error = FALSE;
1189
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001190 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001191 if (error)
1192 rettv->vval.v_number = -1;
1193 else if (n > 0)
1194 rettv->vval.v_number = n;
1195 else
1196 rettv->vval.v_number = -n;
1197 }
1198}
1199
1200/*
1201 * "acos()" function
1202 */
1203 static void
1204f_acos(typval_T *argvars, typval_T *rettv)
1205{
1206 float_T f = 0.0;
1207
1208 rettv->v_type = VAR_FLOAT;
1209 if (get_float_arg(argvars, &f) == OK)
1210 rettv->vval.v_float = acos(f);
1211 else
1212 rettv->vval.v_float = 0.0;
1213}
1214#endif
1215
1216/*
1217 * "add(list, item)" function
1218 */
1219 static void
1220f_add(typval_T *argvars, typval_T *rettv)
1221{
1222 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001223 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001224
1225 rettv->vval.v_number = 1; /* Default: Failed */
1226 if (argvars[0].v_type == VAR_LIST)
1227 {
1228 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001229 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001230 (char_u *)N_("add() argument"), TRUE)
1231 && list_append_tv(l, &argvars[1]) == OK)
1232 copy_tv(&argvars[0], rettv);
1233 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001234 else if (argvars[0].v_type == VAR_BLOB)
1235 {
1236 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001237 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001238 (char_u *)N_("add() argument"), TRUE))
1239 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001240 int error = FALSE;
1241 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1242
1243 if (!error)
1244 {
1245 ga_append(&b->bv_ga, (int)n);
1246 copy_tv(&argvars[0], rettv);
1247 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001248 }
1249 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001250 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001251 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252}
1253
1254/*
1255 * "and(expr, expr)" function
1256 */
1257 static void
1258f_and(typval_T *argvars, typval_T *rettv)
1259{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001260 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1261 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001262}
1263
1264/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001265 * If there is a window for "curbuf", make it the current window.
1266 */
1267 static void
1268find_win_for_curbuf(void)
1269{
1270 wininfo_T *wip;
1271
1272 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1273 {
1274 if (wip->wi_win != NULL)
1275 {
1276 curwin = wip->wi_win;
1277 break;
1278 }
1279 }
1280}
1281
1282/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001283 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001284 */
1285 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001286set_buffer_lines(
1287 buf_T *buf,
1288 linenr_T lnum_arg,
1289 int append,
1290 typval_T *lines,
1291 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001292{
Bram Moolenaarca851592018-06-06 21:04:07 +02001293 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1294 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 list_T *l = NULL;
1296 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001297 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001298 linenr_T append_lnum;
1299 buf_T *curbuf_save = NULL;
1300 win_T *curwin_save = NULL;
1301 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302
Bram Moolenaarca851592018-06-06 21:04:07 +02001303 /* When using the current buffer ml_mfp will be set if needed. Useful when
1304 * setline() is used on startup. For other buffers the buffer must be
1305 * loaded. */
1306 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001308 rettv->vval.v_number = 1; /* FAIL */
1309 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001310 }
1311
Bram Moolenaarca851592018-06-06 21:04:07 +02001312 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001314 curbuf_save = curbuf;
1315 curwin_save = curwin;
1316 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001317 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001318 }
1319
1320 if (append)
1321 // appendbufline() uses the line number below which we insert
1322 append_lnum = lnum - 1;
1323 else
1324 // setbufline() uses the line number above which we insert, we only
1325 // append if it's below the last line
1326 append_lnum = curbuf->b_ml.ml_line_count;
1327
1328 if (lines->v_type == VAR_LIST)
1329 {
1330 l = lines->vval.v_list;
1331 li = l->lv_first;
1332 }
1333 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001334 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001335
1336 /* default result is zero == OK */
1337 for (;;)
1338 {
1339 if (l != NULL)
1340 {
1341 /* list argument, get next string */
1342 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001344 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001345 li = li->li_next;
1346 }
1347
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 rettv->vval.v_number = 1; /* FAIL */
1349 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1350 break;
1351
1352 /* When coming here from Insert mode, sync undo, so that this can be
1353 * undone separately from what was previously inserted. */
1354 if (u_sync_once == 2)
1355 {
1356 u_sync_once = 1; /* notify that u_sync() was called */
1357 u_sync(TRUE);
1358 }
1359
1360 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1361 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001362 // Existing line, replace it.
1363 // Removes any existing text properties.
1364 if (u_savesub(lnum) == OK && ml_replace_len(
1365 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001366 {
1367 changed_bytes(lnum, 0);
1368 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1369 check_cursor_col();
1370 rettv->vval.v_number = 0; /* OK */
1371 }
1372 }
1373 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1374 {
1375 /* append the line */
1376 ++added;
1377 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1378 rettv->vval.v_number = 0; /* OK */
1379 }
1380
1381 if (l == NULL) /* only one string argument */
1382 break;
1383 ++lnum;
1384 }
1385
1386 if (added > 0)
1387 {
1388 win_T *wp;
1389 tabpage_T *tp;
1390
1391 appended_lines_mark(append_lnum, added);
1392 FOR_ALL_TAB_WINDOWS(tp, wp)
1393 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1394 wp->w_cursor.lnum += added;
1395 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001396 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001397 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001398
1399 if (!is_curbuf)
1400 {
1401 curbuf = curbuf_save;
1402 curwin = curwin_save;
1403 }
1404}
1405
1406/*
1407 * "append(lnum, string/list)" function
1408 */
1409 static void
1410f_append(typval_T *argvars, typval_T *rettv)
1411{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001412 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001413
1414 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1415}
1416
1417/*
1418 * "appendbufline(buf, lnum, string/list)" function
1419 */
1420 static void
1421f_appendbufline(typval_T *argvars, typval_T *rettv)
1422{
1423 linenr_T lnum;
1424 buf_T *buf;
1425
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001426 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001427 if (buf == NULL)
1428 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001429 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001430 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001431 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001432 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1433 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434}
1435
1436/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001437 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438 */
1439 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001440f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001441{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001442 win_T *wp;
1443
1444 if (argvars[0].v_type == VAR_UNKNOWN)
1445 // use the current window
1446 rettv->vval.v_number = ARGCOUNT;
1447 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001448 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001449 // use the global argument list
1450 rettv->vval.v_number = GARGCOUNT;
1451 else
1452 {
1453 // use the argument list of the specified window
1454 wp = find_win_by_nr_or_id(&argvars[0]);
1455 if (wp != NULL)
1456 rettv->vval.v_number = WARGCOUNT(wp);
1457 else
1458 rettv->vval.v_number = -1;
1459 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001460}
1461
1462/*
1463 * "argidx()" function
1464 */
1465 static void
1466f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1467{
1468 rettv->vval.v_number = curwin->w_arg_idx;
1469}
1470
1471/*
1472 * "arglistid()" function
1473 */
1474 static void
1475f_arglistid(typval_T *argvars, typval_T *rettv)
1476{
1477 win_T *wp;
1478
1479 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001480 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001481 if (wp != NULL)
1482 rettv->vval.v_number = wp->w_alist->id;
1483}
1484
1485/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001486 * Get the argument list for a given window
1487 */
1488 static void
1489get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1490{
1491 int idx;
1492
1493 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1494 for (idx = 0; idx < argcount; ++idx)
1495 list_append_string(rettv->vval.v_list,
1496 alist_name(&arglist[idx]), -1);
1497}
1498
1499/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500 * "argv(nr)" function
1501 */
1502 static void
1503f_argv(typval_T *argvars, typval_T *rettv)
1504{
1505 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001506 aentry_T *arglist = NULL;
1507 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508
1509 if (argvars[0].v_type != VAR_UNKNOWN)
1510 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001511 if (argvars[1].v_type == VAR_UNKNOWN)
1512 {
1513 arglist = ARGLIST;
1514 argcount = ARGCOUNT;
1515 }
1516 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001517 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001518 {
1519 arglist = GARGLIST;
1520 argcount = GARGCOUNT;
1521 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001522 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001523 {
1524 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1525
1526 if (wp != NULL)
1527 {
1528 /* Use the argument list of the specified window */
1529 arglist = WARGLIST(wp);
1530 argcount = WARGCOUNT(wp);
1531 }
1532 }
1533
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001534 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001535 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001536 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001537 if (arglist != NULL && idx >= 0 && idx < argcount)
1538 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1539 else if (idx == -1)
1540 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001541 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001542 else
1543 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544}
1545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546#ifdef FEAT_FLOAT
1547/*
1548 * "asin()" function
1549 */
1550 static void
1551f_asin(typval_T *argvars, typval_T *rettv)
1552{
1553 float_T f = 0.0;
1554
1555 rettv->v_type = VAR_FLOAT;
1556 if (get_float_arg(argvars, &f) == OK)
1557 rettv->vval.v_float = asin(f);
1558 else
1559 rettv->vval.v_float = 0.0;
1560}
1561
1562/*
1563 * "atan()" function
1564 */
1565 static void
1566f_atan(typval_T *argvars, typval_T *rettv)
1567{
1568 float_T f = 0.0;
1569
1570 rettv->v_type = VAR_FLOAT;
1571 if (get_float_arg(argvars, &f) == OK)
1572 rettv->vval.v_float = atan(f);
1573 else
1574 rettv->vval.v_float = 0.0;
1575}
1576
1577/*
1578 * "atan2()" function
1579 */
1580 static void
1581f_atan2(typval_T *argvars, typval_T *rettv)
1582{
1583 float_T fx = 0.0, fy = 0.0;
1584
1585 rettv->v_type = VAR_FLOAT;
1586 if (get_float_arg(argvars, &fx) == OK
1587 && get_float_arg(&argvars[1], &fy) == OK)
1588 rettv->vval.v_float = atan2(fx, fy);
1589 else
1590 rettv->vval.v_float = 0.0;
1591}
1592#endif
1593
1594/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001595 * "balloon_show()" function
1596 */
1597#ifdef FEAT_BEVAL
1598 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001599f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1600{
1601 rettv->v_type = VAR_STRING;
1602 if (balloonEval != NULL)
1603 {
1604 if (balloonEval->msg == NULL)
1605 rettv->vval.v_string = NULL;
1606 else
1607 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1608 }
1609}
1610
1611 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001612f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1613{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001614 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001615 {
1616 if (argvars[0].v_type == VAR_LIST
1617# ifdef FEAT_GUI
1618 && !gui.in_use
1619# endif
1620 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001621 {
1622 list_T *l = argvars[0].vval.v_list;
1623
1624 // empty list removes the balloon
1625 post_balloon(balloonEval, NULL,
1626 l == NULL || l->lv_len == 0 ? NULL : l);
1627 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001628 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001629 {
1630 char_u *mesg = tv_get_string_chk(&argvars[0]);
1631
1632 if (mesg != NULL)
1633 // empty string removes the balloon
1634 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1635 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001636 }
1637}
1638
Bram Moolenaar669a8282017-11-19 20:13:05 +01001639# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001640 static void
1641f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1642{
1643 if (rettv_list_alloc(rettv) == OK)
1644 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001645 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001646
1647 if (msg != NULL)
1648 {
1649 pumitem_T *array;
1650 int size = split_message(msg, &array);
1651 int i;
1652
1653 /* Skip the first and last item, they are always empty. */
1654 for (i = 1; i < size - 1; ++i)
1655 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001656 while (size > 0)
1657 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001658 vim_free(array);
1659 }
1660 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001661}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001662# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001663#endif
1664
1665/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001666 * "browse(save, title, initdir, default)" function
1667 */
1668 static void
1669f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1670{
1671#ifdef FEAT_BROWSE
1672 int save;
1673 char_u *title;
1674 char_u *initdir;
1675 char_u *defname;
1676 char_u buf[NUMBUFLEN];
1677 char_u buf2[NUMBUFLEN];
1678 int error = FALSE;
1679
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001680 save = (int)tv_get_number_chk(&argvars[0], &error);
1681 title = tv_get_string_chk(&argvars[1]);
1682 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1683 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684
1685 if (error || title == NULL || initdir == NULL || defname == NULL)
1686 rettv->vval.v_string = NULL;
1687 else
1688 rettv->vval.v_string =
1689 do_browse(save ? BROWSE_SAVE : 0,
1690 title, defname, NULL, initdir, NULL, curbuf);
1691#else
1692 rettv->vval.v_string = NULL;
1693#endif
1694 rettv->v_type = VAR_STRING;
1695}
1696
1697/*
1698 * "browsedir(title, initdir)" function
1699 */
1700 static void
1701f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1702{
1703#ifdef FEAT_BROWSE
1704 char_u *title;
1705 char_u *initdir;
1706 char_u buf[NUMBUFLEN];
1707
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001708 title = tv_get_string_chk(&argvars[0]);
1709 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001710
1711 if (title == NULL || initdir == NULL)
1712 rettv->vval.v_string = NULL;
1713 else
1714 rettv->vval.v_string = do_browse(BROWSE_DIR,
1715 title, NULL, NULL, initdir, NULL, curbuf);
1716#else
1717 rettv->vval.v_string = NULL;
1718#endif
1719 rettv->v_type = VAR_STRING;
1720}
1721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722/*
1723 * Find a buffer by number or exact name.
1724 */
1725 static buf_T *
1726find_buffer(typval_T *avar)
1727{
1728 buf_T *buf = NULL;
1729
1730 if (avar->v_type == VAR_NUMBER)
1731 buf = buflist_findnr((int)avar->vval.v_number);
1732 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1733 {
1734 buf = buflist_findname_exp(avar->vval.v_string);
1735 if (buf == NULL)
1736 {
1737 /* No full path name match, try a match with a URL or a "nofile"
1738 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001739 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001740 if (buf->b_fname != NULL
1741 && (path_with_url(buf->b_fname)
1742#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001743 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001744#endif
1745 )
1746 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1747 break;
1748 }
1749 }
1750 return buf;
1751}
1752
1753/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001754 * "bufadd(expr)" function
1755 */
1756 static void
1757f_bufadd(typval_T *argvars, typval_T *rettv)
1758{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001759 char_u *name = tv_get_string(&argvars[0]);
1760
1761 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001762}
1763
1764/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001765 * "bufexists(expr)" function
1766 */
1767 static void
1768f_bufexists(typval_T *argvars, typval_T *rettv)
1769{
1770 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1771}
1772
1773/*
1774 * "buflisted(expr)" function
1775 */
1776 static void
1777f_buflisted(typval_T *argvars, typval_T *rettv)
1778{
1779 buf_T *buf;
1780
1781 buf = find_buffer(&argvars[0]);
1782 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1783}
1784
1785/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001786 * "bufload(expr)" function
1787 */
1788 static void
1789f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1790{
1791 buf_T *buf = get_buf_arg(&argvars[0]);
1792
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001793 if (buf != NULL)
1794 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001795}
1796
1797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001798 * "bufloaded(expr)" function
1799 */
1800 static void
1801f_bufloaded(typval_T *argvars, typval_T *rettv)
1802{
1803 buf_T *buf;
1804
1805 buf = find_buffer(&argvars[0]);
1806 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1807}
1808
1809 buf_T *
1810buflist_find_by_name(char_u *name, int curtab_only)
1811{
1812 int save_magic;
1813 char_u *save_cpo;
1814 buf_T *buf;
1815
1816 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1817 save_magic = p_magic;
1818 p_magic = TRUE;
1819 save_cpo = p_cpo;
1820 p_cpo = (char_u *)"";
1821
1822 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1823 TRUE, FALSE, curtab_only));
1824
1825 p_magic = save_magic;
1826 p_cpo = save_cpo;
1827 return buf;
1828}
1829
1830/*
1831 * Get buffer by number or pattern.
1832 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001833 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001834tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835{
1836 char_u *name = tv->vval.v_string;
1837 buf_T *buf;
1838
1839 if (tv->v_type == VAR_NUMBER)
1840 return buflist_findnr((int)tv->vval.v_number);
1841 if (tv->v_type != VAR_STRING)
1842 return NULL;
1843 if (name == NULL || *name == NUL)
1844 return curbuf;
1845 if (name[0] == '$' && name[1] == NUL)
1846 return lastbuf;
1847
1848 buf = buflist_find_by_name(name, curtab_only);
1849
1850 /* If not found, try expanding the name, like done for bufexists(). */
1851 if (buf == NULL)
1852 buf = find_buffer(tv);
1853
1854 return buf;
1855}
1856
1857/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001858 * Get the buffer from "arg" and give an error and return NULL if it is not
1859 * valid.
1860 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001861 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001862get_buf_arg(typval_T *arg)
1863{
1864 buf_T *buf;
1865
1866 ++emsg_off;
1867 buf = tv_get_buf(arg, FALSE);
1868 --emsg_off;
1869 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001870 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001871 return buf;
1872}
1873
1874/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001875 * "bufname(expr)" function
1876 */
1877 static void
1878f_bufname(typval_T *argvars, typval_T *rettv)
1879{
1880 buf_T *buf;
1881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001882 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001883 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001884 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001885 rettv->v_type = VAR_STRING;
1886 if (buf != NULL && buf->b_fname != NULL)
1887 rettv->vval.v_string = vim_strsave(buf->b_fname);
1888 else
1889 rettv->vval.v_string = NULL;
1890 --emsg_off;
1891}
1892
1893/*
1894 * "bufnr(expr)" function
1895 */
1896 static void
1897f_bufnr(typval_T *argvars, typval_T *rettv)
1898{
1899 buf_T *buf;
1900 int error = FALSE;
1901 char_u *name;
1902
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001903 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001904 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001905 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001906 --emsg_off;
1907
1908 /* If the buffer isn't found and the second argument is not zero create a
1909 * new buffer. */
1910 if (buf == NULL
1911 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001912 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001913 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001914 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915 && !error)
1916 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1917
1918 if (buf != NULL)
1919 rettv->vval.v_number = buf->b_fnum;
1920 else
1921 rettv->vval.v_number = -1;
1922}
1923
1924 static void
1925buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1926{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 win_T *wp;
1928 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001929 buf_T *buf;
1930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001931 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001932 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001933 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001934 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 {
1936 ++winnr;
1937 if (wp->w_buffer == buf)
1938 break;
1939 }
1940 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001941 --emsg_off;
1942}
1943
1944/*
1945 * "bufwinid(nr)" function
1946 */
1947 static void
1948f_bufwinid(typval_T *argvars, typval_T *rettv)
1949{
1950 buf_win_common(argvars, rettv, FALSE);
1951}
1952
1953/*
1954 * "bufwinnr(nr)" function
1955 */
1956 static void
1957f_bufwinnr(typval_T *argvars, typval_T *rettv)
1958{
1959 buf_win_common(argvars, rettv, TRUE);
1960}
1961
1962/*
1963 * "byte2line(byte)" function
1964 */
1965 static void
1966f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1967{
1968#ifndef FEAT_BYTEOFF
1969 rettv->vval.v_number = -1;
1970#else
1971 long boff = 0;
1972
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001973 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001974 if (boff < 0)
1975 rettv->vval.v_number = -1;
1976 else
1977 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1978 (linenr_T)0, &boff);
1979#endif
1980}
1981
1982 static void
1983byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1984{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 char_u *str;
1987 varnumber_T idx;
1988
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001989 str = tv_get_string_chk(&argvars[0]);
1990 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 rettv->vval.v_number = -1;
1992 if (str == NULL || idx < 0)
1993 return;
1994
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 t = str;
1996 for ( ; idx > 0; idx--)
1997 {
1998 if (*t == NUL) /* EOL reached */
1999 return;
2000 if (enc_utf8 && comp)
2001 t += utf_ptr2len(t);
2002 else
2003 t += (*mb_ptr2len)(t);
2004 }
2005 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006}
2007
2008/*
2009 * "byteidx()" function
2010 */
2011 static void
2012f_byteidx(typval_T *argvars, typval_T *rettv)
2013{
2014 byteidx(argvars, rettv, FALSE);
2015}
2016
2017/*
2018 * "byteidxcomp()" function
2019 */
2020 static void
2021f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2022{
2023 byteidx(argvars, rettv, TRUE);
2024}
2025
2026/*
2027 * "call(func, arglist [, dict])" function
2028 */
2029 static void
2030f_call(typval_T *argvars, typval_T *rettv)
2031{
2032 char_u *func;
2033 partial_T *partial = NULL;
2034 dict_T *selfdict = NULL;
2035
2036 if (argvars[1].v_type != VAR_LIST)
2037 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002038 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 return;
2040 }
2041 if (argvars[1].vval.v_list == NULL)
2042 return;
2043
2044 if (argvars[0].v_type == VAR_FUNC)
2045 func = argvars[0].vval.v_string;
2046 else if (argvars[0].v_type == VAR_PARTIAL)
2047 {
2048 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002049 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002050 }
2051 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002052 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002053 if (*func == NUL)
2054 return; /* type error or empty name */
2055
2056 if (argvars[2].v_type != VAR_UNKNOWN)
2057 {
2058 if (argvars[2].v_type != VAR_DICT)
2059 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002060 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 return;
2062 }
2063 selfdict = argvars[2].vval.v_dict;
2064 }
2065
2066 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2067}
2068
2069#ifdef FEAT_FLOAT
2070/*
2071 * "ceil({float})" function
2072 */
2073 static void
2074f_ceil(typval_T *argvars, typval_T *rettv)
2075{
2076 float_T f = 0.0;
2077
2078 rettv->v_type = VAR_FLOAT;
2079 if (get_float_arg(argvars, &f) == OK)
2080 rettv->vval.v_float = ceil(f);
2081 else
2082 rettv->vval.v_float = 0.0;
2083}
2084#endif
2085
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086/*
2087 * "changenr()" function
2088 */
2089 static void
2090f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2091{
2092 rettv->vval.v_number = curbuf->b_u_seq_cur;
2093}
2094
2095/*
2096 * "char2nr(string)" function
2097 */
2098 static void
2099f_char2nr(typval_T *argvars, typval_T *rettv)
2100{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002101 if (has_mbyte)
2102 {
2103 int utf8 = 0;
2104
2105 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002106 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002107
2108 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002109 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002111 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002112 }
2113 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002114 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002115}
2116
2117/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002118 * "chdir(dir)" function
2119 */
2120 static void
2121f_chdir(typval_T *argvars, typval_T *rettv)
2122{
2123 char_u *cwd;
2124 cdscope_T scope = CDSCOPE_GLOBAL;
2125
2126 rettv->v_type = VAR_STRING;
2127 rettv->vval.v_string = NULL;
2128
2129 if (argvars[0].v_type != VAR_STRING)
2130 return;
2131
2132 // Return the current directory
2133 cwd = alloc(MAXPATHL);
2134 if (cwd != NULL)
2135 {
2136 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2137 {
2138#ifdef BACKSLASH_IN_FILENAME
2139 slash_adjust(cwd);
2140#endif
2141 rettv->vval.v_string = vim_strsave(cwd);
2142 }
2143 vim_free(cwd);
2144 }
2145
2146 if (curwin->w_localdir != NULL)
2147 scope = CDSCOPE_WINDOW;
2148 else if (curtab->tp_localdir != NULL)
2149 scope = CDSCOPE_TABPAGE;
2150
2151 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2152 // Directory change failed
2153 VIM_CLEAR(rettv->vval.v_string);
2154}
2155
2156/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157 * "cindent(lnum)" function
2158 */
2159 static void
2160f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2161{
2162#ifdef FEAT_CINDENT
2163 pos_T pos;
2164 linenr_T lnum;
2165
2166 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002167 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002168 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2169 {
2170 curwin->w_cursor.lnum = lnum;
2171 rettv->vval.v_number = get_c_indent();
2172 curwin->w_cursor = pos;
2173 }
2174 else
2175#endif
2176 rettv->vval.v_number = -1;
2177}
2178
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002179 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002180get_optional_window(typval_T *argvars, int idx)
2181{
2182 win_T *win = curwin;
2183
2184 if (argvars[idx].v_type != VAR_UNKNOWN)
2185 {
2186 win = find_win_by_nr_or_id(&argvars[idx]);
2187 if (win == NULL)
2188 {
2189 emsg(_(e_invalwindow));
2190 return NULL;
2191 }
2192 }
2193 return win;
2194}
2195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002197 * "col(string)" function
2198 */
2199 static void
2200f_col(typval_T *argvars, typval_T *rettv)
2201{
2202 colnr_T col = 0;
2203 pos_T *fp;
2204 int fnum = curbuf->b_fnum;
2205
2206 fp = var2fpos(&argvars[0], FALSE, &fnum);
2207 if (fp != NULL && fnum == curbuf->b_fnum)
2208 {
2209 if (fp->col == MAXCOL)
2210 {
2211 /* '> can be MAXCOL, get the length of the line then */
2212 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2213 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2214 else
2215 col = MAXCOL;
2216 }
2217 else
2218 {
2219 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002220 /* col(".") when the cursor is on the NUL at the end of the line
2221 * because of "coladd" can be seen as an extra column. */
2222 if (virtual_active() && fp == &curwin->w_cursor)
2223 {
2224 char_u *p = ml_get_cursor();
2225
2226 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2227 curwin->w_virtcol - curwin->w_cursor.coladd))
2228 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002229 int l;
2230
2231 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2232 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002233 }
2234 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002235 }
2236 }
2237 rettv->vval.v_number = col;
2238}
2239
2240#if defined(FEAT_INS_EXPAND)
2241/*
2242 * "complete()" function
2243 */
2244 static void
2245f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2246{
2247 int startcol;
2248
2249 if ((State & INSERT) == 0)
2250 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002251 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002252 return;
2253 }
2254
2255 /* Check for undo allowed here, because if something was already inserted
2256 * the line was already saved for undo and this check isn't done. */
2257 if (!undo_allowed())
2258 return;
2259
2260 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2261 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002262 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263 return;
2264 }
2265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002266 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 if (startcol <= 0)
2268 return;
2269
2270 set_completion(startcol - 1, argvars[1].vval.v_list);
2271}
2272
2273/*
2274 * "complete_add()" function
2275 */
2276 static void
2277f_complete_add(typval_T *argvars, typval_T *rettv)
2278{
2279 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2280}
2281
2282/*
2283 * "complete_check()" function
2284 */
2285 static void
2286f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2287{
2288 int saved = RedrawingDisabled;
2289
2290 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002291 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002292 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 RedrawingDisabled = saved;
2294}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002295
2296/*
2297 * "complete_info()" function
2298 */
2299 static void
2300f_complete_info(typval_T *argvars, typval_T *rettv)
2301{
2302 list_T *what_list = NULL;
2303
2304 if (rettv_dict_alloc(rettv) != OK)
2305 return;
2306
2307 if (argvars[0].v_type != VAR_UNKNOWN)
2308 {
2309 if (argvars[0].v_type != VAR_LIST)
2310 {
2311 emsg(_(e_listreq));
2312 return;
2313 }
2314 what_list = argvars[0].vval.v_list;
2315 }
2316 get_complete_info(what_list, rettv->vval.v_dict);
2317}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002318#endif
2319
2320/*
2321 * "confirm(message, buttons[, default [, type]])" function
2322 */
2323 static void
2324f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2325{
2326#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2327 char_u *message;
2328 char_u *buttons = NULL;
2329 char_u buf[NUMBUFLEN];
2330 char_u buf2[NUMBUFLEN];
2331 int def = 1;
2332 int type = VIM_GENERIC;
2333 char_u *typestr;
2334 int error = FALSE;
2335
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002336 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002337 if (message == NULL)
2338 error = TRUE;
2339 if (argvars[1].v_type != VAR_UNKNOWN)
2340 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002341 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002342 if (buttons == NULL)
2343 error = TRUE;
2344 if (argvars[2].v_type != VAR_UNKNOWN)
2345 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002346 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 if (argvars[3].v_type != VAR_UNKNOWN)
2348 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002349 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002350 if (typestr == NULL)
2351 error = TRUE;
2352 else
2353 {
2354 switch (TOUPPER_ASC(*typestr))
2355 {
2356 case 'E': type = VIM_ERROR; break;
2357 case 'Q': type = VIM_QUESTION; break;
2358 case 'I': type = VIM_INFO; break;
2359 case 'W': type = VIM_WARNING; break;
2360 case 'G': type = VIM_GENERIC; break;
2361 }
2362 }
2363 }
2364 }
2365 }
2366
2367 if (buttons == NULL || *buttons == NUL)
2368 buttons = (char_u *)_("&Ok");
2369
2370 if (!error)
2371 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2372 def, NULL, FALSE);
2373#endif
2374}
2375
2376/*
2377 * "copy()" function
2378 */
2379 static void
2380f_copy(typval_T *argvars, typval_T *rettv)
2381{
2382 item_copy(&argvars[0], rettv, FALSE, 0);
2383}
2384
2385#ifdef FEAT_FLOAT
2386/*
2387 * "cos()" function
2388 */
2389 static void
2390f_cos(typval_T *argvars, typval_T *rettv)
2391{
2392 float_T f = 0.0;
2393
2394 rettv->v_type = VAR_FLOAT;
2395 if (get_float_arg(argvars, &f) == OK)
2396 rettv->vval.v_float = cos(f);
2397 else
2398 rettv->vval.v_float = 0.0;
2399}
2400
2401/*
2402 * "cosh()" function
2403 */
2404 static void
2405f_cosh(typval_T *argvars, typval_T *rettv)
2406{
2407 float_T f = 0.0;
2408
2409 rettv->v_type = VAR_FLOAT;
2410 if (get_float_arg(argvars, &f) == OK)
2411 rettv->vval.v_float = cosh(f);
2412 else
2413 rettv->vval.v_float = 0.0;
2414}
2415#endif
2416
2417/*
2418 * "count()" function
2419 */
2420 static void
2421f_count(typval_T *argvars, typval_T *rettv)
2422{
2423 long n = 0;
2424 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002425 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002426
Bram Moolenaar9966b212017-07-28 16:46:57 +02002427 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002428 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002429
2430 if (argvars[0].v_type == VAR_STRING)
2431 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002432 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002433 char_u *p = argvars[0].vval.v_string;
2434 char_u *next;
2435
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002436 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002437 {
2438 if (ic)
2439 {
2440 size_t len = STRLEN(expr);
2441
2442 while (*p != NUL)
2443 {
2444 if (MB_STRNICMP(p, expr, len) == 0)
2445 {
2446 ++n;
2447 p += len;
2448 }
2449 else
2450 MB_PTR_ADV(p);
2451 }
2452 }
2453 else
2454 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2455 != NULL)
2456 {
2457 ++n;
2458 p = next + STRLEN(expr);
2459 }
2460 }
2461
2462 }
2463 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 {
2465 listitem_T *li;
2466 list_T *l;
2467 long idx;
2468
2469 if ((l = argvars[0].vval.v_list) != NULL)
2470 {
2471 li = l->lv_first;
2472 if (argvars[2].v_type != VAR_UNKNOWN)
2473 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474 if (argvars[3].v_type != VAR_UNKNOWN)
2475 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002476 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002477 if (!error)
2478 {
2479 li = list_find(l, idx);
2480 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002481 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002482 }
2483 }
2484 if (error)
2485 li = NULL;
2486 }
2487
2488 for ( ; li != NULL; li = li->li_next)
2489 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2490 ++n;
2491 }
2492 }
2493 else if (argvars[0].v_type == VAR_DICT)
2494 {
2495 int todo;
2496 dict_T *d;
2497 hashitem_T *hi;
2498
2499 if ((d = argvars[0].vval.v_dict) != NULL)
2500 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 if (argvars[2].v_type != VAR_UNKNOWN)
2502 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002503 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002504 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002505 }
2506
2507 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2508 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2509 {
2510 if (!HASHITEM_EMPTY(hi))
2511 {
2512 --todo;
2513 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2514 ++n;
2515 }
2516 }
2517 }
2518 }
2519 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002520 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521 rettv->vval.v_number = n;
2522}
2523
2524/*
2525 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2526 *
2527 * Checks the existence of a cscope connection.
2528 */
2529 static void
2530f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2531{
2532#ifdef FEAT_CSCOPE
2533 int num = 0;
2534 char_u *dbpath = NULL;
2535 char_u *prepend = NULL;
2536 char_u buf[NUMBUFLEN];
2537
2538 if (argvars[0].v_type != VAR_UNKNOWN
2539 && argvars[1].v_type != VAR_UNKNOWN)
2540 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002541 num = (int)tv_get_number(&argvars[0]);
2542 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002544 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002545 }
2546
2547 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2548#endif
2549}
2550
2551/*
2552 * "cursor(lnum, col)" function, or
2553 * "cursor(list)"
2554 *
2555 * Moves the cursor to the specified line and column.
2556 * Returns 0 when the position could be set, -1 otherwise.
2557 */
2558 static void
2559f_cursor(typval_T *argvars, typval_T *rettv)
2560{
2561 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002562 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563 int set_curswant = TRUE;
2564
2565 rettv->vval.v_number = -1;
2566 if (argvars[1].v_type == VAR_UNKNOWN)
2567 {
2568 pos_T pos;
2569 colnr_T curswant = -1;
2570
2571 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2572 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002573 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 return;
2575 }
2576 line = pos.lnum;
2577 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002578 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002579 if (curswant >= 0)
2580 {
2581 curwin->w_curswant = curswant - 1;
2582 set_curswant = FALSE;
2583 }
2584 }
2585 else
2586 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002587 line = tv_get_lnum(argvars);
2588 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002589 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002590 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002592 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 return; /* type error; errmsg already given */
2594 if (line > 0)
2595 curwin->w_cursor.lnum = line;
2596 if (col > 0)
2597 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002598 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002599
2600 /* Make sure the cursor is in a valid position. */
2601 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 /* Correct cursor for multi-byte character. */
2603 if (has_mbyte)
2604 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002605
2606 curwin->w_set_curswant = set_curswant;
2607 rettv->vval.v_number = 0;
2608}
2609
Bram Moolenaar4f974752019-02-17 17:44:42 +01002610#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002611/*
2612 * "debugbreak()" function
2613 */
2614 static void
2615f_debugbreak(typval_T *argvars, typval_T *rettv)
2616{
2617 int pid;
2618
2619 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002620 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002621 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002622 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002623 else
2624 {
2625 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2626
2627 if (hProcess != NULL)
2628 {
2629 DebugBreakProcess(hProcess);
2630 CloseHandle(hProcess);
2631 rettv->vval.v_number = OK;
2632 }
2633 }
2634}
2635#endif
2636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637/*
2638 * "deepcopy()" function
2639 */
2640 static void
2641f_deepcopy(typval_T *argvars, typval_T *rettv)
2642{
2643 int noref = 0;
2644 int copyID;
2645
2646 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002647 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002648 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002649 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002650 else
2651 {
2652 copyID = get_copyID();
2653 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2654 }
2655}
2656
2657/*
2658 * "delete()" function
2659 */
2660 static void
2661f_delete(typval_T *argvars, typval_T *rettv)
2662{
2663 char_u nbuf[NUMBUFLEN];
2664 char_u *name;
2665 char_u *flags;
2666
2667 rettv->vval.v_number = -1;
2668 if (check_restricted() || check_secure())
2669 return;
2670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002671 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 if (name == NULL || *name == NUL)
2673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002674 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 return;
2676 }
2677
2678 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002679 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 else
2681 flags = (char_u *)"";
2682
2683 if (*flags == NUL)
2684 /* delete a file */
2685 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2686 else if (STRCMP(flags, "d") == 0)
2687 /* delete an empty directory */
2688 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2689 else if (STRCMP(flags, "rf") == 0)
2690 /* delete a directory recursively */
2691 rettv->vval.v_number = delete_recursive(name);
2692 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002693 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694}
2695
2696/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002697 * "deletebufline()" function
2698 */
2699 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002700f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002701{
2702 buf_T *buf;
2703 linenr_T first, last;
2704 linenr_T lnum;
2705 long count;
2706 int is_curbuf;
2707 buf_T *curbuf_save = NULL;
2708 win_T *curwin_save = NULL;
2709 tabpage_T *tp;
2710 win_T *wp;
2711
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002712 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002713 if (buf == NULL)
2714 {
2715 rettv->vval.v_number = 1; /* FAIL */
2716 return;
2717 }
2718 is_curbuf = buf == curbuf;
2719
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002720 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002721 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002722 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002723 else
2724 last = first;
2725
2726 if (buf->b_ml.ml_mfp == NULL || first < 1
2727 || first > buf->b_ml.ml_line_count || last < first)
2728 {
2729 rettv->vval.v_number = 1; /* FAIL */
2730 return;
2731 }
2732
2733 if (!is_curbuf)
2734 {
2735 curbuf_save = curbuf;
2736 curwin_save = curwin;
2737 curbuf = buf;
2738 find_win_for_curbuf();
2739 }
2740 if (last > curbuf->b_ml.ml_line_count)
2741 last = curbuf->b_ml.ml_line_count;
2742 count = last - first + 1;
2743
2744 // When coming here from Insert mode, sync undo, so that this can be
2745 // undone separately from what was previously inserted.
2746 if (u_sync_once == 2)
2747 {
2748 u_sync_once = 1; // notify that u_sync() was called
2749 u_sync(TRUE);
2750 }
2751
2752 if (u_save(first - 1, last + 1) == FAIL)
2753 {
2754 rettv->vval.v_number = 1; /* FAIL */
2755 return;
2756 }
2757
2758 for (lnum = first; lnum <= last; ++lnum)
2759 ml_delete(first, TRUE);
2760
2761 FOR_ALL_TAB_WINDOWS(tp, wp)
2762 if (wp->w_buffer == buf)
2763 {
2764 if (wp->w_cursor.lnum > last)
2765 wp->w_cursor.lnum -= count;
2766 else if (wp->w_cursor.lnum> first)
2767 wp->w_cursor.lnum = first;
2768 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2769 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2770 }
2771 check_cursor_col();
2772 deleted_lines_mark(first, count);
2773
2774 if (!is_curbuf)
2775 {
2776 curbuf = curbuf_save;
2777 curwin = curwin_save;
2778 }
2779}
2780
2781/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002782 * "did_filetype()" function
2783 */
2784 static void
2785f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2786{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788}
2789
2790/*
2791 * "diff_filler()" function
2792 */
2793 static void
2794f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2795{
2796#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002797 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002798#endif
2799}
2800
2801/*
2802 * "diff_hlID()" function
2803 */
2804 static void
2805f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2806{
2807#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002808 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002809 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002810 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002811 static int fnum = 0;
2812 static int change_start = 0;
2813 static int change_end = 0;
2814 static hlf_T hlID = (hlf_T)0;
2815 int filler_lines;
2816 int col;
2817
2818 if (lnum < 0) /* ignore type error in {lnum} arg */
2819 lnum = 0;
2820 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002821 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002822 || fnum != curbuf->b_fnum)
2823 {
2824 /* New line, buffer, change: need to get the values. */
2825 filler_lines = diff_check(curwin, lnum);
2826 if (filler_lines < 0)
2827 {
2828 if (filler_lines == -1)
2829 {
2830 change_start = MAXCOL;
2831 change_end = -1;
2832 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2833 hlID = HLF_ADD; /* added line */
2834 else
2835 hlID = HLF_CHD; /* changed line */
2836 }
2837 else
2838 hlID = HLF_ADD; /* added line */
2839 }
2840 else
2841 hlID = (hlf_T)0;
2842 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002843 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002844 fnum = curbuf->b_fnum;
2845 }
2846
2847 if (hlID == HLF_CHD || hlID == HLF_TXD)
2848 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002849 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002850 if (col >= change_start && col <= change_end)
2851 hlID = HLF_TXD; /* changed text */
2852 else
2853 hlID = HLF_CHD; /* changed line */
2854 }
2855 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2856#endif
2857}
2858
2859/*
2860 * "empty({expr})" function
2861 */
2862 static void
2863f_empty(typval_T *argvars, typval_T *rettv)
2864{
2865 int n = FALSE;
2866
2867 switch (argvars[0].v_type)
2868 {
2869 case VAR_STRING:
2870 case VAR_FUNC:
2871 n = argvars[0].vval.v_string == NULL
2872 || *argvars[0].vval.v_string == NUL;
2873 break;
2874 case VAR_PARTIAL:
2875 n = FALSE;
2876 break;
2877 case VAR_NUMBER:
2878 n = argvars[0].vval.v_number == 0;
2879 break;
2880 case VAR_FLOAT:
2881#ifdef FEAT_FLOAT
2882 n = argvars[0].vval.v_float == 0.0;
2883 break;
2884#endif
2885 case VAR_LIST:
2886 n = argvars[0].vval.v_list == NULL
2887 || argvars[0].vval.v_list->lv_first == NULL;
2888 break;
2889 case VAR_DICT:
2890 n = argvars[0].vval.v_dict == NULL
2891 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2892 break;
2893 case VAR_SPECIAL:
2894 n = argvars[0].vval.v_number != VVAL_TRUE;
2895 break;
2896
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002897 case VAR_BLOB:
2898 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002899 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2900 break;
2901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002902 case VAR_JOB:
2903#ifdef FEAT_JOB_CHANNEL
2904 n = argvars[0].vval.v_job == NULL
2905 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2906 break;
2907#endif
2908 case VAR_CHANNEL:
2909#ifdef FEAT_JOB_CHANNEL
2910 n = argvars[0].vval.v_channel == NULL
2911 || !channel_is_open(argvars[0].vval.v_channel);
2912 break;
2913#endif
2914 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002915 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002916 n = TRUE;
2917 break;
2918 }
2919
2920 rettv->vval.v_number = n;
2921}
2922
2923/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002924 * "environ()" function
2925 */
2926 static void
2927f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2928{
2929#if !defined(AMIGA)
2930 int i = 0;
2931 char_u *entry, *value;
2932# ifdef MSWIN
2933 extern wchar_t **_wenviron;
2934# else
2935 extern char **environ;
2936# endif
2937
2938 if (rettv_dict_alloc(rettv) != OK)
2939 return;
2940
2941# ifdef MSWIN
2942 if (*_wenviron == NULL)
2943 return;
2944# else
2945 if (*environ == NULL)
2946 return;
2947# endif
2948
2949 for (i = 0; ; ++i)
2950 {
2951# ifdef MSWIN
2952 short_u *p;
2953
2954 if ((p = (short_u *)_wenviron[i]) == NULL)
2955 return;
2956 entry = utf16_to_enc(p, NULL);
2957# else
2958 if ((entry = (char_u *)environ[i]) == NULL)
2959 return;
2960 entry = vim_strsave(entry);
2961# endif
2962 if (entry == NULL) // out of memory
2963 return;
2964 if ((value = vim_strchr(entry, '=')) == NULL)
2965 {
2966 vim_free(entry);
2967 continue;
2968 }
2969 *value++ = NUL;
2970 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2971 vim_free(entry);
2972 }
2973#endif
2974}
2975
2976/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002977 * "escape({string}, {chars})" function
2978 */
2979 static void
2980f_escape(typval_T *argvars, typval_T *rettv)
2981{
2982 char_u buf[NUMBUFLEN];
2983
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002984 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2985 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002986 rettv->v_type = VAR_STRING;
2987}
2988
2989/*
2990 * "eval()" function
2991 */
2992 static void
2993f_eval(typval_T *argvars, typval_T *rettv)
2994{
2995 char_u *s, *p;
2996
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002997 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002998 if (s != NULL)
2999 s = skipwhite(s);
3000
3001 p = s;
3002 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3003 {
3004 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003005 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006 need_clr_eos = FALSE;
3007 rettv->v_type = VAR_NUMBER;
3008 rettv->vval.v_number = 0;
3009 }
3010 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003011 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003012}
3013
3014/*
3015 * "eventhandler()" function
3016 */
3017 static void
3018f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3019{
3020 rettv->vval.v_number = vgetc_busy;
3021}
3022
3023/*
3024 * "executable()" function
3025 */
3026 static void
3027f_executable(typval_T *argvars, typval_T *rettv)
3028{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003029 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003030
3031 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003032 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003033}
3034
3035static garray_T redir_execute_ga;
3036
3037/*
3038 * Append "value[value_len]" to the execute() output.
3039 */
3040 void
3041execute_redir_str(char_u *value, int value_len)
3042{
3043 int len;
3044
3045 if (value_len == -1)
3046 len = (int)STRLEN(value); /* Append the entire string */
3047 else
3048 len = value_len; /* Append only "value_len" characters */
3049 if (ga_grow(&redir_execute_ga, len) == OK)
3050 {
3051 mch_memmove((char *)redir_execute_ga.ga_data
3052 + redir_execute_ga.ga_len, value, len);
3053 redir_execute_ga.ga_len += len;
3054 }
3055}
3056
3057/*
3058 * Get next line from a list.
3059 * Called by do_cmdline() to get the next line.
3060 * Returns allocated string, or NULL for end of function.
3061 */
3062
3063 static char_u *
3064get_list_line(
3065 int c UNUSED,
3066 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003067 int indent UNUSED,
3068 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003069{
3070 listitem_T **p = (listitem_T **)cookie;
3071 listitem_T *item = *p;
3072 char_u buf[NUMBUFLEN];
3073 char_u *s;
3074
3075 if (item == NULL)
3076 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003077 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003078 *p = item->li_next;
3079 return s == NULL ? NULL : vim_strsave(s);
3080}
3081
3082/*
3083 * "execute()" function
3084 */
3085 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003086execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003087{
3088 char_u *cmd = NULL;
3089 list_T *list = NULL;
3090 int save_msg_silent = msg_silent;
3091 int save_emsg_silent = emsg_silent;
3092 int save_emsg_noredir = emsg_noredir;
3093 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003094 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003095 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003096 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003097 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098
3099 rettv->vval.v_string = NULL;
3100 rettv->v_type = VAR_STRING;
3101
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003102 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003103 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003104 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003105 if (list == NULL || list->lv_first == NULL)
3106 /* empty list, no commands, empty output */
3107 return;
3108 ++list->lv_refcount;
3109 }
3110 else
3111 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003112 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003113 if (cmd == NULL)
3114 return;
3115 }
3116
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003117 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003118 {
3119 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003120 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003121
3122 if (s == NULL)
3123 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003124 if (*s == NUL)
3125 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003126 if (STRNCMP(s, "silent", 6) == 0)
3127 ++msg_silent;
3128 if (STRCMP(s, "silent!") == 0)
3129 {
3130 emsg_silent = TRUE;
3131 emsg_noredir = TRUE;
3132 }
3133 }
3134 else
3135 ++msg_silent;
3136
3137 if (redir_execute)
3138 save_ga = redir_execute_ga;
3139 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3140 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003141 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003142 if (!echo_output)
3143 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003144
3145 if (cmd != NULL)
3146 do_cmdline_cmd(cmd);
3147 else
3148 {
3149 listitem_T *item = list->lv_first;
3150
3151 do_cmdline(NULL, get_list_line, (void *)&item,
3152 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3153 --list->lv_refcount;
3154 }
3155
Bram Moolenaard297f352017-01-29 20:31:21 +01003156 /* Need to append a NUL to the result. */
3157 if (ga_grow(&redir_execute_ga, 1) == OK)
3158 {
3159 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3160 rettv->vval.v_string = redir_execute_ga.ga_data;
3161 }
3162 else
3163 {
3164 ga_clear(&redir_execute_ga);
3165 rettv->vval.v_string = NULL;
3166 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003167 msg_silent = save_msg_silent;
3168 emsg_silent = save_emsg_silent;
3169 emsg_noredir = save_emsg_noredir;
3170
3171 redir_execute = save_redir_execute;
3172 if (redir_execute)
3173 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003174 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003175
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003176 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003177 if (echo_output)
3178 // When not working silently: put it in column zero. A following
3179 // "echon" will overwrite the message, unavoidably.
3180 msg_col = 0;
3181 else
3182 // When working silently: Put it back where it was, since nothing
3183 // should have been written.
3184 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003185}
3186
3187/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003188 * "execute()" function
3189 */
3190 static void
3191f_execute(typval_T *argvars, typval_T *rettv)
3192{
3193 execute_common(argvars, rettv, 0);
3194}
3195
3196/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003197 * "exepath()" function
3198 */
3199 static void
3200f_exepath(typval_T *argvars, typval_T *rettv)
3201{
3202 char_u *p = NULL;
3203
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003204 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003205 rettv->v_type = VAR_STRING;
3206 rettv->vval.v_string = p;
3207}
3208
3209/*
3210 * "exists()" function
3211 */
3212 static void
3213f_exists(typval_T *argvars, typval_T *rettv)
3214{
3215 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003217
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003218 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003219 if (*p == '$') /* environment variable */
3220 {
3221 /* first try "normal" environment variables (fast) */
3222 if (mch_getenv(p + 1) != NULL)
3223 n = TRUE;
3224 else
3225 {
3226 /* try expanding things like $VIM and ${HOME} */
3227 p = expand_env_save(p);
3228 if (p != NULL && *p != '$')
3229 n = TRUE;
3230 vim_free(p);
3231 }
3232 }
3233 else if (*p == '&' || *p == '+') /* option */
3234 {
3235 n = (get_option_tv(&p, NULL, TRUE) == OK);
3236 if (*skipwhite(p) != NUL)
3237 n = FALSE; /* trailing garbage */
3238 }
3239 else if (*p == '*') /* internal or user defined function */
3240 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003241 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003242 }
3243 else if (*p == ':')
3244 {
3245 n = cmd_exists(p + 1);
3246 }
3247 else if (*p == '#')
3248 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003249 if (p[1] == '#')
3250 n = autocmd_supported(p + 2);
3251 else
3252 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003253 }
3254 else /* internal variable */
3255 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003256 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257 }
3258
3259 rettv->vval.v_number = n;
3260}
3261
3262#ifdef FEAT_FLOAT
3263/*
3264 * "exp()" function
3265 */
3266 static void
3267f_exp(typval_T *argvars, typval_T *rettv)
3268{
3269 float_T f = 0.0;
3270
3271 rettv->v_type = VAR_FLOAT;
3272 if (get_float_arg(argvars, &f) == OK)
3273 rettv->vval.v_float = exp(f);
3274 else
3275 rettv->vval.v_float = 0.0;
3276}
3277#endif
3278
3279/*
3280 * "expand()" function
3281 */
3282 static void
3283f_expand(typval_T *argvars, typval_T *rettv)
3284{
3285 char_u *s;
3286 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003287 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003288 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3289 expand_T xpc;
3290 int error = FALSE;
3291 char_u *result;
3292
3293 rettv->v_type = VAR_STRING;
3294 if (argvars[1].v_type != VAR_UNKNOWN
3295 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003296 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003298 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003300 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 if (*s == '%' || *s == '#' || *s == '<')
3302 {
3303 ++emsg_off;
3304 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3305 --emsg_off;
3306 if (rettv->v_type == VAR_LIST)
3307 {
3308 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3309 list_append_string(rettv->vval.v_list, result, -1);
3310 else
3311 vim_free(result);
3312 }
3313 else
3314 rettv->vval.v_string = result;
3315 }
3316 else
3317 {
3318 /* When the optional second argument is non-zero, don't remove matches
3319 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3320 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003321 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003322 options |= WILD_KEEP_ALL;
3323 if (!error)
3324 {
3325 ExpandInit(&xpc);
3326 xpc.xp_context = EXPAND_FILES;
3327 if (p_wic)
3328 options += WILD_ICASE;
3329 if (rettv->v_type == VAR_STRING)
3330 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3331 options, WILD_ALL);
3332 else if (rettv_list_alloc(rettv) != FAIL)
3333 {
3334 int i;
3335
3336 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3337 for (i = 0; i < xpc.xp_numfiles; i++)
3338 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3339 ExpandCleanup(&xpc);
3340 }
3341 }
3342 else
3343 rettv->vval.v_string = NULL;
3344 }
3345}
3346
3347/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003348 * "expandcmd()" function
3349 * Expand all the special characters in a command string.
3350 */
3351 static void
3352f_expandcmd(typval_T *argvars, typval_T *rettv)
3353{
3354 exarg_T eap;
3355 char_u *cmdstr;
3356 char *errormsg = NULL;
3357
3358 rettv->v_type = VAR_STRING;
3359 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3360
3361 memset(&eap, 0, sizeof(eap));
3362 eap.cmd = cmdstr;
3363 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003364 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003365 eap.usefilter = FALSE;
3366 eap.nextcmd = NULL;
3367 eap.cmdidx = CMD_USER;
3368
3369 expand_filename(&eap, &cmdstr, &errormsg);
3370 if (errormsg != NULL && *errormsg != NUL)
3371 emsg(errormsg);
3372
3373 rettv->vval.v_string = cmdstr;
3374}
3375
3376/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 * "extend(list, list [, idx])" function
3378 * "extend(dict, dict [, action])" function
3379 */
3380 static void
3381f_extend(typval_T *argvars, typval_T *rettv)
3382{
3383 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3384
3385 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3386 {
3387 list_T *l1, *l2;
3388 listitem_T *item;
3389 long before;
3390 int error = FALSE;
3391
3392 l1 = argvars[0].vval.v_list;
3393 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003394 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 && l2 != NULL)
3396 {
3397 if (argvars[2].v_type != VAR_UNKNOWN)
3398 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003399 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 if (error)
3401 return; /* type error; errmsg already given */
3402
3403 if (before == l1->lv_len)
3404 item = NULL;
3405 else
3406 {
3407 item = list_find(l1, before);
3408 if (item == NULL)
3409 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003410 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003411 return;
3412 }
3413 }
3414 }
3415 else
3416 item = NULL;
3417 list_extend(l1, l2, item);
3418
3419 copy_tv(&argvars[0], rettv);
3420 }
3421 }
3422 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3423 {
3424 dict_T *d1, *d2;
3425 char_u *action;
3426 int i;
3427
3428 d1 = argvars[0].vval.v_dict;
3429 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003430 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003431 && d2 != NULL)
3432 {
3433 /* Check the third argument. */
3434 if (argvars[2].v_type != VAR_UNKNOWN)
3435 {
3436 static char *(av[]) = {"keep", "force", "error"};
3437
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003438 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439 if (action == NULL)
3440 return; /* type error; errmsg already given */
3441 for (i = 0; i < 3; ++i)
3442 if (STRCMP(action, av[i]) == 0)
3443 break;
3444 if (i == 3)
3445 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003446 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003447 return;
3448 }
3449 }
3450 else
3451 action = (char_u *)"force";
3452
3453 dict_extend(d1, d2, action);
3454
3455 copy_tv(&argvars[0], rettv);
3456 }
3457 }
3458 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003459 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003460}
3461
3462/*
3463 * "feedkeys()" function
3464 */
3465 static void
3466f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3467{
3468 int remap = TRUE;
3469 int insert = FALSE;
3470 char_u *keys, *flags;
3471 char_u nbuf[NUMBUFLEN];
3472 int typed = FALSE;
3473 int execute = FALSE;
3474 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003475 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003476 char_u *keys_esc;
3477
3478 /* This is not allowed in the sandbox. If the commands would still be
3479 * executed in the sandbox it would be OK, but it probably happens later,
3480 * when "sandbox" is no longer set. */
3481 if (check_secure())
3482 return;
3483
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003484 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485
3486 if (argvars[1].v_type != VAR_UNKNOWN)
3487 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003488 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489 for ( ; *flags != NUL; ++flags)
3490 {
3491 switch (*flags)
3492 {
3493 case 'n': remap = FALSE; break;
3494 case 'm': remap = TRUE; break;
3495 case 't': typed = TRUE; break;
3496 case 'i': insert = TRUE; break;
3497 case 'x': execute = TRUE; break;
3498 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003499 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500 }
3501 }
3502 }
3503
3504 if (*keys != NUL || execute)
3505 {
3506 /* Need to escape K_SPECIAL and CSI before putting the string in the
3507 * typeahead buffer. */
3508 keys_esc = vim_strsave_escape_csi(keys);
3509 if (keys_esc != NULL)
3510 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003511 if (lowlevel)
3512 {
3513#ifdef USE_INPUT_BUF
3514 add_to_input_buf(keys, (int)STRLEN(keys));
3515#else
3516 emsg(_("E980: lowlevel input not supported"));
3517#endif
3518 }
3519 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003520 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003521 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003523 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003524#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003525 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003526#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003527 )
3528 typebuf_was_filled = TRUE;
3529 }
3530 vim_free(keys_esc);
3531
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003532 if (execute)
3533 {
3534 int save_msg_scroll = msg_scroll;
3535
3536 /* Avoid a 1 second delay when the keys start Insert mode. */
3537 msg_scroll = FALSE;
3538
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003539 if (!dangerous)
3540 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003541 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003542 if (!dangerous)
3543 --ex_normal_busy;
3544
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003545 msg_scroll |= save_msg_scroll;
3546 }
3547 }
3548 }
3549}
3550
3551/*
3552 * "filereadable()" function
3553 */
3554 static void
3555f_filereadable(typval_T *argvars, typval_T *rettv)
3556{
3557 int fd;
3558 char_u *p;
3559 int n;
3560
3561#ifndef O_NONBLOCK
3562# define O_NONBLOCK 0
3563#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003564 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3566 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3567 {
3568 n = TRUE;
3569 close(fd);
3570 }
3571 else
3572 n = FALSE;
3573
3574 rettv->vval.v_number = n;
3575}
3576
3577/*
3578 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3579 * rights to write into.
3580 */
3581 static void
3582f_filewritable(typval_T *argvars, typval_T *rettv)
3583{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003584 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003585}
3586
3587 static void
3588findfilendir(
3589 typval_T *argvars UNUSED,
3590 typval_T *rettv,
3591 int find_what UNUSED)
3592{
3593#ifdef FEAT_SEARCHPATH
3594 char_u *fname;
3595 char_u *fresult = NULL;
3596 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3597 char_u *p;
3598 char_u pathbuf[NUMBUFLEN];
3599 int count = 1;
3600 int first = TRUE;
3601 int error = FALSE;
3602#endif
3603
3604 rettv->vval.v_string = NULL;
3605 rettv->v_type = VAR_STRING;
3606
3607#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003608 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003609
3610 if (argvars[1].v_type != VAR_UNKNOWN)
3611 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003612 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003613 if (p == NULL)
3614 error = TRUE;
3615 else
3616 {
3617 if (*p != NUL)
3618 path = p;
3619
3620 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003621 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622 }
3623 }
3624
3625 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3626 error = TRUE;
3627
3628 if (*fname != NUL && !error)
3629 {
3630 do
3631 {
3632 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3633 vim_free(fresult);
3634 fresult = find_file_in_path_option(first ? fname : NULL,
3635 first ? (int)STRLEN(fname) : 0,
3636 0, first, path,
3637 find_what,
3638 curbuf->b_ffname,
3639 find_what == FINDFILE_DIR
3640 ? (char_u *)"" : curbuf->b_p_sua);
3641 first = FALSE;
3642
3643 if (fresult != NULL && rettv->v_type == VAR_LIST)
3644 list_append_string(rettv->vval.v_list, fresult, -1);
3645
3646 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3647 }
3648
3649 if (rettv->v_type == VAR_STRING)
3650 rettv->vval.v_string = fresult;
3651#endif
3652}
3653
3654/*
3655 * "filter()" function
3656 */
3657 static void
3658f_filter(typval_T *argvars, typval_T *rettv)
3659{
3660 filter_map(argvars, rettv, FALSE);
3661}
3662
3663/*
3664 * "finddir({fname}[, {path}[, {count}]])" function
3665 */
3666 static void
3667f_finddir(typval_T *argvars, typval_T *rettv)
3668{
3669 findfilendir(argvars, rettv, FINDFILE_DIR);
3670}
3671
3672/*
3673 * "findfile({fname}[, {path}[, {count}]])" function
3674 */
3675 static void
3676f_findfile(typval_T *argvars, typval_T *rettv)
3677{
3678 findfilendir(argvars, rettv, FINDFILE_FILE);
3679}
3680
3681#ifdef FEAT_FLOAT
3682/*
3683 * "float2nr({float})" function
3684 */
3685 static void
3686f_float2nr(typval_T *argvars, typval_T *rettv)
3687{
3688 float_T f = 0.0;
3689
3690 if (get_float_arg(argvars, &f) == OK)
3691 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003692 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003693 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003694 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003695 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003696 else
3697 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698 }
3699}
3700
3701/*
3702 * "floor({float})" function
3703 */
3704 static void
3705f_floor(typval_T *argvars, typval_T *rettv)
3706{
3707 float_T f = 0.0;
3708
3709 rettv->v_type = VAR_FLOAT;
3710 if (get_float_arg(argvars, &f) == OK)
3711 rettv->vval.v_float = floor(f);
3712 else
3713 rettv->vval.v_float = 0.0;
3714}
3715
3716/*
3717 * "fmod()" function
3718 */
3719 static void
3720f_fmod(typval_T *argvars, typval_T *rettv)
3721{
3722 float_T fx = 0.0, fy = 0.0;
3723
3724 rettv->v_type = VAR_FLOAT;
3725 if (get_float_arg(argvars, &fx) == OK
3726 && get_float_arg(&argvars[1], &fy) == OK)
3727 rettv->vval.v_float = fmod(fx, fy);
3728 else
3729 rettv->vval.v_float = 0.0;
3730}
3731#endif
3732
3733/*
3734 * "fnameescape({string})" function
3735 */
3736 static void
3737f_fnameescape(typval_T *argvars, typval_T *rettv)
3738{
3739 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003740 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003741 rettv->v_type = VAR_STRING;
3742}
3743
3744/*
3745 * "fnamemodify({fname}, {mods})" function
3746 */
3747 static void
3748f_fnamemodify(typval_T *argvars, typval_T *rettv)
3749{
3750 char_u *fname;
3751 char_u *mods;
3752 int usedlen = 0;
3753 int len;
3754 char_u *fbuf = NULL;
3755 char_u buf[NUMBUFLEN];
3756
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003757 fname = tv_get_string_chk(&argvars[0]);
3758 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003759 if (fname == NULL || mods == NULL)
3760 fname = NULL;
3761 else
3762 {
3763 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003764 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003765 }
3766
3767 rettv->v_type = VAR_STRING;
3768 if (fname == NULL)
3769 rettv->vval.v_string = NULL;
3770 else
3771 rettv->vval.v_string = vim_strnsave(fname, len);
3772 vim_free(fbuf);
3773}
3774
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775/*
3776 * "foldclosed()" function
3777 */
3778 static void
3779foldclosed_both(
3780 typval_T *argvars UNUSED,
3781 typval_T *rettv,
3782 int end UNUSED)
3783{
3784#ifdef FEAT_FOLDING
3785 linenr_T lnum;
3786 linenr_T first, last;
3787
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003788 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003789 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3790 {
3791 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3792 {
3793 if (end)
3794 rettv->vval.v_number = (varnumber_T)last;
3795 else
3796 rettv->vval.v_number = (varnumber_T)first;
3797 return;
3798 }
3799 }
3800#endif
3801 rettv->vval.v_number = -1;
3802}
3803
3804/*
3805 * "foldclosed()" function
3806 */
3807 static void
3808f_foldclosed(typval_T *argvars, typval_T *rettv)
3809{
3810 foldclosed_both(argvars, rettv, FALSE);
3811}
3812
3813/*
3814 * "foldclosedend()" function
3815 */
3816 static void
3817f_foldclosedend(typval_T *argvars, typval_T *rettv)
3818{
3819 foldclosed_both(argvars, rettv, TRUE);
3820}
3821
3822/*
3823 * "foldlevel()" function
3824 */
3825 static void
3826f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3827{
3828#ifdef FEAT_FOLDING
3829 linenr_T lnum;
3830
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003831 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003832 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3833 rettv->vval.v_number = foldLevel(lnum);
3834#endif
3835}
3836
3837/*
3838 * "foldtext()" function
3839 */
3840 static void
3841f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3842{
3843#ifdef FEAT_FOLDING
3844 linenr_T foldstart;
3845 linenr_T foldend;
3846 char_u *dashes;
3847 linenr_T lnum;
3848 char_u *s;
3849 char_u *r;
3850 int len;
3851 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003852 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003853#endif
3854
3855 rettv->v_type = VAR_STRING;
3856 rettv->vval.v_string = NULL;
3857#ifdef FEAT_FOLDING
3858 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3859 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3860 dashes = get_vim_var_str(VV_FOLDDASHES);
3861 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3862 && dashes != NULL)
3863 {
3864 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003865 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866 if (!linewhite(lnum))
3867 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003868
3869 /* Find interesting text in this line. */
3870 s = skipwhite(ml_get(lnum));
3871 /* skip C comment-start */
3872 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3873 {
3874 s = skipwhite(s + 2);
3875 if (*skipwhite(s) == NUL
3876 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3877 {
3878 s = skipwhite(ml_get(lnum + 1));
3879 if (*s == '*')
3880 s = skipwhite(s + 1);
3881 }
3882 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003883 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003884 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003885 r = alloc(STRLEN(txt)
3886 + STRLEN(dashes) // for %s
3887 + 20 // for %3ld
3888 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889 if (r != NULL)
3890 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003891 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003892 len = (int)STRLEN(r);
3893 STRCAT(r, s);
3894 /* remove 'foldmarker' and 'commentstring' */
3895 foldtext_cleanup(r + len);
3896 rettv->vval.v_string = r;
3897 }
3898 }
3899#endif
3900}
3901
3902/*
3903 * "foldtextresult(lnum)" function
3904 */
3905 static void
3906f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3907{
3908#ifdef FEAT_FOLDING
3909 linenr_T lnum;
3910 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003911 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912 foldinfo_T foldinfo;
3913 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003914 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003915#endif
3916
3917 rettv->v_type = VAR_STRING;
3918 rettv->vval.v_string = NULL;
3919#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003920 if (entered)
3921 return; /* reject recursive use */
3922 entered = TRUE;
3923
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003924 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003925 /* treat illegal types and illegal string values for {lnum} the same */
3926 if (lnum < 0)
3927 lnum = 0;
3928 fold_count = foldedCount(curwin, lnum, &foldinfo);
3929 if (fold_count > 0)
3930 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003931 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3932 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933 if (text == buf)
3934 text = vim_strsave(text);
3935 rettv->vval.v_string = text;
3936 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003937
3938 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003939#endif
3940}
3941
3942/*
3943 * "foreground()" function
3944 */
3945 static void
3946f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3947{
3948#ifdef FEAT_GUI
3949 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003950 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003951 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003952 return;
3953 }
3954#endif
3955#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957#endif
3958}
3959
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003960 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003961common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003962{
3963 char_u *s;
3964 char_u *name;
3965 int use_string = FALSE;
3966 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003967 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003968
3969 if (argvars[0].v_type == VAR_FUNC)
3970 {
3971 /* function(MyFunc, [arg], dict) */
3972 s = argvars[0].vval.v_string;
3973 }
3974 else if (argvars[0].v_type == VAR_PARTIAL
3975 && argvars[0].vval.v_partial != NULL)
3976 {
3977 /* function(dict.MyFunc, [arg]) */
3978 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003979 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003980 }
3981 else
3982 {
3983 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003984 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985 use_string = TRUE;
3986 }
3987
Bram Moolenaar843b8842016-08-21 14:36:15 +02003988 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003989 {
3990 name = s;
3991 trans_name = trans_function_name(&name, FALSE,
3992 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3993 if (*name != NUL)
3994 s = NULL;
3995 }
3996
Bram Moolenaar843b8842016-08-21 14:36:15 +02003997 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3998 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003999 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004001 else if (trans_name != NULL && (is_funcref
4002 ? find_func(trans_name) == NULL
4003 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004004 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004005 else
4006 {
4007 int dict_idx = 0;
4008 int arg_idx = 0;
4009 list_T *list = NULL;
4010
4011 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4012 {
4013 char sid_buf[25];
4014 int off = *s == 's' ? 2 : 5;
4015
4016 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4017 * also be called from another script. Using trans_function_name()
4018 * would also work, but some plugins depend on the name being
4019 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004020 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004021 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022 if (name != NULL)
4023 {
4024 STRCPY(name, sid_buf);
4025 STRCAT(name, s + off);
4026 }
4027 }
4028 else
4029 name = vim_strsave(s);
4030
4031 if (argvars[1].v_type != VAR_UNKNOWN)
4032 {
4033 if (argvars[2].v_type != VAR_UNKNOWN)
4034 {
4035 /* function(name, [args], dict) */
4036 arg_idx = 1;
4037 dict_idx = 2;
4038 }
4039 else if (argvars[1].v_type == VAR_DICT)
4040 /* function(name, dict) */
4041 dict_idx = 1;
4042 else
4043 /* function(name, [args]) */
4044 arg_idx = 1;
4045 if (dict_idx > 0)
4046 {
4047 if (argvars[dict_idx].v_type != VAR_DICT)
4048 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004049 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004050 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004051 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004052 }
4053 if (argvars[dict_idx].vval.v_dict == NULL)
4054 dict_idx = 0;
4055 }
4056 if (arg_idx > 0)
4057 {
4058 if (argvars[arg_idx].v_type != VAR_LIST)
4059 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004060 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004061 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004062 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004063 }
4064 list = argvars[arg_idx].vval.v_list;
4065 if (list == NULL || list->lv_len == 0)
4066 arg_idx = 0;
4067 }
4068 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004069 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004071 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072
4073 /* result is a VAR_PARTIAL */
4074 if (pt == NULL)
4075 vim_free(name);
4076 else
4077 {
4078 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4079 {
4080 listitem_T *li;
4081 int i = 0;
4082 int arg_len = 0;
4083 int lv_len = 0;
4084
4085 if (arg_pt != NULL)
4086 arg_len = arg_pt->pt_argc;
4087 if (list != NULL)
4088 lv_len = list->lv_len;
4089 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004090 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 if (pt->pt_argv == NULL)
4092 {
4093 vim_free(pt);
4094 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004095 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004096 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004097 for (i = 0; i < arg_len; i++)
4098 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4099 if (lv_len > 0)
4100 for (li = list->lv_first; li != NULL;
4101 li = li->li_next)
4102 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004103 }
4104
4105 /* For "function(dict.func, [], dict)" and "func" is a partial
4106 * use "dict". That is backwards compatible. */
4107 if (dict_idx > 0)
4108 {
4109 /* The dict is bound explicitly, pt_auto is FALSE. */
4110 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4111 ++pt->pt_dict->dv_refcount;
4112 }
4113 else if (arg_pt != NULL)
4114 {
4115 /* If the dict was bound automatically the result is also
4116 * bound automatically. */
4117 pt->pt_dict = arg_pt->pt_dict;
4118 pt->pt_auto = arg_pt->pt_auto;
4119 if (pt->pt_dict != NULL)
4120 ++pt->pt_dict->dv_refcount;
4121 }
4122
4123 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004124 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4125 {
4126 pt->pt_func = arg_pt->pt_func;
4127 func_ptr_ref(pt->pt_func);
4128 vim_free(name);
4129 }
4130 else if (is_funcref)
4131 {
4132 pt->pt_func = find_func(trans_name);
4133 func_ptr_ref(pt->pt_func);
4134 vim_free(name);
4135 }
4136 else
4137 {
4138 pt->pt_name = name;
4139 func_ref(name);
4140 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 }
4142 rettv->v_type = VAR_PARTIAL;
4143 rettv->vval.v_partial = pt;
4144 }
4145 else
4146 {
4147 /* result is a VAR_FUNC */
4148 rettv->v_type = VAR_FUNC;
4149 rettv->vval.v_string = name;
4150 func_ref(name);
4151 }
4152 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004153theend:
4154 vim_free(trans_name);
4155}
4156
4157/*
4158 * "funcref()" function
4159 */
4160 static void
4161f_funcref(typval_T *argvars, typval_T *rettv)
4162{
4163 common_function(argvars, rettv, TRUE);
4164}
4165
4166/*
4167 * "function()" function
4168 */
4169 static void
4170f_function(typval_T *argvars, typval_T *rettv)
4171{
4172 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004173}
4174
4175/*
4176 * "garbagecollect()" function
4177 */
4178 static void
4179f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4180{
4181 /* This is postponed until we are back at the toplevel, because we may be
4182 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4183 want_garbage_collect = TRUE;
4184
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004185 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186 garbage_collect_at_exit = TRUE;
4187}
4188
4189/*
4190 * "get()" function
4191 */
4192 static void
4193f_get(typval_T *argvars, typval_T *rettv)
4194{
4195 listitem_T *li;
4196 list_T *l;
4197 dictitem_T *di;
4198 dict_T *d;
4199 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004200 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004201
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004202 if (argvars[0].v_type == VAR_BLOB)
4203 {
4204 int error = FALSE;
4205 int idx = tv_get_number_chk(&argvars[1], &error);
4206
4207 if (!error)
4208 {
4209 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004210 if (idx < 0)
4211 idx = blob_len(argvars[0].vval.v_blob) + idx;
4212 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4213 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004214 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004215 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004216 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004217 tv = rettv;
4218 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004219 }
4220 }
4221 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004222 {
4223 if ((l = argvars[0].vval.v_list) != NULL)
4224 {
4225 int error = FALSE;
4226
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004227 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004228 if (!error && li != NULL)
4229 tv = &li->li_tv;
4230 }
4231 }
4232 else if (argvars[0].v_type == VAR_DICT)
4233 {
4234 if ((d = argvars[0].vval.v_dict) != NULL)
4235 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004236 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004237 if (di != NULL)
4238 tv = &di->di_tv;
4239 }
4240 }
4241 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4242 {
4243 partial_T *pt;
4244 partial_T fref_pt;
4245
4246 if (argvars[0].v_type == VAR_PARTIAL)
4247 pt = argvars[0].vval.v_partial;
4248 else
4249 {
4250 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4251 fref_pt.pt_name = argvars[0].vval.v_string;
4252 pt = &fref_pt;
4253 }
4254
4255 if (pt != NULL)
4256 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004257 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004258 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004259
4260 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4261 {
4262 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004263 n = partial_name(pt);
4264 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 rettv->vval.v_string = NULL;
4266 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004267 {
4268 rettv->vval.v_string = vim_strsave(n);
4269 if (rettv->v_type == VAR_FUNC)
4270 func_ref(rettv->vval.v_string);
4271 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004272 }
4273 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004274 {
4275 what_is_dict = TRUE;
4276 if (pt->pt_dict != NULL)
4277 rettv_dict_set(rettv, pt->pt_dict);
4278 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004279 else if (STRCMP(what, "args") == 0)
4280 {
4281 rettv->v_type = VAR_LIST;
4282 if (rettv_list_alloc(rettv) == OK)
4283 {
4284 int i;
4285
4286 for (i = 0; i < pt->pt_argc; ++i)
4287 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4288 }
4289 }
4290 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004291 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004292
4293 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4294 // third argument
4295 if (!what_is_dict)
4296 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297 }
4298 }
4299 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004300 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301
4302 if (tv == NULL)
4303 {
4304 if (argvars[2].v_type != VAR_UNKNOWN)
4305 copy_tv(&argvars[2], rettv);
4306 }
4307 else
4308 copy_tv(tv, rettv);
4309}
4310
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004311/*
4312 * Returns buffer options, variables and other attributes in a dictionary.
4313 */
4314 static dict_T *
4315get_buffer_info(buf_T *buf)
4316{
4317 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004318 tabpage_T *tp;
4319 win_T *wp;
4320 list_T *windows;
4321
4322 dict = dict_alloc();
4323 if (dict == NULL)
4324 return NULL;
4325
Bram Moolenaare0be1672018-07-08 16:50:37 +02004326 dict_add_number(dict, "bufnr", buf->b_fnum);
4327 dict_add_string(dict, "name", buf->b_ffname);
4328 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4329 : buflist_findlnum(buf));
4330 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4331 dict_add_number(dict, "listed", buf->b_p_bl);
4332 dict_add_number(dict, "changed", bufIsChanged(buf));
4333 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4334 dict_add_number(dict, "hidden",
4335 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004336
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004337 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004338 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004339
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004340 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004341 windows = list_alloc();
4342 if (windows != NULL)
4343 {
4344 FOR_ALL_TAB_WINDOWS(tp, wp)
4345 if (wp->w_buffer == buf)
4346 list_append_number(windows, (varnumber_T)wp->w_id);
4347 dict_add_list(dict, "windows", windows);
4348 }
4349
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004350#ifdef FEAT_TEXT_PROP
4351 // List of popup windows displaying this buffer
4352 windows = list_alloc();
4353 if (windows != NULL)
4354 {
4355 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4356 if (wp->w_buffer == buf)
4357 list_append_number(windows, (varnumber_T)wp->w_id);
4358 FOR_ALL_TABPAGES(tp)
4359 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4360 if (wp->w_buffer == buf)
4361 list_append_number(windows, (varnumber_T)wp->w_id);
4362
4363 dict_add_list(dict, "popups", windows);
4364 }
4365#endif
4366
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004367#ifdef FEAT_SIGNS
4368 if (buf->b_signlist != NULL)
4369 {
4370 /* List of signs placed in this buffer */
4371 list_T *signs = list_alloc();
4372 if (signs != NULL)
4373 {
4374 get_buffer_signs(buf, signs);
4375 dict_add_list(dict, "signs", signs);
4376 }
4377 }
4378#endif
4379
4380 return dict;
4381}
4382
4383/*
4384 * "getbufinfo()" function
4385 */
4386 static void
4387f_getbufinfo(typval_T *argvars, typval_T *rettv)
4388{
4389 buf_T *buf = NULL;
4390 buf_T *argbuf = NULL;
4391 dict_T *d;
4392 int filtered = FALSE;
4393 int sel_buflisted = FALSE;
4394 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004395 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004396
4397 if (rettv_list_alloc(rettv) != OK)
4398 return;
4399
4400 /* List of all the buffers or selected buffers */
4401 if (argvars[0].v_type == VAR_DICT)
4402 {
4403 dict_T *sel_d = argvars[0].vval.v_dict;
4404
4405 if (sel_d != NULL)
4406 {
4407 dictitem_T *di;
4408
4409 filtered = TRUE;
4410
4411 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004412 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004413 sel_buflisted = TRUE;
4414
4415 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004416 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004417 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004418
4419 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004420 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004421 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004422 }
4423 }
4424 else if (argvars[0].v_type != VAR_UNKNOWN)
4425 {
4426 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004427 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004428 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004429 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004430 --emsg_off;
4431 if (argbuf == NULL)
4432 return;
4433 }
4434
4435 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004436 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004437 {
4438 if (argbuf != NULL && argbuf != buf)
4439 continue;
4440 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004441 || (sel_buflisted && !buf->b_p_bl)
4442 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004443 continue;
4444
4445 d = get_buffer_info(buf);
4446 if (d != NULL)
4447 list_append_dict(rettv->vval.v_list, d);
4448 if (argbuf != NULL)
4449 return;
4450 }
4451}
4452
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453/*
4454 * Get line or list of lines from buffer "buf" into "rettv".
4455 * Return a range (from start to end) of lines in rettv from the specified
4456 * buffer.
4457 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4458 */
4459 static void
4460get_buffer_lines(
4461 buf_T *buf,
4462 linenr_T start,
4463 linenr_T end,
4464 int retlist,
4465 typval_T *rettv)
4466{
4467 char_u *p;
4468
4469 rettv->v_type = VAR_STRING;
4470 rettv->vval.v_string = NULL;
4471 if (retlist && rettv_list_alloc(rettv) == FAIL)
4472 return;
4473
4474 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4475 return;
4476
4477 if (!retlist)
4478 {
4479 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4480 p = ml_get_buf(buf, start, FALSE);
4481 else
4482 p = (char_u *)"";
4483 rettv->vval.v_string = vim_strsave(p);
4484 }
4485 else
4486 {
4487 if (end < start)
4488 return;
4489
4490 if (start < 1)
4491 start = 1;
4492 if (end > buf->b_ml.ml_line_count)
4493 end = buf->b_ml.ml_line_count;
4494 while (start <= end)
4495 if (list_append_string(rettv->vval.v_list,
4496 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4497 break;
4498 }
4499}
4500
4501/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004502 * "getbufline()" function
4503 */
4504 static void
4505f_getbufline(typval_T *argvars, typval_T *rettv)
4506{
4507 linenr_T lnum;
4508 linenr_T end;
4509 buf_T *buf;
4510
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004511 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004512 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004513 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514 --emsg_off;
4515
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004516 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 if (argvars[2].v_type == VAR_UNKNOWN)
4518 end = lnum;
4519 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004520 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521
4522 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4523}
4524
4525/*
4526 * "getbufvar()" function
4527 */
4528 static void
4529f_getbufvar(typval_T *argvars, typval_T *rettv)
4530{
4531 buf_T *buf;
4532 buf_T *save_curbuf;
4533 char_u *varname;
4534 dictitem_T *v;
4535 int done = FALSE;
4536
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004537 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4538 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004539 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004540 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004541
4542 rettv->v_type = VAR_STRING;
4543 rettv->vval.v_string = NULL;
4544
4545 if (buf != NULL && varname != NULL)
4546 {
4547 /* set curbuf to be our buf, temporarily */
4548 save_curbuf = curbuf;
4549 curbuf = buf;
4550
Bram Moolenaar30567352016-08-27 21:25:44 +02004551 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004552 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004553 if (varname[1] == NUL)
4554 {
4555 /* get all buffer-local options in a dict */
4556 dict_T *opts = get_winbuf_options(TRUE);
4557
4558 if (opts != NULL)
4559 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004560 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004561 done = TRUE;
4562 }
4563 }
4564 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4565 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004566 done = TRUE;
4567 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004568 else
4569 {
4570 /* Look up the variable. */
4571 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4572 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4573 'b', varname, FALSE);
4574 if (v != NULL)
4575 {
4576 copy_tv(&v->di_tv, rettv);
4577 done = TRUE;
4578 }
4579 }
4580
4581 /* restore previous notion of curbuf */
4582 curbuf = save_curbuf;
4583 }
4584
4585 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4586 /* use the default value */
4587 copy_tv(&argvars[2], rettv);
4588
4589 --emsg_off;
4590}
4591
4592/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004593 * "getchangelist()" function
4594 */
4595 static void
4596f_getchangelist(typval_T *argvars, typval_T *rettv)
4597{
4598#ifdef FEAT_JUMPLIST
4599 buf_T *buf;
4600 int i;
4601 list_T *l;
4602 dict_T *d;
4603#endif
4604
4605 if (rettv_list_alloc(rettv) != OK)
4606 return;
4607
4608#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004609 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004610 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004611 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004612 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004613 if (buf == NULL)
4614 return;
4615
4616 l = list_alloc();
4617 if (l == NULL)
4618 return;
4619
4620 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4621 return;
4622 /*
4623 * The current window change list index tracks only the position in the
4624 * current buffer change list. For other buffers, use the change list
4625 * length as the current index.
4626 */
4627 list_append_number(rettv->vval.v_list,
4628 (varnumber_T)((buf == curwin->w_buffer)
4629 ? curwin->w_changelistidx : buf->b_changelistlen));
4630
4631 for (i = 0; i < buf->b_changelistlen; ++i)
4632 {
4633 if (buf->b_changelist[i].lnum == 0)
4634 continue;
4635 if ((d = dict_alloc()) == NULL)
4636 return;
4637 if (list_append_dict(l, d) == FAIL)
4638 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004639 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4640 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004641 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004642 }
4643#endif
4644}
4645/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004646 * "getchar()" function
4647 */
4648 static void
4649f_getchar(typval_T *argvars, typval_T *rettv)
4650{
4651 varnumber_T n;
4652 int error = FALSE;
4653
Bram Moolenaar84d93902018-09-11 20:10:20 +02004654#ifdef MESSAGE_QUEUE
4655 // vpeekc() used to check for messages, but that caused problems, invoking
4656 // a callback where it was not expected. Some plugins use getchar(1) in a
4657 // loop to await a message, therefore make sure we check for messages here.
4658 parse_queued_messages();
4659#endif
4660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661 /* Position the cursor. Needed after a message that ends in a space. */
4662 windgoto(msg_row, msg_col);
4663
4664 ++no_mapping;
4665 ++allow_keys;
4666 for (;;)
4667 {
4668 if (argvars[0].v_type == VAR_UNKNOWN)
4669 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004670 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004671 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672 /* getchar(1): only check if char avail */
4673 n = vpeekc_any();
4674 else if (error || vpeekc_any() == NUL)
4675 /* illegal argument or getchar(0) and no char avail: return zero */
4676 n = 0;
4677 else
4678 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004679 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680
4681 if (n == K_IGNORE)
4682 continue;
4683 break;
4684 }
4685 --no_mapping;
4686 --allow_keys;
4687
4688 set_vim_var_nr(VV_MOUSE_WIN, 0);
4689 set_vim_var_nr(VV_MOUSE_WINID, 0);
4690 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4691 set_vim_var_nr(VV_MOUSE_COL, 0);
4692
4693 rettv->vval.v_number = n;
4694 if (IS_SPECIAL(n) || mod_mask != 0)
4695 {
4696 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4697 int i = 0;
4698
4699 /* Turn a special key into three bytes, plus modifier. */
4700 if (mod_mask != 0)
4701 {
4702 temp[i++] = K_SPECIAL;
4703 temp[i++] = KS_MODIFIER;
4704 temp[i++] = mod_mask;
4705 }
4706 if (IS_SPECIAL(n))
4707 {
4708 temp[i++] = K_SPECIAL;
4709 temp[i++] = K_SECOND(n);
4710 temp[i++] = K_THIRD(n);
4711 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004712 else if (has_mbyte)
4713 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004714 else
4715 temp[i++] = n;
4716 temp[i++] = NUL;
4717 rettv->v_type = VAR_STRING;
4718 rettv->vval.v_string = vim_strsave(temp);
4719
4720#ifdef FEAT_MOUSE
4721 if (is_mouse_key(n))
4722 {
4723 int row = mouse_row;
4724 int col = mouse_col;
4725 win_T *win;
4726 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004728 int winnr = 1;
4729
4730 if (row >= 0 && col >= 0)
4731 {
4732 /* Find the window at the mouse coordinates and compute the
4733 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004734 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004735 if (win == NULL)
4736 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004737 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004738# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004739 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004740 winnr = 0;
4741 else
4742# endif
4743 for (wp = firstwin; wp != win && wp != NULL;
4744 wp = wp->w_next)
4745 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4747 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4748 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4749 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4750 }
4751 }
4752#endif
4753 }
4754}
4755
4756/*
4757 * "getcharmod()" function
4758 */
4759 static void
4760f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4761{
4762 rettv->vval.v_number = mod_mask;
4763}
4764
4765/*
4766 * "getcharsearch()" function
4767 */
4768 static void
4769f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4770{
4771 if (rettv_dict_alloc(rettv) != FAIL)
4772 {
4773 dict_T *dict = rettv->vval.v_dict;
4774
Bram Moolenaare0be1672018-07-08 16:50:37 +02004775 dict_add_string(dict, "char", last_csearch());
4776 dict_add_number(dict, "forward", last_csearch_forward());
4777 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004778 }
4779}
4780
4781/*
4782 * "getcmdline()" function
4783 */
4784 static void
4785f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4786{
4787 rettv->v_type = VAR_STRING;
4788 rettv->vval.v_string = get_cmdline_str();
4789}
4790
4791/*
4792 * "getcmdpos()" function
4793 */
4794 static void
4795f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4796{
4797 rettv->vval.v_number = get_cmdline_pos() + 1;
4798}
4799
4800/*
4801 * "getcmdtype()" function
4802 */
4803 static void
4804f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4805{
4806 rettv->v_type = VAR_STRING;
4807 rettv->vval.v_string = alloc(2);
4808 if (rettv->vval.v_string != NULL)
4809 {
4810 rettv->vval.v_string[0] = get_cmdline_type();
4811 rettv->vval.v_string[1] = NUL;
4812 }
4813}
4814
4815/*
4816 * "getcmdwintype()" function
4817 */
4818 static void
4819f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4820{
4821 rettv->v_type = VAR_STRING;
4822 rettv->vval.v_string = NULL;
4823#ifdef FEAT_CMDWIN
4824 rettv->vval.v_string = alloc(2);
4825 if (rettv->vval.v_string != NULL)
4826 {
4827 rettv->vval.v_string[0] = cmdwin_type;
4828 rettv->vval.v_string[1] = NUL;
4829 }
4830#endif
4831}
4832
4833#if defined(FEAT_CMDL_COMPL)
4834/*
4835 * "getcompletion()" function
4836 */
4837 static void
4838f_getcompletion(typval_T *argvars, typval_T *rettv)
4839{
4840 char_u *pat;
4841 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004842 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004843 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4844 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004845
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004846 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004847 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004848
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004849 if (p_wic)
4850 options |= WILD_ICASE;
4851
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004852 /* For filtered results, 'wildignore' is used */
4853 if (!filtered)
4854 options |= WILD_KEEP_ALL;
4855
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004856 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004857 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004858 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004859 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004860 if (xpc.xp_context == EXPAND_NOTHING)
4861 {
4862 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004863 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004864 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004865 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004866 return;
4867 }
4868
4869# if defined(FEAT_MENU)
4870 if (xpc.xp_context == EXPAND_MENUS)
4871 {
4872 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4873 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4874 }
4875# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004876#ifdef FEAT_CSCOPE
4877 if (xpc.xp_context == EXPAND_CSCOPE)
4878 {
4879 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4880 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4881 }
4882#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004883#ifdef FEAT_SIGNS
4884 if (xpc.xp_context == EXPAND_SIGN)
4885 {
4886 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4887 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4888 }
4889#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004890
4891 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4892 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4893 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004894 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004895
4896 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4897
4898 for (i = 0; i < xpc.xp_numfiles; i++)
4899 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4900 }
4901 vim_free(pat);
4902 ExpandCleanup(&xpc);
4903}
4904#endif
4905
4906/*
4907 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004908 *
4909 * Return the current working directory of a window in a tab page.
4910 * First optional argument 'winnr' is the window number or -1 and the second
4911 * optional argument 'tabnr' is the tab page number.
4912 *
4913 * If no arguments are supplied, then return the directory of the current
4914 * window.
4915 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4916 * the specified window.
4917 * If 'winnr' is 0 then return the directory of the current window.
4918 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4919 * directory of the specified tab page. Otherwise return the directory of the
4920 * specified window in the specified tab page.
4921 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922 */
4923 static void
4924f_getcwd(typval_T *argvars, typval_T *rettv)
4925{
4926 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004927 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004929 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930
4931 rettv->v_type = VAR_STRING;
4932 rettv->vval.v_string = NULL;
4933
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004934 if (argvars[0].v_type == VAR_NUMBER
4935 && argvars[0].vval.v_number == -1
4936 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004937 global = TRUE;
4938 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004939 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004940
4941 if (wp != NULL && wp->w_localdir != NULL)
4942 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004943 else if (tp != NULL && tp->tp_localdir != NULL)
4944 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4945 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004947 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004948 rettv->vval.v_string = vim_strsave(globaldir);
4949 else
4950 {
4951 cwd = alloc(MAXPATHL);
4952 if (cwd != NULL)
4953 {
4954 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4955 rettv->vval.v_string = vim_strsave(cwd);
4956 vim_free(cwd);
4957 }
4958 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004959 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004960#ifdef BACKSLASH_IN_FILENAME
4961 if (rettv->vval.v_string != NULL)
4962 slash_adjust(rettv->vval.v_string);
4963#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004964}
4965
4966/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004967 * "getenv()" function
4968 */
4969 static void
4970f_getenv(typval_T *argvars, typval_T *rettv)
4971{
4972 int mustfree = FALSE;
4973 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4974
4975 if (p == NULL)
4976 {
4977 rettv->v_type = VAR_SPECIAL;
4978 rettv->vval.v_number = VVAL_NULL;
4979 return;
4980 }
4981 if (!mustfree)
4982 p = vim_strsave(p);
4983 rettv->vval.v_string = p;
4984 rettv->v_type = VAR_STRING;
4985}
4986
4987/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004988 * "getfontname()" function
4989 */
4990 static void
4991f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4992{
4993 rettv->v_type = VAR_STRING;
4994 rettv->vval.v_string = NULL;
4995#ifdef FEAT_GUI
4996 if (gui.in_use)
4997 {
4998 GuiFont font;
4999 char_u *name = NULL;
5000
5001 if (argvars[0].v_type == VAR_UNKNOWN)
5002 {
5003 /* Get the "Normal" font. Either the name saved by
5004 * hl_set_font_name() or from the font ID. */
5005 font = gui.norm_font;
5006 name = hl_get_font_name();
5007 }
5008 else
5009 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005010 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005011 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5012 return;
5013 font = gui_mch_get_font(name, FALSE);
5014 if (font == NOFONT)
5015 return; /* Invalid font name, return empty string. */
5016 }
5017 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5018 if (argvars[0].v_type != VAR_UNKNOWN)
5019 gui_mch_free_font(font);
5020 }
5021#endif
5022}
5023
5024/*
5025 * "getfperm({fname})" function
5026 */
5027 static void
5028f_getfperm(typval_T *argvars, typval_T *rettv)
5029{
5030 char_u *fname;
5031 stat_T st;
5032 char_u *perm = NULL;
5033 char_u flags[] = "rwx";
5034 int i;
5035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005036 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037
5038 rettv->v_type = VAR_STRING;
5039 if (mch_stat((char *)fname, &st) >= 0)
5040 {
5041 perm = vim_strsave((char_u *)"---------");
5042 if (perm != NULL)
5043 {
5044 for (i = 0; i < 9; i++)
5045 {
5046 if (st.st_mode & (1 << (8 - i)))
5047 perm[i] = flags[i % 3];
5048 }
5049 }
5050 }
5051 rettv->vval.v_string = perm;
5052}
5053
5054/*
5055 * "getfsize({fname})" function
5056 */
5057 static void
5058f_getfsize(typval_T *argvars, typval_T *rettv)
5059{
5060 char_u *fname;
5061 stat_T st;
5062
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005063 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005064
5065 rettv->v_type = VAR_NUMBER;
5066
5067 if (mch_stat((char *)fname, &st) >= 0)
5068 {
5069 if (mch_isdir(fname))
5070 rettv->vval.v_number = 0;
5071 else
5072 {
5073 rettv->vval.v_number = (varnumber_T)st.st_size;
5074
5075 /* non-perfect check for overflow */
5076 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5077 rettv->vval.v_number = -2;
5078 }
5079 }
5080 else
5081 rettv->vval.v_number = -1;
5082}
5083
5084/*
5085 * "getftime({fname})" function
5086 */
5087 static void
5088f_getftime(typval_T *argvars, typval_T *rettv)
5089{
5090 char_u *fname;
5091 stat_T st;
5092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005093 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094
5095 if (mch_stat((char *)fname, &st) >= 0)
5096 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5097 else
5098 rettv->vval.v_number = -1;
5099}
5100
5101/*
5102 * "getftype({fname})" function
5103 */
5104 static void
5105f_getftype(typval_T *argvars, typval_T *rettv)
5106{
5107 char_u *fname;
5108 stat_T st;
5109 char_u *type = NULL;
5110 char *t;
5111
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005112 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113
5114 rettv->v_type = VAR_STRING;
5115 if (mch_lstat((char *)fname, &st) >= 0)
5116 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 if (S_ISREG(st.st_mode))
5118 t = "file";
5119 else if (S_ISDIR(st.st_mode))
5120 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005121 else if (S_ISLNK(st.st_mode))
5122 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005123 else if (S_ISBLK(st.st_mode))
5124 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005125 else if (S_ISCHR(st.st_mode))
5126 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127 else if (S_ISFIFO(st.st_mode))
5128 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005129 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005130 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005131 else
5132 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005133 type = vim_strsave((char_u *)t);
5134 }
5135 rettv->vval.v_string = type;
5136}
5137
5138/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005139 * "getjumplist()" function
5140 */
5141 static void
5142f_getjumplist(typval_T *argvars, typval_T *rettv)
5143{
5144#ifdef FEAT_JUMPLIST
5145 win_T *wp;
5146 int i;
5147 list_T *l;
5148 dict_T *d;
5149#endif
5150
5151 if (rettv_list_alloc(rettv) != OK)
5152 return;
5153
5154#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005155 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005156 if (wp == NULL)
5157 return;
5158
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005159 cleanup_jumplist(wp, TRUE);
5160
Bram Moolenaar4f505882018-02-10 21:06:32 +01005161 l = list_alloc();
5162 if (l == NULL)
5163 return;
5164
5165 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5166 return;
5167 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5168
5169 for (i = 0; i < wp->w_jumplistlen; ++i)
5170 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005171 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5172 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005173 if ((d = dict_alloc()) == NULL)
5174 return;
5175 if (list_append_dict(l, d) == FAIL)
5176 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005177 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5178 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005179 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005180 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005181 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005182 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005183 }
5184#endif
5185}
5186
5187/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005188 * "getline(lnum, [end])" function
5189 */
5190 static void
5191f_getline(typval_T *argvars, typval_T *rettv)
5192{
5193 linenr_T lnum;
5194 linenr_T end;
5195 int retlist;
5196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005197 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005198 if (argvars[1].v_type == VAR_UNKNOWN)
5199 {
5200 end = 0;
5201 retlist = FALSE;
5202 }
5203 else
5204 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005205 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005206 retlist = TRUE;
5207 }
5208
5209 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5210}
5211
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005212#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005213 static void
5214get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5215{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005216 if (what_arg->v_type == VAR_UNKNOWN)
5217 {
5218 if (rettv_list_alloc(rettv) == OK)
5219 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005220 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005221 }
5222 else
5223 {
5224 if (rettv_dict_alloc(rettv) == OK)
5225 if (is_qf || (wp != NULL))
5226 {
5227 if (what_arg->v_type == VAR_DICT)
5228 {
5229 dict_T *d = what_arg->vval.v_dict;
5230
5231 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005232 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005233 }
5234 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005235 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005236 }
5237 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005238}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005239#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005240
5241/*
5242 * "getloclist()" function
5243 */
5244 static void
5245f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5246{
5247#ifdef FEAT_QUICKFIX
5248 win_T *wp;
5249
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005250 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005251 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5252#endif
5253}
5254
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005256 * "getpid()" function
5257 */
5258 static void
5259f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5260{
5261 rettv->vval.v_number = mch_get_pid();
5262}
5263
5264 static void
5265getpos_both(
5266 typval_T *argvars,
5267 typval_T *rettv,
5268 int getcurpos)
5269{
5270 pos_T *fp;
5271 list_T *l;
5272 int fnum = -1;
5273
5274 if (rettv_list_alloc(rettv) == OK)
5275 {
5276 l = rettv->vval.v_list;
5277 if (getcurpos)
5278 fp = &curwin->w_cursor;
5279 else
5280 fp = var2fpos(&argvars[0], TRUE, &fnum);
5281 if (fnum != -1)
5282 list_append_number(l, (varnumber_T)fnum);
5283 else
5284 list_append_number(l, (varnumber_T)0);
5285 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5286 : (varnumber_T)0);
5287 list_append_number(l, (fp != NULL)
5288 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5289 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005290 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005291 (varnumber_T)0);
5292 if (getcurpos)
5293 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005294 int save_set_curswant = curwin->w_set_curswant;
5295 colnr_T save_curswant = curwin->w_curswant;
5296 colnr_T save_virtcol = curwin->w_virtcol;
5297
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 update_curswant();
5299 list_append_number(l, curwin->w_curswant == MAXCOL ?
5300 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005301
5302 // Do not change "curswant", as it is unexpected that a get
5303 // function has a side effect.
5304 if (save_set_curswant)
5305 {
5306 curwin->w_set_curswant = save_set_curswant;
5307 curwin->w_curswant = save_curswant;
5308 curwin->w_virtcol = save_virtcol;
5309 curwin->w_valid &= ~VALID_VIRTCOL;
5310 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005311 }
5312 }
5313 else
5314 rettv->vval.v_number = FALSE;
5315}
5316
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005317/*
5318 * "getcurpos()" function
5319 */
5320 static void
5321f_getcurpos(typval_T *argvars, typval_T *rettv)
5322{
5323 getpos_both(argvars, rettv, TRUE);
5324}
5325
5326/*
5327 * "getpos(string)" function
5328 */
5329 static void
5330f_getpos(typval_T *argvars, typval_T *rettv)
5331{
5332 getpos_both(argvars, rettv, FALSE);
5333}
5334
5335/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005336 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005337 */
5338 static void
5339f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5340{
5341#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005342 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005343#endif
5344}
5345
5346/*
5347 * "getreg()" function
5348 */
5349 static void
5350f_getreg(typval_T *argvars, typval_T *rettv)
5351{
5352 char_u *strregname;
5353 int regname;
5354 int arg2 = FALSE;
5355 int return_list = FALSE;
5356 int error = FALSE;
5357
5358 if (argvars[0].v_type != VAR_UNKNOWN)
5359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005360 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361 error = strregname == NULL;
5362 if (argvars[1].v_type != VAR_UNKNOWN)
5363 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005364 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005365 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005366 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005367 }
5368 }
5369 else
5370 strregname = get_vim_var_str(VV_REG);
5371
5372 if (error)
5373 return;
5374
5375 regname = (strregname == NULL ? '"' : *strregname);
5376 if (regname == 0)
5377 regname = '"';
5378
5379 if (return_list)
5380 {
5381 rettv->v_type = VAR_LIST;
5382 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5383 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5384 if (rettv->vval.v_list == NULL)
5385 (void)rettv_list_alloc(rettv);
5386 else
5387 ++rettv->vval.v_list->lv_refcount;
5388 }
5389 else
5390 {
5391 rettv->v_type = VAR_STRING;
5392 rettv->vval.v_string = get_reg_contents(regname,
5393 arg2 ? GREG_EXPR_SRC : 0);
5394 }
5395}
5396
5397/*
5398 * "getregtype()" function
5399 */
5400 static void
5401f_getregtype(typval_T *argvars, typval_T *rettv)
5402{
5403 char_u *strregname;
5404 int regname;
5405 char_u buf[NUMBUFLEN + 2];
5406 long reglen = 0;
5407
5408 if (argvars[0].v_type != VAR_UNKNOWN)
5409 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005410 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005411 if (strregname == NULL) /* type error; errmsg already given */
5412 {
5413 rettv->v_type = VAR_STRING;
5414 rettv->vval.v_string = NULL;
5415 return;
5416 }
5417 }
5418 else
5419 /* Default to v:register */
5420 strregname = get_vim_var_str(VV_REG);
5421
5422 regname = (strregname == NULL ? '"' : *strregname);
5423 if (regname == 0)
5424 regname = '"';
5425
5426 buf[0] = NUL;
5427 buf[1] = NUL;
5428 switch (get_reg_type(regname, &reglen))
5429 {
5430 case MLINE: buf[0] = 'V'; break;
5431 case MCHAR: buf[0] = 'v'; break;
5432 case MBLOCK:
5433 buf[0] = Ctrl_V;
5434 sprintf((char *)buf + 1, "%ld", reglen + 1);
5435 break;
5436 }
5437 rettv->v_type = VAR_STRING;
5438 rettv->vval.v_string = vim_strsave(buf);
5439}
5440
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005441/*
5442 * Returns information (variables, options, etc.) about a tab page
5443 * as a dictionary.
5444 */
5445 static dict_T *
5446get_tabpage_info(tabpage_T *tp, int tp_idx)
5447{
5448 win_T *wp;
5449 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005450 list_T *l;
5451
5452 dict = dict_alloc();
5453 if (dict == NULL)
5454 return NULL;
5455
Bram Moolenaare0be1672018-07-08 16:50:37 +02005456 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005457
5458 l = list_alloc();
5459 if (l != NULL)
5460 {
5461 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005462 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005463 list_append_number(l, (varnumber_T)wp->w_id);
5464 dict_add_list(dict, "windows", l);
5465 }
5466
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005467 /* Make a reference to tabpage variables */
5468 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005469
5470 return dict;
5471}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005472
5473/*
5474 * "gettabinfo()" function
5475 */
5476 static void
5477f_gettabinfo(typval_T *argvars, typval_T *rettv)
5478{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005479 tabpage_T *tp, *tparg = NULL;
5480 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005481 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005482
5483 if (rettv_list_alloc(rettv) != OK)
5484 return;
5485
5486 if (argvars[0].v_type != VAR_UNKNOWN)
5487 {
5488 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005489 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005490 if (tparg == NULL)
5491 return;
5492 }
5493
5494 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005495 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005496 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005497 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005498 if (tparg != NULL && tp != tparg)
5499 continue;
5500 d = get_tabpage_info(tp, tpnr);
5501 if (d != NULL)
5502 list_append_dict(rettv->vval.v_list, d);
5503 if (tparg != NULL)
5504 return;
5505 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005506}
5507
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508/*
5509 * "gettabvar()" function
5510 */
5511 static void
5512f_gettabvar(typval_T *argvars, typval_T *rettv)
5513{
5514 win_T *oldcurwin;
5515 tabpage_T *tp, *oldtabpage;
5516 dictitem_T *v;
5517 char_u *varname;
5518 int done = FALSE;
5519
5520 rettv->v_type = VAR_STRING;
5521 rettv->vval.v_string = NULL;
5522
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005523 varname = tv_get_string_chk(&argvars[1]);
5524 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005525 if (tp != NULL && varname != NULL)
5526 {
5527 /* Set tp to be our tabpage, temporarily. Also set the window to the
5528 * first window in the tabpage, otherwise the window is not valid. */
5529 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005530 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5531 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005532 {
5533 /* look up the variable */
5534 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5535 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5536 if (v != NULL)
5537 {
5538 copy_tv(&v->di_tv, rettv);
5539 done = TRUE;
5540 }
5541 }
5542
5543 /* restore previous notion of curwin */
5544 restore_win(oldcurwin, oldtabpage, TRUE);
5545 }
5546
5547 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5548 copy_tv(&argvars[2], rettv);
5549}
5550
5551/*
5552 * "gettabwinvar()" function
5553 */
5554 static void
5555f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5556{
5557 getwinvar(argvars, rettv, 1);
5558}
5559
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005560/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005561 * "gettagstack()" function
5562 */
5563 static void
5564f_gettagstack(typval_T *argvars, typval_T *rettv)
5565{
5566 win_T *wp = curwin; // default is current window
5567
5568 if (rettv_dict_alloc(rettv) != OK)
5569 return;
5570
5571 if (argvars[0].v_type != VAR_UNKNOWN)
5572 {
5573 wp = find_win_by_nr_or_id(&argvars[0]);
5574 if (wp == NULL)
5575 return;
5576 }
5577
5578 get_tagstack(wp, rettv->vval.v_dict);
5579}
5580
5581/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005582 * Returns information about a window as a dictionary.
5583 */
5584 static dict_T *
5585get_win_info(win_T *wp, short tpnr, short winnr)
5586{
5587 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005588
5589 dict = dict_alloc();
5590 if (dict == NULL)
5591 return NULL;
5592
Bram Moolenaare0be1672018-07-08 16:50:37 +02005593 dict_add_number(dict, "tabnr", tpnr);
5594 dict_add_number(dict, "winnr", winnr);
5595 dict_add_number(dict, "winid", wp->w_id);
5596 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005597 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005598 dict_add_number(dict, "topline", wp->w_topline);
5599 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005600#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005601 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005602#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005603 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005604 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005605 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005606
Bram Moolenaar69905d12017-08-13 18:14:47 +02005607#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005608 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005609#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005610#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005611 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5612 dict_add_number(dict, "loclist",
5613 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005614#endif
5615
Bram Moolenaar30567352016-08-27 21:25:44 +02005616 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005617 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005618
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005619 return dict;
5620}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005621
5622/*
5623 * "getwininfo()" function
5624 */
5625 static void
5626f_getwininfo(typval_T *argvars, typval_T *rettv)
5627{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005628 tabpage_T *tp;
5629 win_T *wp = NULL, *wparg = NULL;
5630 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005631 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632
5633 if (rettv_list_alloc(rettv) != OK)
5634 return;
5635
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005636 if (argvars[0].v_type != VAR_UNKNOWN)
5637 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005638 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005639 if (wparg == NULL)
5640 return;
5641 }
5642
5643 /* Collect information about either all the windows across all the tab
5644 * pages or one particular window.
5645 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005646 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005647 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005648 tabnr++;
5649 winnr = 0;
5650 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005651 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005652 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005653 if (wparg != NULL && wp != wparg)
5654 continue;
5655 d = get_win_info(wp, tabnr, winnr);
5656 if (d != NULL)
5657 list_append_dict(rettv->vval.v_list, d);
5658 if (wparg != NULL)
5659 /* found information about a specific window */
5660 return;
5661 }
5662 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005663}
5664
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005665/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005666 * "win_execute()" function
5667 */
5668 static void
5669f_win_execute(typval_T *argvars, typval_T *rettv)
5670{
5671 int id = (int)tv_get_number(argvars);
5672 win_T *wp = win_id2wp(id);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005673 win_T *save_curwin;
5674 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005675
5676 if (wp != NULL)
5677 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005678 if (switch_win_noblock(&save_curwin, &save_curtab, wp, curtab, TRUE)
5679 == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005680 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005681 check_cursor();
5682 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005683 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005684 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005685 }
5686}
5687
5688/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689 * "win_findbuf()" function
5690 */
5691 static void
5692f_win_findbuf(typval_T *argvars, typval_T *rettv)
5693{
5694 if (rettv_list_alloc(rettv) != FAIL)
5695 win_findbuf(argvars, rettv->vval.v_list);
5696}
5697
5698/*
5699 * "win_getid()" function
5700 */
5701 static void
5702f_win_getid(typval_T *argvars, typval_T *rettv)
5703{
5704 rettv->vval.v_number = win_getid(argvars);
5705}
5706
5707/*
5708 * "win_gotoid()" function
5709 */
5710 static void
5711f_win_gotoid(typval_T *argvars, typval_T *rettv)
5712{
5713 rettv->vval.v_number = win_gotoid(argvars);
5714}
5715
5716/*
5717 * "win_id2tabwin()" function
5718 */
5719 static void
5720f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5721{
5722 if (rettv_list_alloc(rettv) != FAIL)
5723 win_id2tabwin(argvars, rettv->vval.v_list);
5724}
5725
5726/*
5727 * "win_id2win()" function
5728 */
5729 static void
5730f_win_id2win(typval_T *argvars, typval_T *rettv)
5731{
5732 rettv->vval.v_number = win_id2win(argvars);
5733}
5734
5735/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005736 * "win_screenpos()" function
5737 */
5738 static void
5739f_win_screenpos(typval_T *argvars, typval_T *rettv)
5740{
5741 win_T *wp;
5742
5743 if (rettv_list_alloc(rettv) == FAIL)
5744 return;
5745
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005746 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005747 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5748 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5749}
5750
5751/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005752 * "getwinpos({timeout})" function
5753 */
5754 static void
5755f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5756{
5757 int x = -1;
5758 int y = -1;
5759
5760 if (rettv_list_alloc(rettv) == FAIL)
5761 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005762#if defined(FEAT_GUI) \
5763 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5764 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005765 {
5766 varnumber_T timeout = 100;
5767
5768 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005769 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005770
5771 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005772 }
5773#endif
5774 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5775 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5776}
5777
5778
5779/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005780 * "getwinposx()" function
5781 */
5782 static void
5783f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5784{
5785 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005786#if defined(FEAT_GUI) \
5787 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5788 || defined(MSWIN)
5789
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005790 {
5791 int x, y;
5792
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005793 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005794 rettv->vval.v_number = x;
5795 }
5796#endif
5797}
5798
5799/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005800 * "getwinposy()" function
5801 */
5802 static void
5803f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5804{
5805 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005806#if defined(FEAT_GUI) \
5807 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5808 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005809 {
5810 int x, y;
5811
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005812 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005813 rettv->vval.v_number = y;
5814 }
5815#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005816}
5817
5818/*
5819 * "getwinvar()" function
5820 */
5821 static void
5822f_getwinvar(typval_T *argvars, typval_T *rettv)
5823{
5824 getwinvar(argvars, rettv, 0);
5825}
5826
5827/*
5828 * "glob()" function
5829 */
5830 static void
5831f_glob(typval_T *argvars, typval_T *rettv)
5832{
5833 int options = WILD_SILENT|WILD_USE_NL;
5834 expand_T xpc;
5835 int error = FALSE;
5836
5837 /* When the optional second argument is non-zero, don't remove matches
5838 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5839 rettv->v_type = VAR_STRING;
5840 if (argvars[1].v_type != VAR_UNKNOWN)
5841 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005842 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005843 options |= WILD_KEEP_ALL;
5844 if (argvars[2].v_type != VAR_UNKNOWN)
5845 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005846 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005847 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005848 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005849 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850 options |= WILD_ALLLINKS;
5851 }
5852 }
5853 if (!error)
5854 {
5855 ExpandInit(&xpc);
5856 xpc.xp_context = EXPAND_FILES;
5857 if (p_wic)
5858 options += WILD_ICASE;
5859 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005860 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005861 NULL, options, WILD_ALL);
5862 else if (rettv_list_alloc(rettv) != FAIL)
5863 {
5864 int i;
5865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005866 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005867 NULL, options, WILD_ALL_KEEP);
5868 for (i = 0; i < xpc.xp_numfiles; i++)
5869 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5870
5871 ExpandCleanup(&xpc);
5872 }
5873 }
5874 else
5875 rettv->vval.v_string = NULL;
5876}
5877
5878/*
5879 * "globpath()" function
5880 */
5881 static void
5882f_globpath(typval_T *argvars, typval_T *rettv)
5883{
5884 int flags = 0;
5885 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005886 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005887 int error = FALSE;
5888 garray_T ga;
5889 int i;
5890
5891 /* When the optional second argument is non-zero, don't remove matches
5892 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5893 rettv->v_type = VAR_STRING;
5894 if (argvars[2].v_type != VAR_UNKNOWN)
5895 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005896 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005897 flags |= WILD_KEEP_ALL;
5898 if (argvars[3].v_type != VAR_UNKNOWN)
5899 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005900 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005901 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005902 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005903 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005904 flags |= WILD_ALLLINKS;
5905 }
5906 }
5907 if (file != NULL && !error)
5908 {
5909 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005910 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005911 if (rettv->v_type == VAR_STRING)
5912 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5913 else if (rettv_list_alloc(rettv) != FAIL)
5914 for (i = 0; i < ga.ga_len; ++i)
5915 list_append_string(rettv->vval.v_list,
5916 ((char_u **)(ga.ga_data))[i], -1);
5917 ga_clear_strings(&ga);
5918 }
5919 else
5920 rettv->vval.v_string = NULL;
5921}
5922
5923/*
5924 * "glob2regpat()" function
5925 */
5926 static void
5927f_glob2regpat(typval_T *argvars, typval_T *rettv)
5928{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005929 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930
5931 rettv->v_type = VAR_STRING;
5932 rettv->vval.v_string = (pat == NULL)
5933 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5934}
5935
5936/* for VIM_VERSION_ defines */
5937#include "version.h"
5938
5939/*
5940 * "has()" function
5941 */
5942 static void
5943f_has(typval_T *argvars, typval_T *rettv)
5944{
5945 int i;
5946 char_u *name;
5947 int n = FALSE;
5948 static char *(has_list[]) =
5949 {
5950#ifdef AMIGA
5951 "amiga",
5952# ifdef FEAT_ARP
5953 "arp",
5954# endif
5955#endif
5956#ifdef __BEOS__
5957 "beos",
5958#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005959#if defined(BSD) && !defined(MACOS_X)
5960 "bsd",
5961#endif
5962#ifdef hpux
5963 "hpux",
5964#endif
5965#ifdef __linux__
5966 "linux",
5967#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005968#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005969 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5970 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005971# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005972 "macunix", /* Mac OS X, with the darwin feature */
5973 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005974# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975#endif
5976#ifdef __QNX__
5977 "qnx",
5978#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005979#ifdef SUN_SYSTEM
5980 "sun",
5981#else
5982 "moon",
5983#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984#ifdef UNIX
5985 "unix",
5986#endif
5987#ifdef VMS
5988 "vms",
5989#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005990#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991 "win32",
5992#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005993#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 "win32unix",
5995#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005996#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 "win64",
5998#endif
5999#ifdef EBCDIC
6000 "ebcdic",
6001#endif
6002#ifndef CASE_INSENSITIVE_FILENAME
6003 "fname_case",
6004#endif
6005#ifdef HAVE_ACL
6006 "acl",
6007#endif
6008#ifdef FEAT_ARABIC
6009 "arabic",
6010#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006011 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006012#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006013 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006014#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006015#ifdef FEAT_AUTOSERVERNAME
6016 "autoservername",
6017#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006018#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006019 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006020# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006021 "balloon_multiline",
6022# endif
6023#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006024#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006025 "balloon_eval_term",
6026#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6028 "builtin_terms",
6029# ifdef ALL_BUILTIN_TCAPS
6030 "all_builtin_terms",
6031# endif
6032#endif
6033#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006034 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006035 || defined(FEAT_GUI_MOTIF))
6036 "browsefilter",
6037#endif
6038#ifdef FEAT_BYTEOFF
6039 "byte_offset",
6040#endif
6041#ifdef FEAT_JOB_CHANNEL
6042 "channel",
6043#endif
6044#ifdef FEAT_CINDENT
6045 "cindent",
6046#endif
6047#ifdef FEAT_CLIENTSERVER
6048 "clientserver",
6049#endif
6050#ifdef FEAT_CLIPBOARD
6051 "clipboard",
6052#endif
6053#ifdef FEAT_CMDL_COMPL
6054 "cmdline_compl",
6055#endif
6056#ifdef FEAT_CMDHIST
6057 "cmdline_hist",
6058#endif
6059#ifdef FEAT_COMMENTS
6060 "comments",
6061#endif
6062#ifdef FEAT_CONCEAL
6063 "conceal",
6064#endif
6065#ifdef FEAT_CRYPT
6066 "cryptv",
6067 "crypt-blowfish",
6068 "crypt-blowfish2",
6069#endif
6070#ifdef FEAT_CSCOPE
6071 "cscope",
6072#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006074#ifdef CURSOR_SHAPE
6075 "cursorshape",
6076#endif
6077#ifdef DEBUG
6078 "debug",
6079#endif
6080#ifdef FEAT_CON_DIALOG
6081 "dialog_con",
6082#endif
6083#ifdef FEAT_GUI_DIALOG
6084 "dialog_gui",
6085#endif
6086#ifdef FEAT_DIFF
6087 "diff",
6088#endif
6089#ifdef FEAT_DIGRAPHS
6090 "digraphs",
6091#endif
6092#ifdef FEAT_DIRECTX
6093 "directx",
6094#endif
6095#ifdef FEAT_DND
6096 "dnd",
6097#endif
6098#ifdef FEAT_EMACS_TAGS
6099 "emacs_tags",
6100#endif
6101 "eval", /* always present, of course! */
6102 "ex_extra", /* graduated feature */
6103#ifdef FEAT_SEARCH_EXTRA
6104 "extra_search",
6105#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006106#ifdef FEAT_SEARCHPATH
6107 "file_in_path",
6108#endif
6109#ifdef FEAT_FILTERPIPE
6110 "filterpipe",
6111#endif
6112#ifdef FEAT_FIND_ID
6113 "find_in_path",
6114#endif
6115#ifdef FEAT_FLOAT
6116 "float",
6117#endif
6118#ifdef FEAT_FOLDING
6119 "folding",
6120#endif
6121#ifdef FEAT_FOOTER
6122 "footer",
6123#endif
6124#if !defined(USE_SYSTEM) && defined(UNIX)
6125 "fork",
6126#endif
6127#ifdef FEAT_GETTEXT
6128 "gettext",
6129#endif
6130#ifdef FEAT_GUI
6131 "gui",
6132#endif
6133#ifdef FEAT_GUI_ATHENA
6134# ifdef FEAT_GUI_NEXTAW
6135 "gui_neXtaw",
6136# else
6137 "gui_athena",
6138# endif
6139#endif
6140#ifdef FEAT_GUI_GTK
6141 "gui_gtk",
6142# ifdef USE_GTK3
6143 "gui_gtk3",
6144# else
6145 "gui_gtk2",
6146# endif
6147#endif
6148#ifdef FEAT_GUI_GNOME
6149 "gui_gnome",
6150#endif
6151#ifdef FEAT_GUI_MAC
6152 "gui_mac",
6153#endif
6154#ifdef FEAT_GUI_MOTIF
6155 "gui_motif",
6156#endif
6157#ifdef FEAT_GUI_PHOTON
6158 "gui_photon",
6159#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006160#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006161 "gui_win32",
6162#endif
6163#ifdef FEAT_HANGULIN
6164 "hangul_input",
6165#endif
6166#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6167 "iconv",
6168#endif
6169#ifdef FEAT_INS_EXPAND
6170 "insert_expand",
6171#endif
6172#ifdef FEAT_JOB_CHANNEL
6173 "job",
6174#endif
6175#ifdef FEAT_JUMPLIST
6176 "jumplist",
6177#endif
6178#ifdef FEAT_KEYMAP
6179 "keymap",
6180#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006181 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182#ifdef FEAT_LANGMAP
6183 "langmap",
6184#endif
6185#ifdef FEAT_LIBCALL
6186 "libcall",
6187#endif
6188#ifdef FEAT_LINEBREAK
6189 "linebreak",
6190#endif
6191#ifdef FEAT_LISP
6192 "lispindent",
6193#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195#ifdef FEAT_LOCALMAP
6196 "localmap",
6197#endif
6198#ifdef FEAT_LUA
6199# ifndef DYNAMIC_LUA
6200 "lua",
6201# endif
6202#endif
6203#ifdef FEAT_MENU
6204 "menu",
6205#endif
6206#ifdef FEAT_SESSION
6207 "mksession",
6208#endif
6209#ifdef FEAT_MODIFY_FNAME
6210 "modify_fname",
6211#endif
6212#ifdef FEAT_MOUSE
6213 "mouse",
6214#endif
6215#ifdef FEAT_MOUSESHAPE
6216 "mouseshape",
6217#endif
6218#if defined(UNIX) || defined(VMS)
6219# ifdef FEAT_MOUSE_DEC
6220 "mouse_dec",
6221# endif
6222# ifdef FEAT_MOUSE_GPM
6223 "mouse_gpm",
6224# endif
6225# ifdef FEAT_MOUSE_JSB
6226 "mouse_jsbterm",
6227# endif
6228# ifdef FEAT_MOUSE_NET
6229 "mouse_netterm",
6230# endif
6231# ifdef FEAT_MOUSE_PTERM
6232 "mouse_pterm",
6233# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006234# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006235 "mouse_sgr",
6236# endif
6237# ifdef FEAT_SYSMOUSE
6238 "mouse_sysmouse",
6239# endif
6240# ifdef FEAT_MOUSE_URXVT
6241 "mouse_urxvt",
6242# endif
6243# ifdef FEAT_MOUSE_XTERM
6244 "mouse_xterm",
6245# endif
6246#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006247 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006248#ifdef FEAT_MBYTE_IME
6249 "multi_byte_ime",
6250#endif
6251#ifdef FEAT_MULTI_LANG
6252 "multi_lang",
6253#endif
6254#ifdef FEAT_MZSCHEME
6255#ifndef DYNAMIC_MZSCHEME
6256 "mzscheme",
6257#endif
6258#endif
6259#ifdef FEAT_NUM64
6260 "num64",
6261#endif
6262#ifdef FEAT_OLE
6263 "ole",
6264#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006265#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268#ifdef FEAT_PATH_EXTRA
6269 "path_extra",
6270#endif
6271#ifdef FEAT_PERL
6272#ifndef DYNAMIC_PERL
6273 "perl",
6274#endif
6275#endif
6276#ifdef FEAT_PERSISTENT_UNDO
6277 "persistent_undo",
6278#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006279#if defined(FEAT_PYTHON)
6280 "python_compiled",
6281# if defined(DYNAMIC_PYTHON)
6282 "python_dynamic",
6283# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006284 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006285 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006286# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006287#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006288#if defined(FEAT_PYTHON3)
6289 "python3_compiled",
6290# if defined(DYNAMIC_PYTHON3)
6291 "python3_dynamic",
6292# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006294 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006295# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006296#endif
6297#ifdef FEAT_POSTSCRIPT
6298 "postscript",
6299#endif
6300#ifdef FEAT_PRINTER
6301 "printer",
6302#endif
6303#ifdef FEAT_PROFILE
6304 "profile",
6305#endif
6306#ifdef FEAT_RELTIME
6307 "reltime",
6308#endif
6309#ifdef FEAT_QUICKFIX
6310 "quickfix",
6311#endif
6312#ifdef FEAT_RIGHTLEFT
6313 "rightleft",
6314#endif
6315#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6316 "ruby",
6317#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006319#ifdef FEAT_CMDL_INFO
6320 "showcmd",
6321 "cmdline_info",
6322#endif
6323#ifdef FEAT_SIGNS
6324 "signs",
6325#endif
6326#ifdef FEAT_SMARTINDENT
6327 "smartindent",
6328#endif
6329#ifdef STARTUPTIME
6330 "startuptime",
6331#endif
6332#ifdef FEAT_STL_OPT
6333 "statusline",
6334#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335#ifdef FEAT_NETBEANS_INTG
6336 "netbeans_intg",
6337#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006338#ifdef FEAT_SOUND
6339 "sound",
6340#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341#ifdef FEAT_SPELL
6342 "spell",
6343#endif
6344#ifdef FEAT_SYN_HL
6345 "syntax",
6346#endif
6347#if defined(USE_SYSTEM) || !defined(UNIX)
6348 "system",
6349#endif
6350#ifdef FEAT_TAG_BINS
6351 "tag_binary",
6352#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353#ifdef FEAT_TCL
6354# ifndef DYNAMIC_TCL
6355 "tcl",
6356# endif
6357#endif
6358#ifdef FEAT_TERMGUICOLORS
6359 "termguicolors",
6360#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006361#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006362 "terminal",
6363#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364#ifdef TERMINFO
6365 "terminfo",
6366#endif
6367#ifdef FEAT_TERMRESPONSE
6368 "termresponse",
6369#endif
6370#ifdef FEAT_TEXTOBJ
6371 "textobjects",
6372#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006373#ifdef FEAT_TEXT_PROP
6374 "textprop",
6375#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376#ifdef HAVE_TGETENT
6377 "tgetent",
6378#endif
6379#ifdef FEAT_TIMERS
6380 "timers",
6381#endif
6382#ifdef FEAT_TITLE
6383 "title",
6384#endif
6385#ifdef FEAT_TOOLBAR
6386 "toolbar",
6387#endif
6388#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6389 "unnamedplus",
6390#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006391 "user-commands", /* was accidentally included in 5.4 */
6392 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006393#ifdef FEAT_VARTABS
6394 "vartabs",
6395#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006396 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006397#ifdef FEAT_VIMINFO
6398 "viminfo",
6399#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006400 "vimscript-1",
6401 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006402 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006403 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006404 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006407#ifdef FEAT_VTP
6408 "vtp",
6409#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410#ifdef FEAT_WILDIGN
6411 "wildignore",
6412#endif
6413#ifdef FEAT_WILDMENU
6414 "wildmenu",
6415#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417#ifdef FEAT_WAK
6418 "winaltkeys",
6419#endif
6420#ifdef FEAT_WRITEBACKUP
6421 "writebackup",
6422#endif
6423#ifdef FEAT_XIM
6424 "xim",
6425#endif
6426#ifdef FEAT_XFONTSET
6427 "xfontset",
6428#endif
6429#ifdef FEAT_XPM_W32
6430 "xpm",
6431 "xpm_w32", /* for backward compatibility */
6432#else
6433# if defined(HAVE_XPM)
6434 "xpm",
6435# endif
6436#endif
6437#ifdef USE_XSMP
6438 "xsmp",
6439#endif
6440#ifdef USE_XSMP_INTERACT
6441 "xsmp_interact",
6442#endif
6443#ifdef FEAT_XCLIPBOARD
6444 "xterm_clipboard",
6445#endif
6446#ifdef FEAT_XTERM_SAVE
6447 "xterm_save",
6448#endif
6449#if defined(UNIX) && defined(FEAT_X11)
6450 "X11",
6451#endif
6452 NULL
6453 };
6454
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006455 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456 for (i = 0; has_list[i] != NULL; ++i)
6457 if (STRICMP(name, has_list[i]) == 0)
6458 {
6459 n = TRUE;
6460 break;
6461 }
6462
6463 if (n == FALSE)
6464 {
6465 if (STRNICMP(name, "patch", 5) == 0)
6466 {
6467 if (name[5] == '-'
6468 && STRLEN(name) >= 11
6469 && vim_isdigit(name[6])
6470 && vim_isdigit(name[8])
6471 && vim_isdigit(name[10]))
6472 {
6473 int major = atoi((char *)name + 6);
6474 int minor = atoi((char *)name + 8);
6475
6476 /* Expect "patch-9.9.01234". */
6477 n = (major < VIM_VERSION_MAJOR
6478 || (major == VIM_VERSION_MAJOR
6479 && (minor < VIM_VERSION_MINOR
6480 || (minor == VIM_VERSION_MINOR
6481 && has_patch(atoi((char *)name + 10))))));
6482 }
6483 else
6484 n = has_patch(atoi((char *)name + 5));
6485 }
6486 else if (STRICMP(name, "vim_starting") == 0)
6487 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006488 else if (STRICMP(name, "ttyin") == 0)
6489 n = mch_input_isatty();
6490 else if (STRICMP(name, "ttyout") == 0)
6491 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006492 else if (STRICMP(name, "multi_byte_encoding") == 0)
6493 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006494#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495 else if (STRICMP(name, "balloon_multiline") == 0)
6496 n = multiline_balloon_available();
6497#endif
6498#ifdef DYNAMIC_TCL
6499 else if (STRICMP(name, "tcl") == 0)
6500 n = tcl_enabled(FALSE);
6501#endif
6502#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6503 else if (STRICMP(name, "iconv") == 0)
6504 n = iconv_enabled(FALSE);
6505#endif
6506#ifdef DYNAMIC_LUA
6507 else if (STRICMP(name, "lua") == 0)
6508 n = lua_enabled(FALSE);
6509#endif
6510#ifdef DYNAMIC_MZSCHEME
6511 else if (STRICMP(name, "mzscheme") == 0)
6512 n = mzscheme_enabled(FALSE);
6513#endif
6514#ifdef DYNAMIC_RUBY
6515 else if (STRICMP(name, "ruby") == 0)
6516 n = ruby_enabled(FALSE);
6517#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518#ifdef DYNAMIC_PYTHON
6519 else if (STRICMP(name, "python") == 0)
6520 n = python_enabled(FALSE);
6521#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522#ifdef DYNAMIC_PYTHON3
6523 else if (STRICMP(name, "python3") == 0)
6524 n = python3_enabled(FALSE);
6525#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006526#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6527 else if (STRICMP(name, "pythonx") == 0)
6528 {
6529# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6530 if (p_pyx == 0)
6531 n = python3_enabled(FALSE) || python_enabled(FALSE);
6532 else if (p_pyx == 3)
6533 n = python3_enabled(FALSE);
6534 else if (p_pyx == 2)
6535 n = python_enabled(FALSE);
6536# elif defined(DYNAMIC_PYTHON)
6537 n = python_enabled(FALSE);
6538# elif defined(DYNAMIC_PYTHON3)
6539 n = python3_enabled(FALSE);
6540# endif
6541 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006542#endif
6543#ifdef DYNAMIC_PERL
6544 else if (STRICMP(name, "perl") == 0)
6545 n = perl_enabled(FALSE);
6546#endif
6547#ifdef FEAT_GUI
6548 else if (STRICMP(name, "gui_running") == 0)
6549 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550# ifdef FEAT_BROWSE
6551 else if (STRICMP(name, "browse") == 0)
6552 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6553# endif
6554#endif
6555#ifdef FEAT_SYN_HL
6556 else if (STRICMP(name, "syntax_items") == 0)
6557 n = syntax_present(curwin);
6558#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006559#ifdef FEAT_VTP
6560 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006561 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562#endif
6563#ifdef FEAT_NETBEANS_INTG
6564 else if (STRICMP(name, "netbeans_enabled") == 0)
6565 n = netbeans_active();
6566#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006567#ifdef FEAT_MOUSE_GPM
6568 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6569 n = gpm_enabled();
6570#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006571#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006572 else if (STRICMP(name, "terminal") == 0)
6573 n = terminal_enabled();
6574#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006575#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006576 else if (STRICMP(name, "conpty") == 0)
6577 n = use_conpty();
6578#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006579 }
6580
6581 rettv->vval.v_number = n;
6582}
6583
6584/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006585 * "haslocaldir()" function
6586 */
6587 static void
6588f_haslocaldir(typval_T *argvars, typval_T *rettv)
6589{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006590 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591 win_T *wp = NULL;
6592
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006593 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6594
6595 // Check for window-local and tab-local directories
6596 if (wp != NULL && wp->w_localdir != NULL)
6597 rettv->vval.v_number = 1;
6598 else if (tp != NULL && tp->tp_localdir != NULL)
6599 rettv->vval.v_number = 2;
6600 else
6601 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602}
6603
6604/*
6605 * "hasmapto()" function
6606 */
6607 static void
6608f_hasmapto(typval_T *argvars, typval_T *rettv)
6609{
6610 char_u *name;
6611 char_u *mode;
6612 char_u buf[NUMBUFLEN];
6613 int abbr = FALSE;
6614
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006615 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616 if (argvars[1].v_type == VAR_UNKNOWN)
6617 mode = (char_u *)"nvo";
6618 else
6619 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006620 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006621 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006622 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623 }
6624
6625 if (map_to_exists(name, mode, abbr))
6626 rettv->vval.v_number = TRUE;
6627 else
6628 rettv->vval.v_number = FALSE;
6629}
6630
6631/*
6632 * "histadd()" function
6633 */
6634 static void
6635f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6636{
6637#ifdef FEAT_CMDHIST
6638 int histype;
6639 char_u *str;
6640 char_u buf[NUMBUFLEN];
6641#endif
6642
6643 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006644 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645 return;
6646#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006647 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006648 histype = str != NULL ? get_histtype(str) : -1;
6649 if (histype >= 0)
6650 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006651 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652 if (*str != NUL)
6653 {
6654 init_history();
6655 add_to_history(histype, str, FALSE, NUL);
6656 rettv->vval.v_number = TRUE;
6657 return;
6658 }
6659 }
6660#endif
6661}
6662
6663/*
6664 * "histdel()" function
6665 */
6666 static void
6667f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6668{
6669#ifdef FEAT_CMDHIST
6670 int n;
6671 char_u buf[NUMBUFLEN];
6672 char_u *str;
6673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006674 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675 if (str == NULL)
6676 n = 0;
6677 else if (argvars[1].v_type == VAR_UNKNOWN)
6678 /* only one argument: clear entire history */
6679 n = clr_history(get_histtype(str));
6680 else if (argvars[1].v_type == VAR_NUMBER)
6681 /* index given: remove that entry */
6682 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006683 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006684 else
6685 /* string given: remove all matching entries */
6686 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006687 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 rettv->vval.v_number = n;
6689#endif
6690}
6691
6692/*
6693 * "histget()" function
6694 */
6695 static void
6696f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6697{
6698#ifdef FEAT_CMDHIST
6699 int type;
6700 int idx;
6701 char_u *str;
6702
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006703 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006704 if (str == NULL)
6705 rettv->vval.v_string = NULL;
6706 else
6707 {
6708 type = get_histtype(str);
6709 if (argvars[1].v_type == VAR_UNKNOWN)
6710 idx = get_history_idx(type);
6711 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006712 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006713 /* -1 on type error */
6714 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6715 }
6716#else
6717 rettv->vval.v_string = NULL;
6718#endif
6719 rettv->v_type = VAR_STRING;
6720}
6721
6722/*
6723 * "histnr()" function
6724 */
6725 static void
6726f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6727{
6728 int i;
6729
6730#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006731 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732
6733 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6734 if (i >= HIST_CMD && i < HIST_COUNT)
6735 i = get_history_idx(i);
6736 else
6737#endif
6738 i = -1;
6739 rettv->vval.v_number = i;
6740}
6741
6742/*
6743 * "highlightID(name)" function
6744 */
6745 static void
6746f_hlID(typval_T *argvars, typval_T *rettv)
6747{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006748 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006749}
6750
6751/*
6752 * "highlight_exists()" function
6753 */
6754 static void
6755f_hlexists(typval_T *argvars, typval_T *rettv)
6756{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006757 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758}
6759
6760/*
6761 * "hostname()" function
6762 */
6763 static void
6764f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6765{
6766 char_u hostname[256];
6767
6768 mch_get_host_name(hostname, 256);
6769 rettv->v_type = VAR_STRING;
6770 rettv->vval.v_string = vim_strsave(hostname);
6771}
6772
6773/*
6774 * iconv() function
6775 */
6776 static void
6777f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6778{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 char_u buf1[NUMBUFLEN];
6780 char_u buf2[NUMBUFLEN];
6781 char_u *from, *to, *str;
6782 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006783
6784 rettv->v_type = VAR_STRING;
6785 rettv->vval.v_string = NULL;
6786
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006787 str = tv_get_string(&argvars[0]);
6788 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6789 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006790 vimconv.vc_type = CONV_NONE;
6791 convert_setup(&vimconv, from, to);
6792
6793 /* If the encodings are equal, no conversion needed. */
6794 if (vimconv.vc_type == CONV_NONE)
6795 rettv->vval.v_string = vim_strsave(str);
6796 else
6797 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6798
6799 convert_setup(&vimconv, NULL, NULL);
6800 vim_free(from);
6801 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802}
6803
6804/*
6805 * "indent()" function
6806 */
6807 static void
6808f_indent(typval_T *argvars, typval_T *rettv)
6809{
6810 linenr_T lnum;
6811
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006812 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6814 rettv->vval.v_number = get_indent_lnum(lnum);
6815 else
6816 rettv->vval.v_number = -1;
6817}
6818
6819/*
6820 * "index()" function
6821 */
6822 static void
6823f_index(typval_T *argvars, typval_T *rettv)
6824{
6825 list_T *l;
6826 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006827 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828 long idx = 0;
6829 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006830 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831
6832 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006833 if (argvars[0].v_type == VAR_BLOB)
6834 {
6835 typval_T tv;
6836 int start = 0;
6837
6838 if (argvars[2].v_type != VAR_UNKNOWN)
6839 {
6840 start = tv_get_number_chk(&argvars[2], &error);
6841 if (error)
6842 return;
6843 }
6844 b = argvars[0].vval.v_blob;
6845 if (b == NULL)
6846 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006847 if (start < 0)
6848 {
6849 start = blob_len(b) + start;
6850 if (start < 0)
6851 start = 0;
6852 }
6853
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006854 for (idx = start; idx < blob_len(b); ++idx)
6855 {
6856 tv.v_type = VAR_NUMBER;
6857 tv.vval.v_number = blob_get(b, idx);
6858 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6859 {
6860 rettv->vval.v_number = idx;
6861 return;
6862 }
6863 }
6864 return;
6865 }
6866 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006868 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869 return;
6870 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006871
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006872 l = argvars[0].vval.v_list;
6873 if (l != NULL)
6874 {
6875 item = l->lv_first;
6876 if (argvars[2].v_type != VAR_UNKNOWN)
6877 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 /* Start at specified item. Use the cached index that list_find()
6879 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006880 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006881 idx = l->lv_idx;
6882 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006883 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006884 if (error)
6885 item = NULL;
6886 }
6887
6888 for ( ; item != NULL; item = item->li_next, ++idx)
6889 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6890 {
6891 rettv->vval.v_number = idx;
6892 break;
6893 }
6894 }
6895}
6896
6897static int inputsecret_flag = 0;
6898
6899/*
6900 * "input()" function
6901 * Also handles inputsecret() when inputsecret is set.
6902 */
6903 static void
6904f_input(typval_T *argvars, typval_T *rettv)
6905{
6906 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6907}
6908
6909/*
6910 * "inputdialog()" function
6911 */
6912 static void
6913f_inputdialog(typval_T *argvars, typval_T *rettv)
6914{
6915#if defined(FEAT_GUI_TEXTDIALOG)
6916 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6917 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6918 {
6919 char_u *message;
6920 char_u buf[NUMBUFLEN];
6921 char_u *defstr = (char_u *)"";
6922
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006923 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006925 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6927 else
6928 IObuff[0] = NUL;
6929 if (message != NULL && defstr != NULL
6930 && do_dialog(VIM_QUESTION, NULL, message,
6931 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6932 rettv->vval.v_string = vim_strsave(IObuff);
6933 else
6934 {
6935 if (message != NULL && defstr != NULL
6936 && argvars[1].v_type != VAR_UNKNOWN
6937 && argvars[2].v_type != VAR_UNKNOWN)
6938 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006939 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940 else
6941 rettv->vval.v_string = NULL;
6942 }
6943 rettv->v_type = VAR_STRING;
6944 }
6945 else
6946#endif
6947 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6948}
6949
6950/*
6951 * "inputlist()" function
6952 */
6953 static void
6954f_inputlist(typval_T *argvars, typval_T *rettv)
6955{
6956 listitem_T *li;
6957 int selected;
6958 int mouse_used;
6959
6960#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006961 /* While starting up, there is no place to enter text. When running tests
6962 * with --not-a-term we assume feedkeys() will be used. */
6963 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006964 return;
6965#endif
6966 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6967 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006968 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006969 return;
6970 }
6971
6972 msg_start();
6973 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6974 lines_left = Rows; /* avoid more prompt */
6975 msg_scroll = TRUE;
6976 msg_clr_eos();
6977
6978 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6979 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006980 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 msg_putchar('\n');
6982 }
6983
6984 /* Ask for choice. */
6985 selected = prompt_for_number(&mouse_used);
6986 if (mouse_used)
6987 selected -= lines_left;
6988
6989 rettv->vval.v_number = selected;
6990}
6991
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006992static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6993
6994/*
6995 * "inputrestore()" function
6996 */
6997 static void
6998f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6999{
7000 if (ga_userinput.ga_len > 0)
7001 {
7002 --ga_userinput.ga_len;
7003 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7004 + ga_userinput.ga_len);
7005 /* default return is zero == OK */
7006 }
7007 else if (p_verbose > 1)
7008 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007009 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 rettv->vval.v_number = 1; /* Failed */
7011 }
7012}
7013
7014/*
7015 * "inputsave()" function
7016 */
7017 static void
7018f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7019{
7020 /* Add an entry to the stack of typeahead storage. */
7021 if (ga_grow(&ga_userinput, 1) == OK)
7022 {
7023 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7024 + ga_userinput.ga_len);
7025 ++ga_userinput.ga_len;
7026 /* default return is zero == OK */
7027 }
7028 else
7029 rettv->vval.v_number = 1; /* Failed */
7030}
7031
7032/*
7033 * "inputsecret()" function
7034 */
7035 static void
7036f_inputsecret(typval_T *argvars, typval_T *rettv)
7037{
7038 ++cmdline_star;
7039 ++inputsecret_flag;
7040 f_input(argvars, rettv);
7041 --cmdline_star;
7042 --inputsecret_flag;
7043}
7044
7045/*
7046 * "insert()" function
7047 */
7048 static void
7049f_insert(typval_T *argvars, typval_T *rettv)
7050{
7051 long before = 0;
7052 listitem_T *item;
7053 list_T *l;
7054 int error = FALSE;
7055
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007056 if (argvars[0].v_type == VAR_BLOB)
7057 {
7058 int val, len;
7059 char_u *p;
7060
7061 len = blob_len(argvars[0].vval.v_blob);
7062 if (argvars[2].v_type != VAR_UNKNOWN)
7063 {
7064 before = (long)tv_get_number_chk(&argvars[2], &error);
7065 if (error)
7066 return; // type error; errmsg already given
7067 if (before < 0 || before > len)
7068 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007069 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007070 return;
7071 }
7072 }
7073 val = tv_get_number_chk(&argvars[1], &error);
7074 if (error)
7075 return;
7076 if (val < 0 || val > 255)
7077 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007078 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007079 return;
7080 }
7081
7082 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7083 return;
7084 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7085 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7086 *(p + before) = val;
7087 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7088
7089 copy_tv(&argvars[0], rettv);
7090 }
7091 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007092 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007093 else if ((l = argvars[0].vval.v_list) != NULL
7094 && !var_check_lock(l->lv_lock,
7095 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007096 {
7097 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007098 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099 if (error)
7100 return; /* type error; errmsg already given */
7101
7102 if (before == l->lv_len)
7103 item = NULL;
7104 else
7105 {
7106 item = list_find(l, before);
7107 if (item == NULL)
7108 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007109 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007110 l = NULL;
7111 }
7112 }
7113 if (l != NULL)
7114 {
7115 list_insert_tv(l, &argvars[1], item);
7116 copy_tv(&argvars[0], rettv);
7117 }
7118 }
7119}
7120
7121/*
7122 * "invert(expr)" function
7123 */
7124 static void
7125f_invert(typval_T *argvars, typval_T *rettv)
7126{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007127 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007128}
7129
7130/*
7131 * "isdirectory()" function
7132 */
7133 static void
7134f_isdirectory(typval_T *argvars, typval_T *rettv)
7135{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007136 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007137}
7138
7139/*
7140 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7141 * or it refers to a List or Dictionary that is locked.
7142 */
7143 static int
7144tv_islocked(typval_T *tv)
7145{
7146 return (tv->v_lock & VAR_LOCKED)
7147 || (tv->v_type == VAR_LIST
7148 && tv->vval.v_list != NULL
7149 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7150 || (tv->v_type == VAR_DICT
7151 && tv->vval.v_dict != NULL
7152 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7153}
7154
7155/*
7156 * "islocked()" function
7157 */
7158 static void
7159f_islocked(typval_T *argvars, typval_T *rettv)
7160{
7161 lval_T lv;
7162 char_u *end;
7163 dictitem_T *di;
7164
7165 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007166 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007167 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007168 if (end != NULL && lv.ll_name != NULL)
7169 {
7170 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007171 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 else
7173 {
7174 if (lv.ll_tv == NULL)
7175 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007176 di = find_var(lv.ll_name, NULL, TRUE);
7177 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007178 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007179 /* Consider a variable locked when:
7180 * 1. the variable itself is locked
7181 * 2. the value of the variable is locked.
7182 * 3. the List or Dict value is locked.
7183 */
7184 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7185 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 }
7187 }
7188 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007189 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007190 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007191 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007192 else if (lv.ll_list != NULL)
7193 /* List item. */
7194 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7195 else
7196 /* Dictionary item. */
7197 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7198 }
7199 }
7200
7201 clear_lval(&lv);
7202}
7203
7204#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7205/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007206 * "isinf()" function
7207 */
7208 static void
7209f_isinf(typval_T *argvars, typval_T *rettv)
7210{
7211 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7212 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7213}
7214
7215/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007216 * "isnan()" function
7217 */
7218 static void
7219f_isnan(typval_T *argvars, typval_T *rettv)
7220{
7221 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7222 && isnan(argvars[0].vval.v_float);
7223}
7224#endif
7225
7226/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007227 * "last_buffer_nr()" function.
7228 */
7229 static void
7230f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7231{
7232 int n = 0;
7233 buf_T *buf;
7234
Bram Moolenaar29323592016-07-24 22:04:11 +02007235 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 if (n < buf->b_fnum)
7237 n = buf->b_fnum;
7238
7239 rettv->vval.v_number = n;
7240}
7241
7242/*
7243 * "len()" function
7244 */
7245 static void
7246f_len(typval_T *argvars, typval_T *rettv)
7247{
7248 switch (argvars[0].v_type)
7249 {
7250 case VAR_STRING:
7251 case VAR_NUMBER:
7252 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007253 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007255 case VAR_BLOB:
7256 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7257 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 case VAR_LIST:
7259 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7260 break;
7261 case VAR_DICT:
7262 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7263 break;
7264 case VAR_UNKNOWN:
7265 case VAR_SPECIAL:
7266 case VAR_FLOAT:
7267 case VAR_FUNC:
7268 case VAR_PARTIAL:
7269 case VAR_JOB:
7270 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007271 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007272 break;
7273 }
7274}
7275
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007276 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007277libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007278{
7279#ifdef FEAT_LIBCALL
7280 char_u *string_in;
7281 char_u **string_result;
7282 int nr_result;
7283#endif
7284
7285 rettv->v_type = type;
7286 if (type != VAR_NUMBER)
7287 rettv->vval.v_string = NULL;
7288
7289 if (check_restricted() || check_secure())
7290 return;
7291
7292#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007293 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7295 {
7296 string_in = NULL;
7297 if (argvars[2].v_type == VAR_STRING)
7298 string_in = argvars[2].vval.v_string;
7299 if (type == VAR_NUMBER)
7300 string_result = NULL;
7301 else
7302 string_result = &rettv->vval.v_string;
7303 if (mch_libcall(argvars[0].vval.v_string,
7304 argvars[1].vval.v_string,
7305 string_in,
7306 argvars[2].vval.v_number,
7307 string_result,
7308 &nr_result) == OK
7309 && type == VAR_NUMBER)
7310 rettv->vval.v_number = nr_result;
7311 }
7312#endif
7313}
7314
7315/*
7316 * "libcall()" function
7317 */
7318 static void
7319f_libcall(typval_T *argvars, typval_T *rettv)
7320{
7321 libcall_common(argvars, rettv, VAR_STRING);
7322}
7323
7324/*
7325 * "libcallnr()" function
7326 */
7327 static void
7328f_libcallnr(typval_T *argvars, typval_T *rettv)
7329{
7330 libcall_common(argvars, rettv, VAR_NUMBER);
7331}
7332
7333/*
7334 * "line(string)" function
7335 */
7336 static void
7337f_line(typval_T *argvars, typval_T *rettv)
7338{
7339 linenr_T lnum = 0;
7340 pos_T *fp;
7341 int fnum;
7342
7343 fp = var2fpos(&argvars[0], TRUE, &fnum);
7344 if (fp != NULL)
7345 lnum = fp->lnum;
7346 rettv->vval.v_number = lnum;
7347}
7348
7349/*
7350 * "line2byte(lnum)" function
7351 */
7352 static void
7353f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7354{
7355#ifndef FEAT_BYTEOFF
7356 rettv->vval.v_number = -1;
7357#else
7358 linenr_T lnum;
7359
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007360 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007361 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7362 rettv->vval.v_number = -1;
7363 else
7364 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7365 if (rettv->vval.v_number >= 0)
7366 ++rettv->vval.v_number;
7367#endif
7368}
7369
7370/*
7371 * "lispindent(lnum)" function
7372 */
7373 static void
7374f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7375{
7376#ifdef FEAT_LISP
7377 pos_T pos;
7378 linenr_T lnum;
7379
7380 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007381 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7383 {
7384 curwin->w_cursor.lnum = lnum;
7385 rettv->vval.v_number = get_lisp_indent();
7386 curwin->w_cursor = pos;
7387 }
7388 else
7389#endif
7390 rettv->vval.v_number = -1;
7391}
7392
7393/*
7394 * "localtime()" function
7395 */
7396 static void
7397f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7398{
7399 rettv->vval.v_number = (varnumber_T)time(NULL);
7400}
7401
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007402 static void
7403get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7404{
7405 char_u *keys;
7406 char_u *which;
7407 char_u buf[NUMBUFLEN];
7408 char_u *keys_buf = NULL;
7409 char_u *rhs;
7410 int mode;
7411 int abbr = FALSE;
7412 int get_dict = FALSE;
7413 mapblock_T *mp;
7414 int buffer_local;
7415
7416 /* return empty string for failure */
7417 rettv->v_type = VAR_STRING;
7418 rettv->vval.v_string = NULL;
7419
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007420 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007421 if (*keys == NUL)
7422 return;
7423
7424 if (argvars[1].v_type != VAR_UNKNOWN)
7425 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007426 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 if (argvars[2].v_type != VAR_UNKNOWN)
7428 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007429 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007431 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432 }
7433 }
7434 else
7435 which = (char_u *)"";
7436 if (which == NULL)
7437 return;
7438
7439 mode = get_map_mode(&which, 0);
7440
7441 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7442 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7443 vim_free(keys_buf);
7444
7445 if (!get_dict)
7446 {
7447 /* Return a string. */
7448 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007449 {
7450 if (*rhs == NUL)
7451 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7452 else
7453 rettv->vval.v_string = str2special_save(rhs, FALSE);
7454 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455
7456 }
7457 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7458 {
7459 /* Return a dictionary. */
7460 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7461 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7462 dict_T *dict = rettv->vval.v_dict;
7463
Bram Moolenaare0be1672018-07-08 16:50:37 +02007464 dict_add_string(dict, "lhs", lhs);
7465 dict_add_string(dict, "rhs", mp->m_orig_str);
7466 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7467 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7468 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007469 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7470 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007471 dict_add_number(dict, "buffer", (long)buffer_local);
7472 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7473 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474
7475 vim_free(lhs);
7476 vim_free(mapmode);
7477 }
7478}
7479
7480#ifdef FEAT_FLOAT
7481/*
7482 * "log()" function
7483 */
7484 static void
7485f_log(typval_T *argvars, typval_T *rettv)
7486{
7487 float_T f = 0.0;
7488
7489 rettv->v_type = VAR_FLOAT;
7490 if (get_float_arg(argvars, &f) == OK)
7491 rettv->vval.v_float = log(f);
7492 else
7493 rettv->vval.v_float = 0.0;
7494}
7495
7496/*
7497 * "log10()" function
7498 */
7499 static void
7500f_log10(typval_T *argvars, typval_T *rettv)
7501{
7502 float_T f = 0.0;
7503
7504 rettv->v_type = VAR_FLOAT;
7505 if (get_float_arg(argvars, &f) == OK)
7506 rettv->vval.v_float = log10(f);
7507 else
7508 rettv->vval.v_float = 0.0;
7509}
7510#endif
7511
7512#ifdef FEAT_LUA
7513/*
7514 * "luaeval()" function
7515 */
7516 static void
7517f_luaeval(typval_T *argvars, typval_T *rettv)
7518{
7519 char_u *str;
7520 char_u buf[NUMBUFLEN];
7521
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007522 if (check_restricted() || check_secure())
7523 return;
7524
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007525 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 do_luaeval(str, argvars + 1, rettv);
7527}
7528#endif
7529
7530/*
7531 * "map()" function
7532 */
7533 static void
7534f_map(typval_T *argvars, typval_T *rettv)
7535{
7536 filter_map(argvars, rettv, TRUE);
7537}
7538
7539/*
7540 * "maparg()" function
7541 */
7542 static void
7543f_maparg(typval_T *argvars, typval_T *rettv)
7544{
7545 get_maparg(argvars, rettv, TRUE);
7546}
7547
7548/*
7549 * "mapcheck()" function
7550 */
7551 static void
7552f_mapcheck(typval_T *argvars, typval_T *rettv)
7553{
7554 get_maparg(argvars, rettv, FALSE);
7555}
7556
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007557typedef enum
7558{
7559 MATCH_END, /* matchend() */
7560 MATCH_MATCH, /* match() */
7561 MATCH_STR, /* matchstr() */
7562 MATCH_LIST, /* matchlist() */
7563 MATCH_POS /* matchstrpos() */
7564} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007565
7566 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007567find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007568{
7569 char_u *str = NULL;
7570 long len = 0;
7571 char_u *expr = NULL;
7572 char_u *pat;
7573 regmatch_T regmatch;
7574 char_u patbuf[NUMBUFLEN];
7575 char_u strbuf[NUMBUFLEN];
7576 char_u *save_cpo;
7577 long start = 0;
7578 long nth = 1;
7579 colnr_T startcol = 0;
7580 int match = 0;
7581 list_T *l = NULL;
7582 listitem_T *li = NULL;
7583 long idx = 0;
7584 char_u *tofree = NULL;
7585
7586 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7587 save_cpo = p_cpo;
7588 p_cpo = (char_u *)"";
7589
7590 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007591 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007593 /* type MATCH_LIST: return empty list when there are no matches.
7594 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595 if (rettv_list_alloc(rettv) == FAIL)
7596 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007597 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007598 && (list_append_string(rettv->vval.v_list,
7599 (char_u *)"", 0) == FAIL
7600 || list_append_number(rettv->vval.v_list,
7601 (varnumber_T)-1) == FAIL
7602 || list_append_number(rettv->vval.v_list,
7603 (varnumber_T)-1) == FAIL
7604 || list_append_number(rettv->vval.v_list,
7605 (varnumber_T)-1) == FAIL))
7606 {
7607 list_free(rettv->vval.v_list);
7608 rettv->vval.v_list = NULL;
7609 goto theend;
7610 }
7611 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007612 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613 {
7614 rettv->v_type = VAR_STRING;
7615 rettv->vval.v_string = NULL;
7616 }
7617
7618 if (argvars[0].v_type == VAR_LIST)
7619 {
7620 if ((l = argvars[0].vval.v_list) == NULL)
7621 goto theend;
7622 li = l->lv_first;
7623 }
7624 else
7625 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007626 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 len = (long)STRLEN(str);
7628 }
7629
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007630 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631 if (pat == NULL)
7632 goto theend;
7633
7634 if (argvars[2].v_type != VAR_UNKNOWN)
7635 {
7636 int error = FALSE;
7637
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007638 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007639 if (error)
7640 goto theend;
7641 if (l != NULL)
7642 {
7643 li = list_find(l, start);
7644 if (li == NULL)
7645 goto theend;
7646 idx = l->lv_idx; /* use the cached index */
7647 }
7648 else
7649 {
7650 if (start < 0)
7651 start = 0;
7652 if (start > len)
7653 goto theend;
7654 /* When "count" argument is there ignore matches before "start",
7655 * otherwise skip part of the string. Differs when pattern is "^"
7656 * or "\<". */
7657 if (argvars[3].v_type != VAR_UNKNOWN)
7658 startcol = start;
7659 else
7660 {
7661 str += start;
7662 len -= start;
7663 }
7664 }
7665
7666 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007667 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007668 if (error)
7669 goto theend;
7670 }
7671
7672 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7673 if (regmatch.regprog != NULL)
7674 {
7675 regmatch.rm_ic = p_ic;
7676
7677 for (;;)
7678 {
7679 if (l != NULL)
7680 {
7681 if (li == NULL)
7682 {
7683 match = FALSE;
7684 break;
7685 }
7686 vim_free(tofree);
7687 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7688 if (str == NULL)
7689 break;
7690 }
7691
7692 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7693
7694 if (match && --nth <= 0)
7695 break;
7696 if (l == NULL && !match)
7697 break;
7698
7699 /* Advance to just after the match. */
7700 if (l != NULL)
7701 {
7702 li = li->li_next;
7703 ++idx;
7704 }
7705 else
7706 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007707 startcol = (colnr_T)(regmatch.startp[0]
7708 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007709 if (startcol > (colnr_T)len
7710 || str + startcol <= regmatch.startp[0])
7711 {
7712 match = FALSE;
7713 break;
7714 }
7715 }
7716 }
7717
7718 if (match)
7719 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007720 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721 {
7722 listitem_T *li1 = rettv->vval.v_list->lv_first;
7723 listitem_T *li2 = li1->li_next;
7724 listitem_T *li3 = li2->li_next;
7725 listitem_T *li4 = li3->li_next;
7726
7727 vim_free(li1->li_tv.vval.v_string);
7728 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7729 (int)(regmatch.endp[0] - regmatch.startp[0]));
7730 li3->li_tv.vval.v_number =
7731 (varnumber_T)(regmatch.startp[0] - expr);
7732 li4->li_tv.vval.v_number =
7733 (varnumber_T)(regmatch.endp[0] - expr);
7734 if (l != NULL)
7735 li2->li_tv.vval.v_number = (varnumber_T)idx;
7736 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007737 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 {
7739 int i;
7740
7741 /* return list with matched string and submatches */
7742 for (i = 0; i < NSUBEXP; ++i)
7743 {
7744 if (regmatch.endp[i] == NULL)
7745 {
7746 if (list_append_string(rettv->vval.v_list,
7747 (char_u *)"", 0) == FAIL)
7748 break;
7749 }
7750 else if (list_append_string(rettv->vval.v_list,
7751 regmatch.startp[i],
7752 (int)(regmatch.endp[i] - regmatch.startp[i]))
7753 == FAIL)
7754 break;
7755 }
7756 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007757 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758 {
7759 /* return matched string */
7760 if (l != NULL)
7761 copy_tv(&li->li_tv, rettv);
7762 else
7763 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7764 (int)(regmatch.endp[0] - regmatch.startp[0]));
7765 }
7766 else if (l != NULL)
7767 rettv->vval.v_number = idx;
7768 else
7769 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007770 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007771 rettv->vval.v_number =
7772 (varnumber_T)(regmatch.startp[0] - str);
7773 else
7774 rettv->vval.v_number =
7775 (varnumber_T)(regmatch.endp[0] - str);
7776 rettv->vval.v_number += (varnumber_T)(str - expr);
7777 }
7778 }
7779 vim_regfree(regmatch.regprog);
7780 }
7781
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007782theend:
7783 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007784 /* matchstrpos() without a list: drop the second item. */
7785 listitem_remove(rettv->vval.v_list,
7786 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007787 vim_free(tofree);
7788 p_cpo = save_cpo;
7789}
7790
7791/*
7792 * "match()" function
7793 */
7794 static void
7795f_match(typval_T *argvars, typval_T *rettv)
7796{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007797 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798}
7799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007800/*
7801 * "matchend()" function
7802 */
7803 static void
7804f_matchend(typval_T *argvars, typval_T *rettv)
7805{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007806 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807}
7808
7809/*
7810 * "matchlist()" function
7811 */
7812 static void
7813f_matchlist(typval_T *argvars, typval_T *rettv)
7814{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007815 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816}
7817
7818/*
7819 * "matchstr()" function
7820 */
7821 static void
7822f_matchstr(typval_T *argvars, typval_T *rettv)
7823{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007824 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825}
7826
7827/*
7828 * "matchstrpos()" function
7829 */
7830 static void
7831f_matchstrpos(typval_T *argvars, typval_T *rettv)
7832{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007833 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007834}
7835
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007836 static void
7837max_min(typval_T *argvars, typval_T *rettv, int domax)
7838{
7839 varnumber_T n = 0;
7840 varnumber_T i;
7841 int error = FALSE;
7842
7843 if (argvars[0].v_type == VAR_LIST)
7844 {
7845 list_T *l;
7846 listitem_T *li;
7847
7848 l = argvars[0].vval.v_list;
7849 if (l != NULL)
7850 {
7851 li = l->lv_first;
7852 if (li != NULL)
7853 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007854 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855 for (;;)
7856 {
7857 li = li->li_next;
7858 if (li == NULL)
7859 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007860 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 if (domax ? i > n : i < n)
7862 n = i;
7863 }
7864 }
7865 }
7866 }
7867 else if (argvars[0].v_type == VAR_DICT)
7868 {
7869 dict_T *d;
7870 int first = TRUE;
7871 hashitem_T *hi;
7872 int todo;
7873
7874 d = argvars[0].vval.v_dict;
7875 if (d != NULL)
7876 {
7877 todo = (int)d->dv_hashtab.ht_used;
7878 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7879 {
7880 if (!HASHITEM_EMPTY(hi))
7881 {
7882 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007883 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007884 if (first)
7885 {
7886 n = i;
7887 first = FALSE;
7888 }
7889 else if (domax ? i > n : i < n)
7890 n = i;
7891 }
7892 }
7893 }
7894 }
7895 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007896 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897 rettv->vval.v_number = error ? 0 : n;
7898}
7899
7900/*
7901 * "max()" function
7902 */
7903 static void
7904f_max(typval_T *argvars, typval_T *rettv)
7905{
7906 max_min(argvars, rettv, TRUE);
7907}
7908
7909/*
7910 * "min()" function
7911 */
7912 static void
7913f_min(typval_T *argvars, typval_T *rettv)
7914{
7915 max_min(argvars, rettv, FALSE);
7916}
7917
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918/*
7919 * Create the directory in which "dir" is located, and higher levels when
7920 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007921 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007922 */
7923 static int
7924mkdir_recurse(char_u *dir, int prot)
7925{
7926 char_u *p;
7927 char_u *updir;
7928 int r = FAIL;
7929
7930 /* Get end of directory name in "dir".
7931 * We're done when it's "/" or "c:/". */
7932 p = gettail_sep(dir);
7933 if (p <= get_past_head(dir))
7934 return OK;
7935
7936 /* If the directory exists we're done. Otherwise: create it.*/
7937 updir = vim_strnsave(dir, (int)(p - dir));
7938 if (updir == NULL)
7939 return FAIL;
7940 if (mch_isdir(updir))
7941 r = OK;
7942 else if (mkdir_recurse(updir, prot) == OK)
7943 r = vim_mkdir_emsg(updir, prot);
7944 vim_free(updir);
7945 return r;
7946}
7947
7948#ifdef vim_mkdir
7949/*
7950 * "mkdir()" function
7951 */
7952 static void
7953f_mkdir(typval_T *argvars, typval_T *rettv)
7954{
7955 char_u *dir;
7956 char_u buf[NUMBUFLEN];
7957 int prot = 0755;
7958
7959 rettv->vval.v_number = FAIL;
7960 if (check_restricted() || check_secure())
7961 return;
7962
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007963 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007965 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007967 if (*gettail(dir) == NUL)
7968 /* remove trailing slashes */
7969 *gettail_sep(dir) = NUL;
7970
7971 if (argvars[1].v_type != VAR_UNKNOWN)
7972 {
7973 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007976 if (prot == -1)
7977 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007978 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007979 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007980 {
7981 if (mch_isdir(dir))
7982 {
7983 /* With the "p" flag it's OK if the dir already exists. */
7984 rettv->vval.v_number = OK;
7985 return;
7986 }
7987 mkdir_recurse(dir, prot);
7988 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007989 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007990 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991}
7992#endif
7993
7994/*
7995 * "mode()" function
7996 */
7997 static void
7998f_mode(typval_T *argvars, typval_T *rettv)
7999{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008000 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001
Bram Moolenaar612cc382018-07-29 15:34:26 +02008002 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003
8004 if (time_for_testing == 93784)
8005 {
8006 /* Testing the two-character code. */
8007 buf[0] = 'x';
8008 buf[1] = '!';
8009 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008010#ifdef FEAT_TERMINAL
8011 else if (term_use_loop())
8012 buf[0] = 't';
8013#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008014 else if (VIsual_active)
8015 {
8016 if (VIsual_select)
8017 buf[0] = VIsual_mode + 's' - 'v';
8018 else
8019 buf[0] = VIsual_mode;
8020 }
8021 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8022 || State == CONFIRM)
8023 {
8024 buf[0] = 'r';
8025 if (State == ASKMORE)
8026 buf[1] = 'm';
8027 else if (State == CONFIRM)
8028 buf[1] = '?';
8029 }
8030 else if (State == EXTERNCMD)
8031 buf[0] = '!';
8032 else if (State & INSERT)
8033 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008034 if (State & VREPLACE_FLAG)
8035 {
8036 buf[0] = 'R';
8037 buf[1] = 'v';
8038 }
8039 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008040 {
8041 if (State & REPLACE_FLAG)
8042 buf[0] = 'R';
8043 else
8044 buf[0] = 'i';
8045#ifdef FEAT_INS_EXPAND
8046 if (ins_compl_active())
8047 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008048 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008049 buf[1] = 'x';
8050#endif
8051 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008052 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008053 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054 {
8055 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008056 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008057 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008058 else if (exmode_active == EXMODE_NORMAL)
8059 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008060 }
8061 else
8062 {
8063 buf[0] = 'n';
8064 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008065 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008067 // to be able to detect force-linewise/blockwise/characterwise operations
8068 buf[2] = motion_force;
8069 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008070 else if (restart_edit == 'I' || restart_edit == 'R'
8071 || restart_edit == 'V')
8072 {
8073 buf[1] = 'i';
8074 buf[2] = restart_edit;
8075 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008076 }
8077
8078 /* Clear out the minor mode when the argument is not a non-zero number or
8079 * non-empty string. */
8080 if (!non_zero_arg(&argvars[0]))
8081 buf[1] = NUL;
8082
8083 rettv->vval.v_string = vim_strsave(buf);
8084 rettv->v_type = VAR_STRING;
8085}
8086
8087#if defined(FEAT_MZSCHEME) || defined(PROTO)
8088/*
8089 * "mzeval()" function
8090 */
8091 static void
8092f_mzeval(typval_T *argvars, typval_T *rettv)
8093{
8094 char_u *str;
8095 char_u buf[NUMBUFLEN];
8096
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008097 if (check_restricted() || check_secure())
8098 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008099 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008100 do_mzeval(str, rettv);
8101}
8102
8103 void
8104mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8105{
8106 typval_T argvars[3];
8107
8108 argvars[0].v_type = VAR_STRING;
8109 argvars[0].vval.v_string = name;
8110 copy_tv(args, &argvars[1]);
8111 argvars[2].v_type = VAR_UNKNOWN;
8112 f_call(argvars, rettv);
8113 clear_tv(&argvars[1]);
8114}
8115#endif
8116
8117/*
8118 * "nextnonblank()" function
8119 */
8120 static void
8121f_nextnonblank(typval_T *argvars, typval_T *rettv)
8122{
8123 linenr_T lnum;
8124
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008125 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008126 {
8127 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8128 {
8129 lnum = 0;
8130 break;
8131 }
8132 if (*skipwhite(ml_get(lnum)) != NUL)
8133 break;
8134 }
8135 rettv->vval.v_number = lnum;
8136}
8137
8138/*
8139 * "nr2char()" function
8140 */
8141 static void
8142f_nr2char(typval_T *argvars, typval_T *rettv)
8143{
8144 char_u buf[NUMBUFLEN];
8145
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 if (has_mbyte)
8147 {
8148 int utf8 = 0;
8149
8150 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008151 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008152 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008153 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008154 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008155 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156 }
8157 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008159 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160 buf[1] = NUL;
8161 }
8162 rettv->v_type = VAR_STRING;
8163 rettv->vval.v_string = vim_strsave(buf);
8164}
8165
8166/*
8167 * "or(expr, expr)" function
8168 */
8169 static void
8170f_or(typval_T *argvars, typval_T *rettv)
8171{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008172 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8173 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174}
8175
8176/*
8177 * "pathshorten()" function
8178 */
8179 static void
8180f_pathshorten(typval_T *argvars, typval_T *rettv)
8181{
8182 char_u *p;
8183
8184 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008185 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 if (p == NULL)
8187 rettv->vval.v_string = NULL;
8188 else
8189 {
8190 p = vim_strsave(p);
8191 rettv->vval.v_string = p;
8192 if (p != NULL)
8193 shorten_dir(p);
8194 }
8195}
8196
8197#ifdef FEAT_PERL
8198/*
8199 * "perleval()" function
8200 */
8201 static void
8202f_perleval(typval_T *argvars, typval_T *rettv)
8203{
8204 char_u *str;
8205 char_u buf[NUMBUFLEN];
8206
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008207 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008208 do_perleval(str, rettv);
8209}
8210#endif
8211
8212#ifdef FEAT_FLOAT
8213/*
8214 * "pow()" function
8215 */
8216 static void
8217f_pow(typval_T *argvars, typval_T *rettv)
8218{
8219 float_T fx = 0.0, fy = 0.0;
8220
8221 rettv->v_type = VAR_FLOAT;
8222 if (get_float_arg(argvars, &fx) == OK
8223 && get_float_arg(&argvars[1], &fy) == OK)
8224 rettv->vval.v_float = pow(fx, fy);
8225 else
8226 rettv->vval.v_float = 0.0;
8227}
8228#endif
8229
8230/*
8231 * "prevnonblank()" function
8232 */
8233 static void
8234f_prevnonblank(typval_T *argvars, typval_T *rettv)
8235{
8236 linenr_T lnum;
8237
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008238 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8240 lnum = 0;
8241 else
8242 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8243 --lnum;
8244 rettv->vval.v_number = lnum;
8245}
8246
8247/* This dummy va_list is here because:
8248 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8249 * - locally in the function results in a "used before set" warning
8250 * - using va_start() to initialize it gives "function with fixed args" error */
8251static va_list ap;
8252
8253/*
8254 * "printf()" function
8255 */
8256 static void
8257f_printf(typval_T *argvars, typval_T *rettv)
8258{
8259 char_u buf[NUMBUFLEN];
8260 int len;
8261 char_u *s;
8262 int saved_did_emsg = did_emsg;
8263 char *fmt;
8264
8265 rettv->v_type = VAR_STRING;
8266 rettv->vval.v_string = NULL;
8267
8268 /* Get the required length, allocate the buffer and do it for real. */
8269 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008270 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008271 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272 if (!did_emsg)
8273 {
8274 s = alloc(len + 1);
8275 if (s != NULL)
8276 {
8277 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008278 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8279 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008280 }
8281 }
8282 did_emsg |= saved_did_emsg;
8283}
8284
8285/*
8286 * "pumvisible()" function
8287 */
8288 static void
8289f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8290{
8291#ifdef FEAT_INS_EXPAND
8292 if (pum_visible())
8293 rettv->vval.v_number = 1;
8294#endif
8295}
8296
8297#ifdef FEAT_PYTHON3
8298/*
8299 * "py3eval()" function
8300 */
8301 static void
8302f_py3eval(typval_T *argvars, typval_T *rettv)
8303{
8304 char_u *str;
8305 char_u buf[NUMBUFLEN];
8306
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008307 if (check_restricted() || check_secure())
8308 return;
8309
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008310 if (p_pyx == 0)
8311 p_pyx = 3;
8312
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008313 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 do_py3eval(str, rettv);
8315}
8316#endif
8317
8318#ifdef FEAT_PYTHON
8319/*
8320 * "pyeval()" function
8321 */
8322 static void
8323f_pyeval(typval_T *argvars, typval_T *rettv)
8324{
8325 char_u *str;
8326 char_u buf[NUMBUFLEN];
8327
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008328 if (check_restricted() || check_secure())
8329 return;
8330
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008331 if (p_pyx == 0)
8332 p_pyx = 2;
8333
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008334 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335 do_pyeval(str, rettv);
8336}
8337#endif
8338
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008339#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8340/*
8341 * "pyxeval()" function
8342 */
8343 static void
8344f_pyxeval(typval_T *argvars, typval_T *rettv)
8345{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008346 if (check_restricted() || check_secure())
8347 return;
8348
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008349# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8350 init_pyxversion();
8351 if (p_pyx == 2)
8352 f_pyeval(argvars, rettv);
8353 else
8354 f_py3eval(argvars, rettv);
8355# elif defined(FEAT_PYTHON)
8356 f_pyeval(argvars, rettv);
8357# elif defined(FEAT_PYTHON3)
8358 f_py3eval(argvars, rettv);
8359# endif
8360}
8361#endif
8362
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008363/*
8364 * "range()" function
8365 */
8366 static void
8367f_range(typval_T *argvars, typval_T *rettv)
8368{
8369 varnumber_T start;
8370 varnumber_T end;
8371 varnumber_T stride = 1;
8372 varnumber_T i;
8373 int error = FALSE;
8374
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008375 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 if (argvars[1].v_type == VAR_UNKNOWN)
8377 {
8378 end = start - 1;
8379 start = 0;
8380 }
8381 else
8382 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008383 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008385 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 }
8387
8388 if (error)
8389 return; /* type error; errmsg already given */
8390 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008391 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008393 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 else
8395 {
8396 if (rettv_list_alloc(rettv) == OK)
8397 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8398 if (list_append_number(rettv->vval.v_list,
8399 (varnumber_T)i) == FAIL)
8400 break;
8401 }
8402}
8403
8404/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008405 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008406 */
8407 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008408readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008409{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008410 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008411 typval_T save_val;
8412 typval_T rettv;
8413 typval_T argv[2];
8414 int retval = 0;
8415 int error = FALSE;
8416
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008417 if (expr->v_type == VAR_UNKNOWN)
8418 return 1;
8419
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008420 prepare_vimvar(VV_VAL, &save_val);
8421 set_vim_var_string(VV_VAL, name, -1);
8422 argv[0].v_type = VAR_STRING;
8423 argv[0].vval.v_string = name;
8424
8425 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8426 goto theend;
8427
8428 retval = tv_get_number_chk(&rettv, &error);
8429 if (error)
8430 retval = -1;
8431 clear_tv(&rettv);
8432
8433theend:
8434 set_vim_var_string(VV_VAL, NULL, 0);
8435 restore_vimvar(VV_VAL, &save_val);
8436 return retval;
8437}
8438
8439/*
8440 * "readdir()" function
8441 */
8442 static void
8443f_readdir(typval_T *argvars, typval_T *rettv)
8444{
8445 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008446 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008447 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008448 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008449 garray_T ga;
8450 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008451
8452 if (rettv_list_alloc(rettv) == FAIL)
8453 return;
8454 path = tv_get_string(&argvars[0]);
8455 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008456
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008457 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8458 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008459 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008460 for (i = 0; i < ga.ga_len; i++)
8461 {
8462 p = ((char_u **)ga.ga_data)[i];
8463 list_append_string(rettv->vval.v_list, p, -1);
8464 }
8465 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008466 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008467}
8468
8469/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470 * "readfile()" function
8471 */
8472 static void
8473f_readfile(typval_T *argvars, typval_T *rettv)
8474{
8475 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008476 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008477 int failed = FALSE;
8478 char_u *fname;
8479 FILE *fd;
8480 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8481 int io_size = sizeof(buf);
8482 int readlen; /* size of last fread() */
8483 char_u *prev = NULL; /* previously read bytes, if any */
8484 long prevlen = 0; /* length of data in prev */
8485 long prevsize = 0; /* size of prev buffer */
8486 long maxline = MAXLNUM;
8487 long cnt = 0;
8488 char_u *p; /* position in buf */
8489 char_u *start; /* start of current line */
8490
8491 if (argvars[1].v_type != VAR_UNKNOWN)
8492 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008493 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008494 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008495 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8496 blob = TRUE;
8497
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008499 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008500 }
8501
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008502 if (blob)
8503 {
8504 if (rettv_blob_alloc(rettv) == FAIL)
8505 return;
8506 }
8507 else
8508 {
8509 if (rettv_list_alloc(rettv) == FAIL)
8510 return;
8511 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008512
8513 /* Always open the file in binary mode, library functions have a mind of
8514 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008515 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008516 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8517 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008518 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008519 return;
8520 }
8521
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008522 if (blob)
8523 {
8524 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8525 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008526 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008527 blob_free(rettv->vval.v_blob);
8528 }
8529 fclose(fd);
8530 return;
8531 }
8532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008533 while (cnt < maxline || maxline < 0)
8534 {
8535 readlen = (int)fread(buf, 1, io_size, fd);
8536
8537 /* This for loop processes what was read, but is also entered at end
8538 * of file so that either:
8539 * - an incomplete line gets written
8540 * - a "binary" file gets an empty line at the end if it ends in a
8541 * newline. */
8542 for (p = buf, start = buf;
8543 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8544 ++p)
8545 {
8546 if (*p == '\n' || readlen <= 0)
8547 {
8548 listitem_T *li;
8549 char_u *s = NULL;
8550 long_u len = p - start;
8551
8552 /* Finished a line. Remove CRs before NL. */
8553 if (readlen > 0 && !binary)
8554 {
8555 while (len > 0 && start[len - 1] == '\r')
8556 --len;
8557 /* removal may cross back to the "prev" string */
8558 if (len == 0)
8559 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8560 --prevlen;
8561 }
8562 if (prevlen == 0)
8563 s = vim_strnsave(start, (int)len);
8564 else
8565 {
8566 /* Change "prev" buffer to be the right size. This way
8567 * the bytes are only copied once, and very long lines are
8568 * allocated only once. */
8569 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8570 {
8571 mch_memmove(s + prevlen, start, len);
8572 s[prevlen + len] = NUL;
8573 prev = NULL; /* the list will own the string */
8574 prevlen = prevsize = 0;
8575 }
8576 }
8577 if (s == NULL)
8578 {
8579 do_outofmem_msg((long_u) prevlen + len + 1);
8580 failed = TRUE;
8581 break;
8582 }
8583
8584 if ((li = listitem_alloc()) == NULL)
8585 {
8586 vim_free(s);
8587 failed = TRUE;
8588 break;
8589 }
8590 li->li_tv.v_type = VAR_STRING;
8591 li->li_tv.v_lock = 0;
8592 li->li_tv.vval.v_string = s;
8593 list_append(rettv->vval.v_list, li);
8594
8595 start = p + 1; /* step over newline */
8596 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8597 break;
8598 }
8599 else if (*p == NUL)
8600 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008601 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8602 * when finding the BF and check the previous two bytes. */
8603 else if (*p == 0xbf && enc_utf8 && !binary)
8604 {
8605 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8606 * + 1, these may be in the "prev" string. */
8607 char_u back1 = p >= buf + 1 ? p[-1]
8608 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8609 char_u back2 = p >= buf + 2 ? p[-2]
8610 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8611 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8612
8613 if (back2 == 0xef && back1 == 0xbb)
8614 {
8615 char_u *dest = p - 2;
8616
8617 /* Usually a BOM is at the beginning of a file, and so at
8618 * the beginning of a line; then we can just step over it.
8619 */
8620 if (start == dest)
8621 start = p + 1;
8622 else
8623 {
8624 /* have to shuffle buf to close gap */
8625 int adjust_prevlen = 0;
8626
8627 if (dest < buf)
8628 {
8629 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8630 dest = buf;
8631 }
8632 if (readlen > p - buf + 1)
8633 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8634 readlen -= 3 - adjust_prevlen;
8635 prevlen -= adjust_prevlen;
8636 p = dest - 1;
8637 }
8638 }
8639 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008640 } /* for */
8641
8642 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8643 break;
8644 if (start < p)
8645 {
8646 /* There's part of a line in buf, store it in "prev". */
8647 if (p - start + prevlen >= prevsize)
8648 {
8649 /* need bigger "prev" buffer */
8650 char_u *newprev;
8651
8652 /* A common use case is ordinary text files and "prev" gets a
8653 * fragment of a line, so the first allocation is made
8654 * small, to avoid repeatedly 'allocing' large and
8655 * 'reallocing' small. */
8656 if (prevsize == 0)
8657 prevsize = (long)(p - start);
8658 else
8659 {
8660 long grow50pc = (prevsize * 3) / 2;
8661 long growmin = (long)((p - start) * 2 + prevlen);
8662 prevsize = grow50pc > growmin ? grow50pc : growmin;
8663 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008664 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008665 if (newprev == NULL)
8666 {
8667 do_outofmem_msg((long_u)prevsize);
8668 failed = TRUE;
8669 break;
8670 }
8671 prev = newprev;
8672 }
8673 /* Add the line part to end of "prev". */
8674 mch_memmove(prev + prevlen, start, p - start);
8675 prevlen += (long)(p - start);
8676 }
8677 } /* while */
8678
8679 /*
8680 * For a negative line count use only the lines at the end of the file,
8681 * free the rest.
8682 */
8683 if (!failed && maxline < 0)
8684 while (cnt > -maxline)
8685 {
8686 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8687 --cnt;
8688 }
8689
8690 if (failed)
8691 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008692 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008693 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008694 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695 }
8696
8697 vim_free(prev);
8698 fclose(fd);
8699}
8700
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008701 static void
8702return_register(int regname, typval_T *rettv)
8703{
8704 char_u buf[2] = {0, 0};
8705
8706 buf[0] = (char_u)regname;
8707 rettv->v_type = VAR_STRING;
8708 rettv->vval.v_string = vim_strsave(buf);
8709}
8710
8711/*
8712 * "reg_executing()" function
8713 */
8714 static void
8715f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8716{
8717 return_register(reg_executing, rettv);
8718}
8719
8720/*
8721 * "reg_recording()" function
8722 */
8723 static void
8724f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8725{
8726 return_register(reg_recording, rettv);
8727}
8728
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008729#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008730/*
8731 * Convert a List to proftime_T.
8732 * Return FAIL when there is something wrong.
8733 */
8734 static int
8735list2proftime(typval_T *arg, proftime_T *tm)
8736{
8737 long n1, n2;
8738 int error = FALSE;
8739
8740 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8741 || arg->vval.v_list->lv_len != 2)
8742 return FAIL;
8743 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8744 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008745# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746 tm->HighPart = n1;
8747 tm->LowPart = n2;
8748# else
8749 tm->tv_sec = n1;
8750 tm->tv_usec = n2;
8751# endif
8752 return error ? FAIL : OK;
8753}
8754#endif /* FEAT_RELTIME */
8755
8756/*
8757 * "reltime()" function
8758 */
8759 static void
8760f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8761{
8762#ifdef FEAT_RELTIME
8763 proftime_T res;
8764 proftime_T start;
8765
8766 if (argvars[0].v_type == VAR_UNKNOWN)
8767 {
8768 /* No arguments: get current time. */
8769 profile_start(&res);
8770 }
8771 else if (argvars[1].v_type == VAR_UNKNOWN)
8772 {
8773 if (list2proftime(&argvars[0], &res) == FAIL)
8774 return;
8775 profile_end(&res);
8776 }
8777 else
8778 {
8779 /* Two arguments: compute the difference. */
8780 if (list2proftime(&argvars[0], &start) == FAIL
8781 || list2proftime(&argvars[1], &res) == FAIL)
8782 return;
8783 profile_sub(&res, &start);
8784 }
8785
8786 if (rettv_list_alloc(rettv) == OK)
8787 {
8788 long n1, n2;
8789
Bram Moolenaar4f974752019-02-17 17:44:42 +01008790# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008791 n1 = res.HighPart;
8792 n2 = res.LowPart;
8793# else
8794 n1 = res.tv_sec;
8795 n2 = res.tv_usec;
8796# endif
8797 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8798 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8799 }
8800#endif
8801}
8802
8803#ifdef FEAT_FLOAT
8804/*
8805 * "reltimefloat()" function
8806 */
8807 static void
8808f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8809{
8810# ifdef FEAT_RELTIME
8811 proftime_T tm;
8812# endif
8813
8814 rettv->v_type = VAR_FLOAT;
8815 rettv->vval.v_float = 0;
8816# ifdef FEAT_RELTIME
8817 if (list2proftime(&argvars[0], &tm) == OK)
8818 rettv->vval.v_float = profile_float(&tm);
8819# endif
8820}
8821#endif
8822
8823/*
8824 * "reltimestr()" function
8825 */
8826 static void
8827f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8828{
8829#ifdef FEAT_RELTIME
8830 proftime_T tm;
8831#endif
8832
8833 rettv->v_type = VAR_STRING;
8834 rettv->vval.v_string = NULL;
8835#ifdef FEAT_RELTIME
8836 if (list2proftime(&argvars[0], &tm) == OK)
8837 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8838#endif
8839}
8840
8841#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008842 static void
8843make_connection(void)
8844{
8845 if (X_DISPLAY == NULL
8846# ifdef FEAT_GUI
8847 && !gui.in_use
8848# endif
8849 )
8850 {
8851 x_force_connect = TRUE;
8852 setup_term_clip();
8853 x_force_connect = FALSE;
8854 }
8855}
8856
8857 static int
8858check_connection(void)
8859{
8860 make_connection();
8861 if (X_DISPLAY == NULL)
8862 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008863 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008864 return FAIL;
8865 }
8866 return OK;
8867}
8868#endif
8869
8870#ifdef FEAT_CLIENTSERVER
8871 static void
8872remote_common(typval_T *argvars, typval_T *rettv, int expr)
8873{
8874 char_u *server_name;
8875 char_u *keys;
8876 char_u *r = NULL;
8877 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008878 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008879# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880 HWND w;
8881# else
8882 Window w;
8883# endif
8884
8885 if (check_restricted() || check_secure())
8886 return;
8887
8888# ifdef FEAT_X11
8889 if (check_connection() == FAIL)
8890 return;
8891# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008892 if (argvars[2].v_type != VAR_UNKNOWN
8893 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008894 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008896 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008897 if (server_name == NULL)
8898 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008899 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008900# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008901 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008903 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8904 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008905# endif
8906 {
8907 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008908 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008909 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008910 vim_free(r);
8911 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008912 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008913 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008914 return;
8915 }
8916
8917 rettv->vval.v_string = r;
8918
8919 if (argvars[2].v_type != VAR_UNKNOWN)
8920 {
8921 dictitem_T v;
8922 char_u str[30];
8923 char_u *idvar;
8924
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008925 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008926 if (idvar != NULL && *idvar != NUL)
8927 {
8928 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8929 v.di_tv.v_type = VAR_STRING;
8930 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008931 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008932 vim_free(v.di_tv.vval.v_string);
8933 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008934 }
8935}
8936#endif
8937
8938/*
8939 * "remote_expr()" function
8940 */
8941 static void
8942f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8943{
8944 rettv->v_type = VAR_STRING;
8945 rettv->vval.v_string = NULL;
8946#ifdef FEAT_CLIENTSERVER
8947 remote_common(argvars, rettv, TRUE);
8948#endif
8949}
8950
8951/*
8952 * "remote_foreground()" function
8953 */
8954 static void
8955f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8956{
8957#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008958# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008959 /* On Win32 it's done in this application. */
8960 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008961 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008962
8963 if (server_name != NULL)
8964 serverForeground(server_name);
8965 }
8966# else
8967 /* Send a foreground() expression to the server. */
8968 argvars[1].v_type = VAR_STRING;
8969 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8970 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008971 rettv->v_type = VAR_STRING;
8972 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008973 remote_common(argvars, rettv, TRUE);
8974 vim_free(argvars[1].vval.v_string);
8975# endif
8976#endif
8977}
8978
8979 static void
8980f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8981{
8982#ifdef FEAT_CLIENTSERVER
8983 dictitem_T v;
8984 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008985# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008986 long_u n = 0;
8987# endif
8988 char_u *serverid;
8989
8990 if (check_restricted() || check_secure())
8991 {
8992 rettv->vval.v_number = -1;
8993 return;
8994 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008995 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008996 if (serverid == NULL)
8997 {
8998 rettv->vval.v_number = -1;
8999 return; /* type error; errmsg already given */
9000 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009001# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009002 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9003 if (n == 0)
9004 rettv->vval.v_number = -1;
9005 else
9006 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009007 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009008 rettv->vval.v_number = (s != NULL);
9009 }
9010# else
9011 if (check_connection() == FAIL)
9012 return;
9013
9014 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9015 serverStrToWin(serverid), &s);
9016# endif
9017
9018 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9019 {
9020 char_u *retvar;
9021
9022 v.di_tv.v_type = VAR_STRING;
9023 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009024 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009025 if (retvar != NULL)
9026 set_var(retvar, &v.di_tv, FALSE);
9027 vim_free(v.di_tv.vval.v_string);
9028 }
9029#else
9030 rettv->vval.v_number = -1;
9031#endif
9032}
9033
9034 static void
9035f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9036{
9037 char_u *r = NULL;
9038
9039#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009040 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009041
9042 if (serverid != NULL && !check_restricted() && !check_secure())
9043 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009044 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009045# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009046 /* The server's HWND is encoded in the 'id' parameter */
9047 long_u n = 0;
9048# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009049
9050 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009051 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009052
Bram Moolenaar4f974752019-02-17 17:44:42 +01009053# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009054 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9055 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009056 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009057 if (r == NULL)
9058# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009059 if (check_connection() == FAIL
9060 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9061 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009062# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009063 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009064 }
9065#endif
9066 rettv->v_type = VAR_STRING;
9067 rettv->vval.v_string = r;
9068}
9069
9070/*
9071 * "remote_send()" function
9072 */
9073 static void
9074f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9075{
9076 rettv->v_type = VAR_STRING;
9077 rettv->vval.v_string = NULL;
9078#ifdef FEAT_CLIENTSERVER
9079 remote_common(argvars, rettv, FALSE);
9080#endif
9081}
9082
9083/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009084 * "remote_startserver()" function
9085 */
9086 static void
9087f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9088{
9089#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009090 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009091
9092 if (server == NULL)
9093 return; /* type error; errmsg already given */
9094 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009095 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009096 else
9097 {
9098# ifdef FEAT_X11
9099 if (check_connection() == OK)
9100 serverRegisterName(X_DISPLAY, server);
9101# else
9102 serverSetName(server);
9103# endif
9104 }
9105#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009106 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009107#endif
9108}
9109
9110/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009111 * "remove()" function
9112 */
9113 static void
9114f_remove(typval_T *argvars, typval_T *rettv)
9115{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009116 char_u *arg_errmsg = (char_u *)N_("remove() argument");
9117
9118 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009119 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009120 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02009121 blob_remove(argvars, rettv);
9122 else if (argvars[0].v_type == VAR_LIST)
9123 list_remove(argvars, rettv, arg_errmsg);
9124 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009125 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009126}
9127
9128/*
9129 * "rename({from}, {to})" function
9130 */
9131 static void
9132f_rename(typval_T *argvars, typval_T *rettv)
9133{
9134 char_u buf[NUMBUFLEN];
9135
9136 if (check_restricted() || check_secure())
9137 rettv->vval.v_number = -1;
9138 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009139 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9140 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009141}
9142
9143/*
9144 * "repeat()" function
9145 */
9146 static void
9147f_repeat(typval_T *argvars, typval_T *rettv)
9148{
9149 char_u *p;
9150 int n;
9151 int slen;
9152 int len;
9153 char_u *r;
9154 int i;
9155
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009156 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009157 if (argvars[0].v_type == VAR_LIST)
9158 {
9159 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9160 while (n-- > 0)
9161 if (list_extend(rettv->vval.v_list,
9162 argvars[0].vval.v_list, NULL) == FAIL)
9163 break;
9164 }
9165 else
9166 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009167 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009168 rettv->v_type = VAR_STRING;
9169 rettv->vval.v_string = NULL;
9170
9171 slen = (int)STRLEN(p);
9172 len = slen * n;
9173 if (len <= 0)
9174 return;
9175
9176 r = alloc(len + 1);
9177 if (r != NULL)
9178 {
9179 for (i = 0; i < n; i++)
9180 mch_memmove(r + i * slen, p, (size_t)slen);
9181 r[len] = NUL;
9182 }
9183
9184 rettv->vval.v_string = r;
9185 }
9186}
9187
9188/*
9189 * "resolve()" function
9190 */
9191 static void
9192f_resolve(typval_T *argvars, typval_T *rettv)
9193{
9194 char_u *p;
9195#ifdef HAVE_READLINK
9196 char_u *buf = NULL;
9197#endif
9198
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009199 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009200#ifdef FEAT_SHORTCUT
9201 {
9202 char_u *v = NULL;
9203
Bram Moolenaardce1e892019-02-10 23:18:53 +01009204 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009205 if (v != NULL)
9206 rettv->vval.v_string = v;
9207 else
9208 rettv->vval.v_string = vim_strsave(p);
9209 }
9210#else
9211# ifdef HAVE_READLINK
9212 {
9213 char_u *cpy;
9214 int len;
9215 char_u *remain = NULL;
9216 char_u *q;
9217 int is_relative_to_current = FALSE;
9218 int has_trailing_pathsep = FALSE;
9219 int limit = 100;
9220
9221 p = vim_strsave(p);
9222
9223 if (p[0] == '.' && (vim_ispathsep(p[1])
9224 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9225 is_relative_to_current = TRUE;
9226
9227 len = STRLEN(p);
9228 if (len > 0 && after_pathsep(p, p + len))
9229 {
9230 has_trailing_pathsep = TRUE;
9231 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9232 }
9233
9234 q = getnextcomp(p);
9235 if (*q != NUL)
9236 {
9237 /* Separate the first path component in "p", and keep the
9238 * remainder (beginning with the path separator). */
9239 remain = vim_strsave(q - 1);
9240 q[-1] = NUL;
9241 }
9242
9243 buf = alloc(MAXPATHL + 1);
9244 if (buf == NULL)
9245 goto fail;
9246
9247 for (;;)
9248 {
9249 for (;;)
9250 {
9251 len = readlink((char *)p, (char *)buf, MAXPATHL);
9252 if (len <= 0)
9253 break;
9254 buf[len] = NUL;
9255
9256 if (limit-- == 0)
9257 {
9258 vim_free(p);
9259 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009260 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009261 rettv->vval.v_string = NULL;
9262 goto fail;
9263 }
9264
9265 /* Ensure that the result will have a trailing path separator
9266 * if the argument has one. */
9267 if (remain == NULL && has_trailing_pathsep)
9268 add_pathsep(buf);
9269
9270 /* Separate the first path component in the link value and
9271 * concatenate the remainders. */
9272 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9273 if (*q != NUL)
9274 {
9275 if (remain == NULL)
9276 remain = vim_strsave(q - 1);
9277 else
9278 {
9279 cpy = concat_str(q - 1, remain);
9280 if (cpy != NULL)
9281 {
9282 vim_free(remain);
9283 remain = cpy;
9284 }
9285 }
9286 q[-1] = NUL;
9287 }
9288
9289 q = gettail(p);
9290 if (q > p && *q == NUL)
9291 {
9292 /* Ignore trailing path separator. */
9293 q[-1] = NUL;
9294 q = gettail(p);
9295 }
9296 if (q > p && !mch_isFullName(buf))
9297 {
9298 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009299 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009300 if (cpy != NULL)
9301 {
9302 STRCPY(cpy, p);
9303 STRCPY(gettail(cpy), buf);
9304 vim_free(p);
9305 p = cpy;
9306 }
9307 }
9308 else
9309 {
9310 vim_free(p);
9311 p = vim_strsave(buf);
9312 }
9313 }
9314
9315 if (remain == NULL)
9316 break;
9317
9318 /* Append the first path component of "remain" to "p". */
9319 q = getnextcomp(remain + 1);
9320 len = q - remain - (*q != NUL);
9321 cpy = vim_strnsave(p, STRLEN(p) + len);
9322 if (cpy != NULL)
9323 {
9324 STRNCAT(cpy, remain, len);
9325 vim_free(p);
9326 p = cpy;
9327 }
9328 /* Shorten "remain". */
9329 if (*q != NUL)
9330 STRMOVE(remain, q - 1);
9331 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009332 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333 }
9334
9335 /* If the result is a relative path name, make it explicitly relative to
9336 * the current directory if and only if the argument had this form. */
9337 if (!vim_ispathsep(*p))
9338 {
9339 if (is_relative_to_current
9340 && *p != NUL
9341 && !(p[0] == '.'
9342 && (p[1] == NUL
9343 || vim_ispathsep(p[1])
9344 || (p[1] == '.'
9345 && (p[2] == NUL
9346 || vim_ispathsep(p[2]))))))
9347 {
9348 /* Prepend "./". */
9349 cpy = concat_str((char_u *)"./", p);
9350 if (cpy != NULL)
9351 {
9352 vim_free(p);
9353 p = cpy;
9354 }
9355 }
9356 else if (!is_relative_to_current)
9357 {
9358 /* Strip leading "./". */
9359 q = p;
9360 while (q[0] == '.' && vim_ispathsep(q[1]))
9361 q += 2;
9362 if (q > p)
9363 STRMOVE(p, p + 2);
9364 }
9365 }
9366
9367 /* Ensure that the result will have no trailing path separator
9368 * if the argument had none. But keep "/" or "//". */
9369 if (!has_trailing_pathsep)
9370 {
9371 q = p + STRLEN(p);
9372 if (after_pathsep(p, q))
9373 *gettail_sep(p) = NUL;
9374 }
9375
9376 rettv->vval.v_string = p;
9377 }
9378# else
9379 rettv->vval.v_string = vim_strsave(p);
9380# endif
9381#endif
9382
9383 simplify_filename(rettv->vval.v_string);
9384
9385#ifdef HAVE_READLINK
9386fail:
9387 vim_free(buf);
9388#endif
9389 rettv->v_type = VAR_STRING;
9390}
9391
9392/*
9393 * "reverse({list})" function
9394 */
9395 static void
9396f_reverse(typval_T *argvars, typval_T *rettv)
9397{
9398 list_T *l;
9399 listitem_T *li, *ni;
9400
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009401 if (argvars[0].v_type == VAR_BLOB)
9402 {
9403 blob_T *b = argvars[0].vval.v_blob;
9404 int i, len = blob_len(b);
9405
9406 for (i = 0; i < len / 2; i++)
9407 {
9408 int tmp = blob_get(b, i);
9409
9410 blob_set(b, i, blob_get(b, len - i - 1));
9411 blob_set(b, len - i - 1, tmp);
9412 }
9413 rettv_blob_set(rettv, b);
9414 return;
9415 }
9416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009417 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009418 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009419 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009420 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009421 (char_u *)N_("reverse() argument"), TRUE))
9422 {
9423 li = l->lv_last;
9424 l->lv_first = l->lv_last = NULL;
9425 l->lv_len = 0;
9426 while (li != NULL)
9427 {
9428 ni = li->li_prev;
9429 list_append(l, li);
9430 li = ni;
9431 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009432 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009433 l->lv_idx = l->lv_len - l->lv_idx - 1;
9434 }
9435}
9436
9437#define SP_NOMOVE 0x01 /* don't move cursor */
9438#define SP_REPEAT 0x02 /* repeat to find outer pair */
9439#define SP_RETCOUNT 0x04 /* return matchcount */
9440#define SP_SETPCMARK 0x08 /* set previous context mark */
9441#define SP_START 0x10 /* accept match at start position */
9442#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9443#define SP_END 0x40 /* leave cursor at end of match */
9444#define SP_COLUMN 0x80 /* start at cursor column */
9445
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009446/*
9447 * Get flags for a search function.
9448 * Possibly sets "p_ws".
9449 * Returns BACKWARD, FORWARD or zero (for an error).
9450 */
9451 static int
9452get_search_arg(typval_T *varp, int *flagsp)
9453{
9454 int dir = FORWARD;
9455 char_u *flags;
9456 char_u nbuf[NUMBUFLEN];
9457 int mask;
9458
9459 if (varp->v_type != VAR_UNKNOWN)
9460 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009461 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009462 if (flags == NULL)
9463 return 0; /* type error; errmsg already given */
9464 while (*flags != NUL)
9465 {
9466 switch (*flags)
9467 {
9468 case 'b': dir = BACKWARD; break;
9469 case 'w': p_ws = TRUE; break;
9470 case 'W': p_ws = FALSE; break;
9471 default: mask = 0;
9472 if (flagsp != NULL)
9473 switch (*flags)
9474 {
9475 case 'c': mask = SP_START; break;
9476 case 'e': mask = SP_END; break;
9477 case 'm': mask = SP_RETCOUNT; break;
9478 case 'n': mask = SP_NOMOVE; break;
9479 case 'p': mask = SP_SUBPAT; break;
9480 case 'r': mask = SP_REPEAT; break;
9481 case 's': mask = SP_SETPCMARK; break;
9482 case 'z': mask = SP_COLUMN; break;
9483 }
9484 if (mask == 0)
9485 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009486 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 dir = 0;
9488 }
9489 else
9490 *flagsp |= mask;
9491 }
9492 if (dir == 0)
9493 break;
9494 ++flags;
9495 }
9496 }
9497 return dir;
9498}
9499
9500/*
9501 * Shared by search() and searchpos() functions.
9502 */
9503 static int
9504search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9505{
9506 int flags;
9507 char_u *pat;
9508 pos_T pos;
9509 pos_T save_cursor;
9510 int save_p_ws = p_ws;
9511 int dir;
9512 int retval = 0; /* default: FAIL */
9513 long lnum_stop = 0;
9514 proftime_T tm;
9515#ifdef FEAT_RELTIME
9516 long time_limit = 0;
9517#endif
9518 int options = SEARCH_KEEP;
9519 int subpatnum;
9520
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009521 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009522 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9523 if (dir == 0)
9524 goto theend;
9525 flags = *flagsp;
9526 if (flags & SP_START)
9527 options |= SEARCH_START;
9528 if (flags & SP_END)
9529 options |= SEARCH_END;
9530 if (flags & SP_COLUMN)
9531 options |= SEARCH_COL;
9532
9533 /* Optional arguments: line number to stop searching and timeout. */
9534 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9535 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009536 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009537 if (lnum_stop < 0)
9538 goto theend;
9539#ifdef FEAT_RELTIME
9540 if (argvars[3].v_type != VAR_UNKNOWN)
9541 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009542 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009543 if (time_limit < 0)
9544 goto theend;
9545 }
9546#endif
9547 }
9548
9549#ifdef FEAT_RELTIME
9550 /* Set the time limit, if there is one. */
9551 profile_setlimit(time_limit, &tm);
9552#endif
9553
9554 /*
9555 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9556 * Check to make sure only those flags are set.
9557 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9558 * flags cannot be set. Check for that condition also.
9559 */
9560 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9561 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9562 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009563 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009564 goto theend;
9565 }
9566
9567 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009568 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009569 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009570 if (subpatnum != FAIL)
9571 {
9572 if (flags & SP_SUBPAT)
9573 retval = subpatnum;
9574 else
9575 retval = pos.lnum;
9576 if (flags & SP_SETPCMARK)
9577 setpcmark();
9578 curwin->w_cursor = pos;
9579 if (match_pos != NULL)
9580 {
9581 /* Store the match cursor position */
9582 match_pos->lnum = pos.lnum;
9583 match_pos->col = pos.col + 1;
9584 }
9585 /* "/$" will put the cursor after the end of the line, may need to
9586 * correct that here */
9587 check_cursor();
9588 }
9589
9590 /* If 'n' flag is used: restore cursor position. */
9591 if (flags & SP_NOMOVE)
9592 curwin->w_cursor = save_cursor;
9593 else
9594 curwin->w_set_curswant = TRUE;
9595theend:
9596 p_ws = save_p_ws;
9597
9598 return retval;
9599}
9600
9601#ifdef FEAT_FLOAT
9602
9603/*
9604 * round() is not in C90, use ceil() or floor() instead.
9605 */
9606 float_T
9607vim_round(float_T f)
9608{
9609 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9610}
9611
9612/*
9613 * "round({float})" function
9614 */
9615 static void
9616f_round(typval_T *argvars, typval_T *rettv)
9617{
9618 float_T f = 0.0;
9619
9620 rettv->v_type = VAR_FLOAT;
9621 if (get_float_arg(argvars, &f) == OK)
9622 rettv->vval.v_float = vim_round(f);
9623 else
9624 rettv->vval.v_float = 0.0;
9625}
9626#endif
9627
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009628#ifdef FEAT_RUBY
9629/*
9630 * "rubyeval()" function
9631 */
9632 static void
9633f_rubyeval(typval_T *argvars, typval_T *rettv)
9634{
9635 char_u *str;
9636 char_u buf[NUMBUFLEN];
9637
9638 str = tv_get_string_buf(&argvars[0], buf);
9639 do_rubyeval(str, rettv);
9640}
9641#endif
9642
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009643/*
9644 * "screenattr()" function
9645 */
9646 static void
9647f_screenattr(typval_T *argvars, typval_T *rettv)
9648{
9649 int row;
9650 int col;
9651 int c;
9652
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009653 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9654 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009655 if (row < 0 || row >= screen_Rows
9656 || col < 0 || col >= screen_Columns)
9657 c = -1;
9658 else
9659 c = ScreenAttrs[LineOffset[row] + col];
9660 rettv->vval.v_number = c;
9661}
9662
9663/*
9664 * "screenchar()" function
9665 */
9666 static void
9667f_screenchar(typval_T *argvars, typval_T *rettv)
9668{
9669 int row;
9670 int col;
9671 int off;
9672 int c;
9673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009674 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9675 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009676 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009677 c = -1;
9678 else
9679 {
9680 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009681 if (enc_utf8 && ScreenLinesUC[off] != 0)
9682 c = ScreenLinesUC[off];
9683 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009684 c = ScreenLines[off];
9685 }
9686 rettv->vval.v_number = c;
9687}
9688
9689/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009690 * "screenchars()" function
9691 */
9692 static void
9693f_screenchars(typval_T *argvars, typval_T *rettv)
9694{
9695 int row;
9696 int col;
9697 int off;
9698 int c;
9699 int i;
9700
9701 if (rettv_list_alloc(rettv) == FAIL)
9702 return;
9703 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9704 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9705 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9706 return;
9707
9708 off = LineOffset[row] + col;
9709 if (enc_utf8 && ScreenLinesUC[off] != 0)
9710 c = ScreenLinesUC[off];
9711 else
9712 c = ScreenLines[off];
9713 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9714
9715 if (enc_utf8)
9716
9717 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9718 list_append_number(rettv->vval.v_list,
9719 (varnumber_T)ScreenLinesC[i][off]);
9720}
9721
9722/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009723 * "screencol()" function
9724 *
9725 * First column is 1 to be consistent with virtcol().
9726 */
9727 static void
9728f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9729{
9730 rettv->vval.v_number = screen_screencol() + 1;
9731}
9732
9733/*
9734 * "screenrow()" function
9735 */
9736 static void
9737f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9738{
9739 rettv->vval.v_number = screen_screenrow() + 1;
9740}
9741
9742/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009743 * "screenstring()" function
9744 */
9745 static void
9746f_screenstring(typval_T *argvars, typval_T *rettv)
9747{
9748 int row;
9749 int col;
9750 int off;
9751 int c;
9752 int i;
9753 char_u buf[MB_MAXBYTES + 1];
9754 int buflen = 0;
9755
9756 rettv->vval.v_string = NULL;
9757 rettv->v_type = VAR_STRING;
9758
9759 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9760 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9761 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9762 return;
9763
9764 off = LineOffset[row] + col;
9765 if (enc_utf8 && ScreenLinesUC[off] != 0)
9766 c = ScreenLinesUC[off];
9767 else
9768 c = ScreenLines[off];
9769 buflen += mb_char2bytes(c, buf);
9770
9771 if (enc_utf8)
9772 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9773 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9774
9775 buf[buflen] = NUL;
9776 rettv->vval.v_string = vim_strsave(buf);
9777}
9778
9779/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009780 * "search()" function
9781 */
9782 static void
9783f_search(typval_T *argvars, typval_T *rettv)
9784{
9785 int flags = 0;
9786
9787 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9788}
9789
9790/*
9791 * "searchdecl()" function
9792 */
9793 static void
9794f_searchdecl(typval_T *argvars, typval_T *rettv)
9795{
9796 int locally = 1;
9797 int thisblock = 0;
9798 int error = FALSE;
9799 char_u *name;
9800
9801 rettv->vval.v_number = 1; /* default: FAIL */
9802
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009803 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009804 if (argvars[1].v_type != VAR_UNKNOWN)
9805 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009806 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009807 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009808 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 }
9810 if (!error && name != NULL)
9811 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9812 locally, thisblock, SEARCH_KEEP) == FAIL;
9813}
9814
9815/*
9816 * Used by searchpair() and searchpairpos()
9817 */
9818 static int
9819searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9820{
9821 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009822 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009823 int save_p_ws = p_ws;
9824 int dir;
9825 int flags = 0;
9826 char_u nbuf1[NUMBUFLEN];
9827 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009828 int retval = 0; /* default: FAIL */
9829 long lnum_stop = 0;
9830 long time_limit = 0;
9831
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009832 /* Get the three pattern arguments: start, middle, end. Will result in an
9833 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009834 spat = tv_get_string_chk(&argvars[0]);
9835 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9836 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009837 if (spat == NULL || mpat == NULL || epat == NULL)
9838 goto theend; /* type error */
9839
9840 /* Handle the optional fourth argument: flags */
9841 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9842 if (dir == 0)
9843 goto theend;
9844
9845 /* Don't accept SP_END or SP_SUBPAT.
9846 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9847 */
9848 if ((flags & (SP_END | SP_SUBPAT)) != 0
9849 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9850 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009851 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009852 goto theend;
9853 }
9854
9855 /* Using 'r' implies 'W', otherwise it doesn't work. */
9856 if (flags & SP_REPEAT)
9857 p_ws = FALSE;
9858
9859 /* Optional fifth argument: skip expression */
9860 if (argvars[3].v_type == VAR_UNKNOWN
9861 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009862 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009863 else
9864 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009865 skip = &argvars[4];
9866 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9867 && skip->v_type != VAR_STRING)
9868 {
9869 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009870 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009871 goto theend;
9872 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009873 if (argvars[5].v_type != VAR_UNKNOWN)
9874 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009875 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009876 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009877 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009878 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009879 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009880 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009881#ifdef FEAT_RELTIME
9882 if (argvars[6].v_type != VAR_UNKNOWN)
9883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009884 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009885 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009886 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009887 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009888 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009889 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009890 }
9891#endif
9892 }
9893 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009894
9895 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9896 match_pos, lnum_stop, time_limit);
9897
9898theend:
9899 p_ws = save_p_ws;
9900
9901 return retval;
9902}
9903
9904/*
9905 * "searchpair()" function
9906 */
9907 static void
9908f_searchpair(typval_T *argvars, typval_T *rettv)
9909{
9910 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9911}
9912
9913/*
9914 * "searchpairpos()" function
9915 */
9916 static void
9917f_searchpairpos(typval_T *argvars, typval_T *rettv)
9918{
9919 pos_T match_pos;
9920 int lnum = 0;
9921 int col = 0;
9922
9923 if (rettv_list_alloc(rettv) == FAIL)
9924 return;
9925
9926 if (searchpair_cmn(argvars, &match_pos) > 0)
9927 {
9928 lnum = match_pos.lnum;
9929 col = match_pos.col;
9930 }
9931
9932 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9933 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9934}
9935
9936/*
9937 * Search for a start/middle/end thing.
9938 * Used by searchpair(), see its documentation for the details.
9939 * Returns 0 or -1 for no match,
9940 */
9941 long
9942do_searchpair(
9943 char_u *spat, /* start pattern */
9944 char_u *mpat, /* middle pattern */
9945 char_u *epat, /* end pattern */
9946 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009947 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009948 int flags, /* SP_SETPCMARK and other SP_ values */
9949 pos_T *match_pos,
9950 linenr_T lnum_stop, /* stop at this line if not zero */
9951 long time_limit UNUSED) /* stop after this many msec */
9952{
9953 char_u *save_cpo;
9954 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9955 long retval = 0;
9956 pos_T pos;
9957 pos_T firstpos;
9958 pos_T foundpos;
9959 pos_T save_cursor;
9960 pos_T save_pos;
9961 int n;
9962 int r;
9963 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009964 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009965 int err;
9966 int options = SEARCH_KEEP;
9967 proftime_T tm;
9968
9969 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9970 save_cpo = p_cpo;
9971 p_cpo = empty_option;
9972
9973#ifdef FEAT_RELTIME
9974 /* Set the time limit, if there is one. */
9975 profile_setlimit(time_limit, &tm);
9976#endif
9977
9978 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9979 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009980 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9981 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009982 if (pat2 == NULL || pat3 == NULL)
9983 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009984 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009985 if (*mpat == NUL)
9986 STRCPY(pat3, pat2);
9987 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009988 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009989 spat, epat, mpat);
9990 if (flags & SP_START)
9991 options |= SEARCH_START;
9992
Bram Moolenaar48570482017-10-30 21:48:41 +01009993 if (skip != NULL)
9994 {
9995 /* Empty string means to not use the skip expression. */
9996 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9997 use_skip = skip->vval.v_string != NULL
9998 && *skip->vval.v_string != NUL;
9999 }
10000
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010001 save_cursor = curwin->w_cursor;
10002 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010003 CLEAR_POS(&firstpos);
10004 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010005 pat = pat3;
10006 for (;;)
10007 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010008 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010009 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010010 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010011 /* didn't find it or found the first match again: FAIL */
10012 break;
10013
10014 if (firstpos.lnum == 0)
10015 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010016 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010017 {
10018 /* Found the same position again. Can happen with a pattern that
10019 * has "\zs" at the end and searching backwards. Advance one
10020 * character and try again. */
10021 if (dir == BACKWARD)
10022 decl(&pos);
10023 else
10024 incl(&pos);
10025 }
10026 foundpos = pos;
10027
10028 /* clear the start flag to avoid getting stuck here */
10029 options &= ~SEARCH_START;
10030
10031 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010032 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010033 {
10034 save_pos = curwin->w_cursor;
10035 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010036 err = FALSE;
10037 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010038 curwin->w_cursor = save_pos;
10039 if (err)
10040 {
10041 /* Evaluating {skip} caused an error, break here. */
10042 curwin->w_cursor = save_cursor;
10043 retval = -1;
10044 break;
10045 }
10046 if (r)
10047 continue;
10048 }
10049
10050 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10051 {
10052 /* Found end when searching backwards or start when searching
10053 * forward: nested pair. */
10054 ++nest;
10055 pat = pat2; /* nested, don't search for middle */
10056 }
10057 else
10058 {
10059 /* Found end when searching forward or start when searching
10060 * backward: end of (nested) pair; or found middle in outer pair. */
10061 if (--nest == 1)
10062 pat = pat3; /* outer level, search for middle */
10063 }
10064
10065 if (nest == 0)
10066 {
10067 /* Found the match: return matchcount or line number. */
10068 if (flags & SP_RETCOUNT)
10069 ++retval;
10070 else
10071 retval = pos.lnum;
10072 if (flags & SP_SETPCMARK)
10073 setpcmark();
10074 curwin->w_cursor = pos;
10075 if (!(flags & SP_REPEAT))
10076 break;
10077 nest = 1; /* search for next unmatched */
10078 }
10079 }
10080
10081 if (match_pos != NULL)
10082 {
10083 /* Store the match cursor position */
10084 match_pos->lnum = curwin->w_cursor.lnum;
10085 match_pos->col = curwin->w_cursor.col + 1;
10086 }
10087
10088 /* If 'n' flag is used or search failed: restore cursor position. */
10089 if ((flags & SP_NOMOVE) || retval == 0)
10090 curwin->w_cursor = save_cursor;
10091
10092theend:
10093 vim_free(pat2);
10094 vim_free(pat3);
10095 if (p_cpo == empty_option)
10096 p_cpo = save_cpo;
10097 else
10098 /* Darn, evaluating the {skip} expression changed the value. */
10099 free_string_option(save_cpo);
10100
10101 return retval;
10102}
10103
10104/*
10105 * "searchpos()" function
10106 */
10107 static void
10108f_searchpos(typval_T *argvars, typval_T *rettv)
10109{
10110 pos_T match_pos;
10111 int lnum = 0;
10112 int col = 0;
10113 int n;
10114 int flags = 0;
10115
10116 if (rettv_list_alloc(rettv) == FAIL)
10117 return;
10118
10119 n = search_cmn(argvars, &match_pos, &flags);
10120 if (n > 0)
10121 {
10122 lnum = match_pos.lnum;
10123 col = match_pos.col;
10124 }
10125
10126 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10127 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10128 if (flags & SP_SUBPAT)
10129 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10130}
10131
10132 static void
10133f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10134{
10135#ifdef FEAT_CLIENTSERVER
10136 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010137 char_u *server = tv_get_string_chk(&argvars[0]);
10138 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010139
10140 rettv->vval.v_number = -1;
10141 if (server == NULL || reply == NULL)
10142 return;
10143 if (check_restricted() || check_secure())
10144 return;
10145# ifdef FEAT_X11
10146 if (check_connection() == FAIL)
10147 return;
10148# endif
10149
10150 if (serverSendReply(server, reply) < 0)
10151 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010152 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010153 return;
10154 }
10155 rettv->vval.v_number = 0;
10156#else
10157 rettv->vval.v_number = -1;
10158#endif
10159}
10160
10161 static void
10162f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10163{
10164 char_u *r = NULL;
10165
10166#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010167# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010168 r = serverGetVimNames();
10169# else
10170 make_connection();
10171 if (X_DISPLAY != NULL)
10172 r = serverGetVimNames(X_DISPLAY);
10173# endif
10174#endif
10175 rettv->v_type = VAR_STRING;
10176 rettv->vval.v_string = r;
10177}
10178
10179/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010180 * "setbufline()" function
10181 */
10182 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010183f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010184{
10185 linenr_T lnum;
10186 buf_T *buf;
10187
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010188 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010189 if (buf == NULL)
10190 rettv->vval.v_number = 1; /* FAIL */
10191 else
10192 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010193 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010194 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010195 }
10196}
10197
10198/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010199 * "setbufvar()" function
10200 */
10201 static void
10202f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10203{
10204 buf_T *buf;
10205 char_u *varname, *bufvarname;
10206 typval_T *varp;
10207 char_u nbuf[NUMBUFLEN];
10208
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010209 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010210 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010211 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10212 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010213 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010214 varp = &argvars[2];
10215
10216 if (buf != NULL && varname != NULL && varp != NULL)
10217 {
10218 if (*varname == '&')
10219 {
10220 long numval;
10221 char_u *strval;
10222 int error = FALSE;
10223 aco_save_T aco;
10224
10225 /* set curbuf to be our buf, temporarily */
10226 aucmd_prepbuf(&aco, buf);
10227
10228 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010229 numval = (long)tv_get_number_chk(varp, &error);
10230 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010231 if (!error && strval != NULL)
10232 set_option_value(varname, numval, strval, OPT_LOCAL);
10233
10234 /* reset notion of buffer */
10235 aucmd_restbuf(&aco);
10236 }
10237 else
10238 {
10239 buf_T *save_curbuf = curbuf;
10240
Bram Moolenaar964b3742019-05-24 18:54:09 +020010241 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010242 if (bufvarname != NULL)
10243 {
10244 curbuf = buf;
10245 STRCPY(bufvarname, "b:");
10246 STRCPY(bufvarname + 2, varname);
10247 set_var(bufvarname, varp, TRUE);
10248 vim_free(bufvarname);
10249 curbuf = save_curbuf;
10250 }
10251 }
10252 }
10253}
10254
10255 static void
10256f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10257{
10258 dict_T *d;
10259 dictitem_T *di;
10260 char_u *csearch;
10261
10262 if (argvars[0].v_type != VAR_DICT)
10263 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010264 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010265 return;
10266 }
10267
10268 if ((d = argvars[0].vval.v_dict) != NULL)
10269 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010270 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 if (csearch != NULL)
10272 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010273 if (enc_utf8)
10274 {
10275 int pcc[MAX_MCO];
10276 int c = utfc_ptr2char(csearch, pcc);
10277
10278 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10279 }
10280 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010281 set_last_csearch(PTR2CHAR(csearch),
10282 csearch, MB_PTR2LEN(csearch));
10283 }
10284
10285 di = dict_find(d, (char_u *)"forward", -1);
10286 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010287 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010288 ? FORWARD : BACKWARD);
10289
10290 di = dict_find(d, (char_u *)"until", -1);
10291 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010292 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010293 }
10294}
10295
10296/*
10297 * "setcmdpos()" function
10298 */
10299 static void
10300f_setcmdpos(typval_T *argvars, typval_T *rettv)
10301{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010302 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010303
10304 if (pos >= 0)
10305 rettv->vval.v_number = set_cmdline_pos(pos);
10306}
10307
10308/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010309 * "setenv()" function
10310 */
10311 static void
10312f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10313{
10314 char_u namebuf[NUMBUFLEN];
10315 char_u valbuf[NUMBUFLEN];
10316 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10317
10318 if (argvars[1].v_type == VAR_SPECIAL
10319 && argvars[1].vval.v_number == VVAL_NULL)
10320 vim_unsetenv(name);
10321 else
10322 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10323}
10324
10325/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010326 * "setfperm({fname}, {mode})" function
10327 */
10328 static void
10329f_setfperm(typval_T *argvars, typval_T *rettv)
10330{
10331 char_u *fname;
10332 char_u modebuf[NUMBUFLEN];
10333 char_u *mode_str;
10334 int i;
10335 int mask;
10336 int mode = 0;
10337
10338 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010339 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010340 if (fname == NULL)
10341 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010342 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010343 if (mode_str == NULL)
10344 return;
10345 if (STRLEN(mode_str) != 9)
10346 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010347 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010348 return;
10349 }
10350
10351 mask = 1;
10352 for (i = 8; i >= 0; --i)
10353 {
10354 if (mode_str[i] != '-')
10355 mode |= mask;
10356 mask = mask << 1;
10357 }
10358 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10359}
10360
10361/*
10362 * "setline()" function
10363 */
10364 static void
10365f_setline(typval_T *argvars, typval_T *rettv)
10366{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010367 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010368
Bram Moolenaarca851592018-06-06 21:04:07 +020010369 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010370}
10371
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010372/*
10373 * Used by "setqflist()" and "setloclist()" functions
10374 */
10375 static void
10376set_qf_ll_list(
10377 win_T *wp UNUSED,
10378 typval_T *list_arg UNUSED,
10379 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010380 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010381 typval_T *rettv)
10382{
10383#ifdef FEAT_QUICKFIX
10384 static char *e_invact = N_("E927: Invalid action: '%s'");
10385 char_u *act;
10386 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010387 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010388#endif
10389
10390 rettv->vval.v_number = -1;
10391
10392#ifdef FEAT_QUICKFIX
10393 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010394 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010395 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010396 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010397 else
10398 {
10399 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010400 dict_T *d = NULL;
10401 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010402
10403 if (action_arg->v_type == VAR_STRING)
10404 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010405 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010406 if (act == NULL)
10407 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010408 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10409 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010410 action = *act;
10411 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010412 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010413 }
10414 else if (action_arg->v_type == VAR_UNKNOWN)
10415 action = ' ';
10416 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010417 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010418
Bram Moolenaard823fa92016-08-12 16:29:27 +020010419 if (action_arg->v_type != VAR_UNKNOWN
10420 && what_arg->v_type != VAR_UNKNOWN)
10421 {
10422 if (what_arg->v_type == VAR_DICT)
10423 d = what_arg->vval.v_dict;
10424 else
10425 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010426 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010427 valid_dict = FALSE;
10428 }
10429 }
10430
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010431 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010432 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010433 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10434 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010435 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010436 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010437 }
10438#endif
10439}
10440
10441/*
10442 * "setloclist()" function
10443 */
10444 static void
10445f_setloclist(typval_T *argvars, typval_T *rettv)
10446{
10447 win_T *win;
10448
10449 rettv->vval.v_number = -1;
10450
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010451 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010452 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010453 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010454}
10455
10456/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010457 * "setpos()" function
10458 */
10459 static void
10460f_setpos(typval_T *argvars, typval_T *rettv)
10461{
10462 pos_T pos;
10463 int fnum;
10464 char_u *name;
10465 colnr_T curswant = -1;
10466
10467 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010468 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010469 if (name != NULL)
10470 {
10471 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10472 {
10473 if (--pos.col < 0)
10474 pos.col = 0;
10475 if (name[0] == '.' && name[1] == NUL)
10476 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010477 /* set cursor; "fnum" is ignored */
10478 curwin->w_cursor = pos;
10479 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010480 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010481 curwin->w_curswant = curswant - 1;
10482 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010483 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010484 check_cursor();
10485 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010486 }
10487 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10488 {
10489 /* set mark */
10490 if (setmark_pos(name[1], &pos, fnum) == OK)
10491 rettv->vval.v_number = 0;
10492 }
10493 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010494 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010495 }
10496 }
10497}
10498
10499/*
10500 * "setqflist()" function
10501 */
10502 static void
10503f_setqflist(typval_T *argvars, typval_T *rettv)
10504{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010505 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010506}
10507
10508/*
10509 * "setreg()" function
10510 */
10511 static void
10512f_setreg(typval_T *argvars, typval_T *rettv)
10513{
10514 int regname;
10515 char_u *strregname;
10516 char_u *stropt;
10517 char_u *strval;
10518 int append;
10519 char_u yank_type;
10520 long block_len;
10521
10522 block_len = -1;
10523 yank_type = MAUTO;
10524 append = FALSE;
10525
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010526 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010527 rettv->vval.v_number = 1; /* FAIL is default */
10528
10529 if (strregname == NULL)
10530 return; /* type error; errmsg already given */
10531 regname = *strregname;
10532 if (regname == 0 || regname == '@')
10533 regname = '"';
10534
10535 if (argvars[2].v_type != VAR_UNKNOWN)
10536 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010537 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010538 if (stropt == NULL)
10539 return; /* type error */
10540 for (; *stropt != NUL; ++stropt)
10541 switch (*stropt)
10542 {
10543 case 'a': case 'A': /* append */
10544 append = TRUE;
10545 break;
10546 case 'v': case 'c': /* character-wise selection */
10547 yank_type = MCHAR;
10548 break;
10549 case 'V': case 'l': /* line-wise selection */
10550 yank_type = MLINE;
10551 break;
10552 case 'b': case Ctrl_V: /* block-wise selection */
10553 yank_type = MBLOCK;
10554 if (VIM_ISDIGIT(stropt[1]))
10555 {
10556 ++stropt;
10557 block_len = getdigits(&stropt) - 1;
10558 --stropt;
10559 }
10560 break;
10561 }
10562 }
10563
10564 if (argvars[1].v_type == VAR_LIST)
10565 {
10566 char_u **lstval;
10567 char_u **allocval;
10568 char_u buf[NUMBUFLEN];
10569 char_u **curval;
10570 char_u **curallocval;
10571 list_T *ll = argvars[1].vval.v_list;
10572 listitem_T *li;
10573 int len;
10574
10575 /* If the list is NULL handle like an empty list. */
10576 len = ll == NULL ? 0 : ll->lv_len;
10577
10578 /* First half: use for pointers to result lines; second half: use for
10579 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010580 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010581 if (lstval == NULL)
10582 return;
10583 curval = lstval;
10584 allocval = lstval + len + 2;
10585 curallocval = allocval;
10586
10587 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10588 li = li->li_next)
10589 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010590 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010591 if (strval == NULL)
10592 goto free_lstval;
10593 if (strval == buf)
10594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010595 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010596 * overwrite the string. */
10597 strval = vim_strsave(buf);
10598 if (strval == NULL)
10599 goto free_lstval;
10600 *curallocval++ = strval;
10601 }
10602 *curval++ = strval;
10603 }
10604 *curval++ = NULL;
10605
10606 write_reg_contents_lst(regname, lstval, -1,
10607 append, yank_type, block_len);
10608free_lstval:
10609 while (curallocval > allocval)
10610 vim_free(*--curallocval);
10611 vim_free(lstval);
10612 }
10613 else
10614 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010615 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010616 if (strval == NULL)
10617 return;
10618 write_reg_contents_ex(regname, strval, -1,
10619 append, yank_type, block_len);
10620 }
10621 rettv->vval.v_number = 0;
10622}
10623
10624/*
10625 * "settabvar()" function
10626 */
10627 static void
10628f_settabvar(typval_T *argvars, typval_T *rettv)
10629{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010630 tabpage_T *save_curtab;
10631 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010632 char_u *varname, *tabvarname;
10633 typval_T *varp;
10634
10635 rettv->vval.v_number = 0;
10636
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010637 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010638 return;
10639
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010640 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10641 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010642 varp = &argvars[2];
10643
Bram Moolenaar4033c552017-09-16 20:54:51 +020010644 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010645 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010646 save_curtab = curtab;
10647 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010648
Bram Moolenaar964b3742019-05-24 18:54:09 +020010649 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010650 if (tabvarname != NULL)
10651 {
10652 STRCPY(tabvarname, "t:");
10653 STRCPY(tabvarname + 2, varname);
10654 set_var(tabvarname, varp, TRUE);
10655 vim_free(tabvarname);
10656 }
10657
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010658 /* Restore current tabpage */
10659 if (valid_tabpage(save_curtab))
10660 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010661 }
10662}
10663
10664/*
10665 * "settabwinvar()" function
10666 */
10667 static void
10668f_settabwinvar(typval_T *argvars, typval_T *rettv)
10669{
10670 setwinvar(argvars, rettv, 1);
10671}
10672
10673/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010674 * "settagstack()" function
10675 */
10676 static void
10677f_settagstack(typval_T *argvars, typval_T *rettv)
10678{
10679 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10680 win_T *wp;
10681 dict_T *d;
10682 int action = 'r';
10683
10684 rettv->vval.v_number = -1;
10685
10686 // first argument: window number or id
10687 wp = find_win_by_nr_or_id(&argvars[0]);
10688 if (wp == NULL)
10689 return;
10690
10691 // second argument: dict with items to set in the tag stack
10692 if (argvars[1].v_type != VAR_DICT)
10693 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010694 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010695 return;
10696 }
10697 d = argvars[1].vval.v_dict;
10698 if (d == NULL)
10699 return;
10700
10701 // third argument: action - 'a' for append and 'r' for replace.
10702 // default is to replace the stack.
10703 if (argvars[2].v_type == VAR_UNKNOWN)
10704 action = 'r';
10705 else if (argvars[2].v_type == VAR_STRING)
10706 {
10707 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010708 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010709 if (actstr == NULL)
10710 return;
10711 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10712 action = *actstr;
10713 else
10714 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010715 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010716 return;
10717 }
10718 }
10719 else
10720 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010721 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010722 return;
10723 }
10724
10725 if (set_tagstack(wp, d, action) == OK)
10726 rettv->vval.v_number = 0;
10727}
10728
10729/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010730 * "setwinvar()" function
10731 */
10732 static void
10733f_setwinvar(typval_T *argvars, typval_T *rettv)
10734{
10735 setwinvar(argvars, rettv, 0);
10736}
10737
10738#ifdef FEAT_CRYPT
10739/*
10740 * "sha256({string})" function
10741 */
10742 static void
10743f_sha256(typval_T *argvars, typval_T *rettv)
10744{
10745 char_u *p;
10746
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010747 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010748 rettv->vval.v_string = vim_strsave(
10749 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10750 rettv->v_type = VAR_STRING;
10751}
10752#endif /* FEAT_CRYPT */
10753
10754/*
10755 * "shellescape({string})" function
10756 */
10757 static void
10758f_shellescape(typval_T *argvars, typval_T *rettv)
10759{
Bram Moolenaar20615522017-06-05 18:46:26 +020010760 int do_special = non_zero_arg(&argvars[1]);
10761
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010762 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010763 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010764 rettv->v_type = VAR_STRING;
10765}
10766
10767/*
10768 * shiftwidth() function
10769 */
10770 static void
10771f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10772{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010773 rettv->vval.v_number = 0;
10774
10775 if (argvars[0].v_type != VAR_UNKNOWN)
10776 {
10777 long col;
10778
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010779 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010780 if (col < 0)
10781 return; // type error; errmsg already given
10782#ifdef FEAT_VARTABS
10783 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10784 return;
10785#endif
10786 }
10787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010788 rettv->vval.v_number = get_sw_value(curbuf);
10789}
10790
10791/*
10792 * "simplify()" function
10793 */
10794 static void
10795f_simplify(typval_T *argvars, typval_T *rettv)
10796{
10797 char_u *p;
10798
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010799 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010800 rettv->vval.v_string = vim_strsave(p);
10801 simplify_filename(rettv->vval.v_string); /* simplify in place */
10802 rettv->v_type = VAR_STRING;
10803}
10804
10805#ifdef FEAT_FLOAT
10806/*
10807 * "sin()" function
10808 */
10809 static void
10810f_sin(typval_T *argvars, typval_T *rettv)
10811{
10812 float_T f = 0.0;
10813
10814 rettv->v_type = VAR_FLOAT;
10815 if (get_float_arg(argvars, &f) == OK)
10816 rettv->vval.v_float = sin(f);
10817 else
10818 rettv->vval.v_float = 0.0;
10819}
10820
10821/*
10822 * "sinh()" function
10823 */
10824 static void
10825f_sinh(typval_T *argvars, typval_T *rettv)
10826{
10827 float_T f = 0.0;
10828
10829 rettv->v_type = VAR_FLOAT;
10830 if (get_float_arg(argvars, &f) == OK)
10831 rettv->vval.v_float = sinh(f);
10832 else
10833 rettv->vval.v_float = 0.0;
10834}
10835#endif
10836
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010837/*
10838 * "soundfold({word})" function
10839 */
10840 static void
10841f_soundfold(typval_T *argvars, typval_T *rettv)
10842{
10843 char_u *s;
10844
10845 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010846 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010847#ifdef FEAT_SPELL
10848 rettv->vval.v_string = eval_soundfold(s);
10849#else
10850 rettv->vval.v_string = vim_strsave(s);
10851#endif
10852}
10853
10854/*
10855 * "spellbadword()" function
10856 */
10857 static void
10858f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10859{
10860 char_u *word = (char_u *)"";
10861 hlf_T attr = HLF_COUNT;
10862 int len = 0;
10863
10864 if (rettv_list_alloc(rettv) == FAIL)
10865 return;
10866
10867#ifdef FEAT_SPELL
10868 if (argvars[0].v_type == VAR_UNKNOWN)
10869 {
10870 /* Find the start and length of the badly spelled word. */
10871 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10872 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010873 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010874 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010875 curwin->w_set_curswant = TRUE;
10876 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010877 }
10878 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10879 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010880 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010881 int capcol = -1;
10882
10883 if (str != NULL)
10884 {
10885 /* Check the argument for spelling. */
10886 while (*str != NUL)
10887 {
10888 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10889 if (attr != HLF_COUNT)
10890 {
10891 word = str;
10892 break;
10893 }
10894 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010895 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010896 }
10897 }
10898 }
10899#endif
10900
10901 list_append_string(rettv->vval.v_list, word, len);
10902 list_append_string(rettv->vval.v_list, (char_u *)(
10903 attr == HLF_SPB ? "bad" :
10904 attr == HLF_SPR ? "rare" :
10905 attr == HLF_SPL ? "local" :
10906 attr == HLF_SPC ? "caps" :
10907 ""), -1);
10908}
10909
10910/*
10911 * "spellsuggest()" function
10912 */
10913 static void
10914f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10915{
10916#ifdef FEAT_SPELL
10917 char_u *str;
10918 int typeerr = FALSE;
10919 int maxcount;
10920 garray_T ga;
10921 int i;
10922 listitem_T *li;
10923 int need_capital = FALSE;
10924#endif
10925
10926 if (rettv_list_alloc(rettv) == FAIL)
10927 return;
10928
10929#ifdef FEAT_SPELL
10930 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010932 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010933 if (argvars[1].v_type != VAR_UNKNOWN)
10934 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010935 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010936 if (maxcount <= 0)
10937 return;
10938 if (argvars[2].v_type != VAR_UNKNOWN)
10939 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010940 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010941 if (typeerr)
10942 return;
10943 }
10944 }
10945 else
10946 maxcount = 25;
10947
10948 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10949
10950 for (i = 0; i < ga.ga_len; ++i)
10951 {
10952 str = ((char_u **)ga.ga_data)[i];
10953
10954 li = listitem_alloc();
10955 if (li == NULL)
10956 vim_free(str);
10957 else
10958 {
10959 li->li_tv.v_type = VAR_STRING;
10960 li->li_tv.v_lock = 0;
10961 li->li_tv.vval.v_string = str;
10962 list_append(rettv->vval.v_list, li);
10963 }
10964 }
10965 ga_clear(&ga);
10966 }
10967#endif
10968}
10969
10970 static void
10971f_split(typval_T *argvars, typval_T *rettv)
10972{
10973 char_u *str;
10974 char_u *end;
10975 char_u *pat = NULL;
10976 regmatch_T regmatch;
10977 char_u patbuf[NUMBUFLEN];
10978 char_u *save_cpo;
10979 int match;
10980 colnr_T col = 0;
10981 int keepempty = FALSE;
10982 int typeerr = FALSE;
10983
10984 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10985 save_cpo = p_cpo;
10986 p_cpo = (char_u *)"";
10987
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010988 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010989 if (argvars[1].v_type != VAR_UNKNOWN)
10990 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010991 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010992 if (pat == NULL)
10993 typeerr = TRUE;
10994 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010995 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010996 }
10997 if (pat == NULL || *pat == NUL)
10998 pat = (char_u *)"[\\x01- ]\\+";
10999
11000 if (rettv_list_alloc(rettv) == FAIL)
11001 return;
11002 if (typeerr)
11003 return;
11004
11005 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11006 if (regmatch.regprog != NULL)
11007 {
11008 regmatch.rm_ic = FALSE;
11009 while (*str != NUL || keepempty)
11010 {
11011 if (*str == NUL)
11012 match = FALSE; /* empty item at the end */
11013 else
11014 match = vim_regexec_nl(&regmatch, str, col);
11015 if (match)
11016 end = regmatch.startp[0];
11017 else
11018 end = str + STRLEN(str);
11019 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
11020 && *str != NUL && match && end < regmatch.endp[0]))
11021 {
11022 if (list_append_string(rettv->vval.v_list, str,
11023 (int)(end - str)) == FAIL)
11024 break;
11025 }
11026 if (!match)
11027 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010011028 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011029 if (regmatch.endp[0] > str)
11030 col = 0;
11031 else
Bram Moolenaar13505972019-01-24 15:04:48 +010011032 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011033 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011034 str = regmatch.endp[0];
11035 }
11036
11037 vim_regfree(regmatch.regprog);
11038 }
11039
11040 p_cpo = save_cpo;
11041}
11042
11043#ifdef FEAT_FLOAT
11044/*
11045 * "sqrt()" function
11046 */
11047 static void
11048f_sqrt(typval_T *argvars, typval_T *rettv)
11049{
11050 float_T f = 0.0;
11051
11052 rettv->v_type = VAR_FLOAT;
11053 if (get_float_arg(argvars, &f) == OK)
11054 rettv->vval.v_float = sqrt(f);
11055 else
11056 rettv->vval.v_float = 0.0;
11057}
11058
11059/*
11060 * "str2float()" function
11061 */
11062 static void
11063f_str2float(typval_T *argvars, typval_T *rettv)
11064{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011065 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011066 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011067
Bram Moolenaar08243d22017-01-10 16:12:29 +010011068 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011069 p = skipwhite(p + 1);
11070 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010011071 if (isneg)
11072 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011073 rettv->v_type = VAR_FLOAT;
11074}
11075#endif
11076
11077/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020011078 * "str2list()" function
11079 */
11080 static void
11081f_str2list(typval_T *argvars, typval_T *rettv)
11082{
11083 char_u *p;
11084 int utf8 = FALSE;
11085
11086 if (rettv_list_alloc(rettv) == FAIL)
11087 return;
11088
11089 if (argvars[1].v_type != VAR_UNKNOWN)
11090 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
11091
11092 p = tv_get_string(&argvars[0]);
11093
11094 if (has_mbyte || utf8)
11095 {
11096 int (*ptr2len)(char_u *);
11097 int (*ptr2char)(char_u *);
11098
11099 if (utf8 || enc_utf8)
11100 {
11101 ptr2len = utf_ptr2len;
11102 ptr2char = utf_ptr2char;
11103 }
11104 else
11105 {
11106 ptr2len = mb_ptr2len;
11107 ptr2char = mb_ptr2char;
11108 }
11109
11110 for ( ; *p != NUL; p += (*ptr2len)(p))
11111 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
11112 }
11113 else
11114 for ( ; *p != NUL; ++p)
11115 list_append_number(rettv->vval.v_list, *p);
11116}
11117
11118/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011119 * "str2nr()" function
11120 */
11121 static void
11122f_str2nr(typval_T *argvars, typval_T *rettv)
11123{
11124 int base = 10;
11125 char_u *p;
11126 varnumber_T n;
11127 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010011128 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011129
11130 if (argvars[1].v_type != VAR_UNKNOWN)
11131 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011132 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011133 if (base != 2 && base != 8 && base != 10 && base != 16)
11134 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011135 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011136 return;
11137 }
11138 }
11139
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011140 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010011141 isneg = (*p == '-');
11142 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011143 p = skipwhite(p + 1);
11144 switch (base)
11145 {
11146 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
11147 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
11148 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
11149 default: what = 0;
11150 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020011151 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
11152 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010011153 if (isneg)
11154 rettv->vval.v_number = -n;
11155 else
11156 rettv->vval.v_number = n;
11157
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011158}
11159
11160#ifdef HAVE_STRFTIME
11161/*
11162 * "strftime({format}[, {time}])" function
11163 */
11164 static void
11165f_strftime(typval_T *argvars, typval_T *rettv)
11166{
11167 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020011168 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011169 struct tm *curtime;
11170 time_t seconds;
11171 char_u *p;
11172
11173 rettv->v_type = VAR_STRING;
11174
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011175 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011176 if (argvars[1].v_type == VAR_UNKNOWN)
11177 seconds = time(NULL);
11178 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011179 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020011180 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011181 /* MSVC returns NULL for an invalid value of seconds. */
11182 if (curtime == NULL)
11183 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
11184 else
11185 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011186 vimconv_T conv;
11187 char_u *enc;
11188
11189 conv.vc_type = CONV_NONE;
11190 enc = enc_locale();
11191 convert_setup(&conv, p_enc, enc);
11192 if (conv.vc_type != CONV_NONE)
11193 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011194 if (p != NULL)
11195 (void)strftime((char *)result_buf, sizeof(result_buf),
11196 (char *)p, curtime);
11197 else
11198 result_buf[0] = NUL;
11199
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011200 if (conv.vc_type != CONV_NONE)
11201 vim_free(p);
11202 convert_setup(&conv, enc, p_enc);
11203 if (conv.vc_type != CONV_NONE)
11204 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
11205 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011206 rettv->vval.v_string = vim_strsave(result_buf);
11207
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011208 /* Release conversion descriptors */
11209 convert_setup(&conv, NULL, NULL);
11210 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011211 }
11212}
11213#endif
11214
11215/*
11216 * "strgetchar()" function
11217 */
11218 static void
11219f_strgetchar(typval_T *argvars, typval_T *rettv)
11220{
11221 char_u *str;
11222 int len;
11223 int error = FALSE;
11224 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011225 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011226
11227 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011228 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011229 if (str == NULL)
11230 return;
11231 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011232 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011233 if (error)
11234 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011235
Bram Moolenaar13505972019-01-24 15:04:48 +010011236 while (charidx >= 0 && byteidx < len)
11237 {
11238 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011239 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011240 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11241 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011242 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011243 --charidx;
11244 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011245 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011246}
11247
11248/*
11249 * "stridx()" function
11250 */
11251 static void
11252f_stridx(typval_T *argvars, typval_T *rettv)
11253{
11254 char_u buf[NUMBUFLEN];
11255 char_u *needle;
11256 char_u *haystack;
11257 char_u *save_haystack;
11258 char_u *pos;
11259 int start_idx;
11260
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011261 needle = tv_get_string_chk(&argvars[1]);
11262 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011263 rettv->vval.v_number = -1;
11264 if (needle == NULL || haystack == NULL)
11265 return; /* type error; errmsg already given */
11266
11267 if (argvars[2].v_type != VAR_UNKNOWN)
11268 {
11269 int error = FALSE;
11270
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011271 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011272 if (error || start_idx >= (int)STRLEN(haystack))
11273 return;
11274 if (start_idx >= 0)
11275 haystack += start_idx;
11276 }
11277
11278 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11279 if (pos != NULL)
11280 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11281}
11282
11283/*
11284 * "string()" function
11285 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011286 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011287f_string(typval_T *argvars, typval_T *rettv)
11288{
11289 char_u *tofree;
11290 char_u numbuf[NUMBUFLEN];
11291
11292 rettv->v_type = VAR_STRING;
11293 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11294 get_copyID());
11295 /* Make a copy if we have a value but it's not in allocated memory. */
11296 if (rettv->vval.v_string != NULL && tofree == NULL)
11297 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11298}
11299
11300/*
11301 * "strlen()" function
11302 */
11303 static void
11304f_strlen(typval_T *argvars, typval_T *rettv)
11305{
11306 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011307 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011308}
11309
11310/*
11311 * "strchars()" function
11312 */
11313 static void
11314f_strchars(typval_T *argvars, typval_T *rettv)
11315{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011316 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011317 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011318 varnumber_T len = 0;
11319 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011320
11321 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011322 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011323 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011324 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011325 else
11326 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011327 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11328 while (*s != NUL)
11329 {
11330 func_mb_ptr2char_adv(&s);
11331 ++len;
11332 }
11333 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011334 }
11335}
11336
11337/*
11338 * "strdisplaywidth()" function
11339 */
11340 static void
11341f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11342{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011343 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011344 int col = 0;
11345
11346 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011347 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348
11349 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11350}
11351
11352/*
11353 * "strwidth()" function
11354 */
11355 static void
11356f_strwidth(typval_T *argvars, typval_T *rettv)
11357{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011358 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011359
Bram Moolenaar13505972019-01-24 15:04:48 +010011360 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011361}
11362
11363/*
11364 * "strcharpart()" function
11365 */
11366 static void
11367f_strcharpart(typval_T *argvars, typval_T *rettv)
11368{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011369 char_u *p;
11370 int nchar;
11371 int nbyte = 0;
11372 int charlen;
11373 int len = 0;
11374 int slen;
11375 int error = FALSE;
11376
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011377 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011378 slen = (int)STRLEN(p);
11379
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011380 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011381 if (!error)
11382 {
11383 if (nchar > 0)
11384 while (nchar > 0 && nbyte < slen)
11385 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011386 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011387 --nchar;
11388 }
11389 else
11390 nbyte = nchar;
11391 if (argvars[2].v_type != VAR_UNKNOWN)
11392 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011393 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011394 while (charlen > 0 && nbyte + len < slen)
11395 {
11396 int off = nbyte + len;
11397
11398 if (off < 0)
11399 len += 1;
11400 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011401 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011402 --charlen;
11403 }
11404 }
11405 else
11406 len = slen - nbyte; /* default: all bytes that are available. */
11407 }
11408
11409 /*
11410 * Only return the overlap between the specified part and the actual
11411 * string.
11412 */
11413 if (nbyte < 0)
11414 {
11415 len += nbyte;
11416 nbyte = 0;
11417 }
11418 else if (nbyte > slen)
11419 nbyte = slen;
11420 if (len < 0)
11421 len = 0;
11422 else if (nbyte + len > slen)
11423 len = slen - nbyte;
11424
11425 rettv->v_type = VAR_STRING;
11426 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011427}
11428
11429/*
11430 * "strpart()" function
11431 */
11432 static void
11433f_strpart(typval_T *argvars, typval_T *rettv)
11434{
11435 char_u *p;
11436 int n;
11437 int len;
11438 int slen;
11439 int error = FALSE;
11440
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011441 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011442 slen = (int)STRLEN(p);
11443
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011444 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011445 if (error)
11446 len = 0;
11447 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011448 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011449 else
11450 len = slen - n; /* default len: all bytes that are available. */
11451
11452 /*
11453 * Only return the overlap between the specified part and the actual
11454 * string.
11455 */
11456 if (n < 0)
11457 {
11458 len += n;
11459 n = 0;
11460 }
11461 else if (n > slen)
11462 n = slen;
11463 if (len < 0)
11464 len = 0;
11465 else if (n + len > slen)
11466 len = slen - n;
11467
11468 rettv->v_type = VAR_STRING;
11469 rettv->vval.v_string = vim_strnsave(p + n, len);
11470}
11471
11472/*
11473 * "strridx()" function
11474 */
11475 static void
11476f_strridx(typval_T *argvars, typval_T *rettv)
11477{
11478 char_u buf[NUMBUFLEN];
11479 char_u *needle;
11480 char_u *haystack;
11481 char_u *rest;
11482 char_u *lastmatch = NULL;
11483 int haystack_len, end_idx;
11484
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011485 needle = tv_get_string_chk(&argvars[1]);
11486 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011487
11488 rettv->vval.v_number = -1;
11489 if (needle == NULL || haystack == NULL)
11490 return; /* type error; errmsg already given */
11491
11492 haystack_len = (int)STRLEN(haystack);
11493 if (argvars[2].v_type != VAR_UNKNOWN)
11494 {
11495 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011496 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011497 if (end_idx < 0)
11498 return; /* can never find a match */
11499 }
11500 else
11501 end_idx = haystack_len;
11502
11503 if (*needle == NUL)
11504 {
11505 /* Empty string matches past the end. */
11506 lastmatch = haystack + end_idx;
11507 }
11508 else
11509 {
11510 for (rest = haystack; *rest != '\0'; ++rest)
11511 {
11512 rest = (char_u *)strstr((char *)rest, (char *)needle);
11513 if (rest == NULL || rest > haystack + end_idx)
11514 break;
11515 lastmatch = rest;
11516 }
11517 }
11518
11519 if (lastmatch == NULL)
11520 rettv->vval.v_number = -1;
11521 else
11522 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11523}
11524
11525/*
11526 * "strtrans()" function
11527 */
11528 static void
11529f_strtrans(typval_T *argvars, typval_T *rettv)
11530{
11531 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011532 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011533}
11534
11535/*
11536 * "submatch()" function
11537 */
11538 static void
11539f_submatch(typval_T *argvars, typval_T *rettv)
11540{
11541 int error = FALSE;
11542 int no;
11543 int retList = 0;
11544
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011545 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011546 if (error)
11547 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011548 if (no < 0 || no >= NSUBEXP)
11549 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011550 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011551 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011552 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011553 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011554 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011555 if (error)
11556 return;
11557
11558 if (retList == 0)
11559 {
11560 rettv->v_type = VAR_STRING;
11561 rettv->vval.v_string = reg_submatch(no);
11562 }
11563 else
11564 {
11565 rettv->v_type = VAR_LIST;
11566 rettv->vval.v_list = reg_submatch_list(no);
11567 }
11568}
11569
11570/*
11571 * "substitute()" function
11572 */
11573 static void
11574f_substitute(typval_T *argvars, typval_T *rettv)
11575{
11576 char_u patbuf[NUMBUFLEN];
11577 char_u subbuf[NUMBUFLEN];
11578 char_u flagsbuf[NUMBUFLEN];
11579
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011580 char_u *str = tv_get_string_chk(&argvars[0]);
11581 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011582 char_u *sub = NULL;
11583 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011584 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011585
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011586 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11587 expr = &argvars[2];
11588 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011589 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011590
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011591 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011592 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11593 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011594 rettv->vval.v_string = NULL;
11595 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011596 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011597}
11598
11599/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011600 * "swapinfo(swap_filename)" function
11601 */
11602 static void
11603f_swapinfo(typval_T *argvars, typval_T *rettv)
11604{
11605 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011606 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011607}
11608
11609/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011610 * "swapname(expr)" function
11611 */
11612 static void
11613f_swapname(typval_T *argvars, typval_T *rettv)
11614{
11615 buf_T *buf;
11616
11617 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011618 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011619 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11620 || buf->b_ml.ml_mfp->mf_fname == NULL)
11621 rettv->vval.v_string = NULL;
11622 else
11623 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11624}
11625
11626/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011627 * "synID(lnum, col, trans)" function
11628 */
11629 static void
11630f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11631{
11632 int id = 0;
11633#ifdef FEAT_SYN_HL
11634 linenr_T lnum;
11635 colnr_T col;
11636 int trans;
11637 int transerr = FALSE;
11638
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011639 lnum = tv_get_lnum(argvars); /* -1 on type error */
11640 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11641 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011642
11643 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11644 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11645 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11646#endif
11647
11648 rettv->vval.v_number = id;
11649}
11650
11651/*
11652 * "synIDattr(id, what [, mode])" function
11653 */
11654 static void
11655f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11656{
11657 char_u *p = NULL;
11658#ifdef FEAT_SYN_HL
11659 int id;
11660 char_u *what;
11661 char_u *mode;
11662 char_u modebuf[NUMBUFLEN];
11663 int modec;
11664
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011665 id = (int)tv_get_number(&argvars[0]);
11666 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011667 if (argvars[2].v_type != VAR_UNKNOWN)
11668 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011669 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011670 modec = TOLOWER_ASC(mode[0]);
11671 if (modec != 't' && modec != 'c' && modec != 'g')
11672 modec = 0; /* replace invalid with current */
11673 }
11674 else
11675 {
11676#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11677 if (USE_24BIT)
11678 modec = 'g';
11679 else
11680#endif
11681 if (t_colors > 1)
11682 modec = 'c';
11683 else
11684 modec = 't';
11685 }
11686
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011687 switch (TOLOWER_ASC(what[0]))
11688 {
11689 case 'b':
11690 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11691 p = highlight_color(id, what, modec);
11692 else /* bold */
11693 p = highlight_has_attr(id, HL_BOLD, modec);
11694 break;
11695
11696 case 'f': /* fg[#] or font */
11697 p = highlight_color(id, what, modec);
11698 break;
11699
11700 case 'i':
11701 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11702 p = highlight_has_attr(id, HL_INVERSE, modec);
11703 else /* italic */
11704 p = highlight_has_attr(id, HL_ITALIC, modec);
11705 break;
11706
11707 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011708 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011709 break;
11710
11711 case 'r': /* reverse */
11712 p = highlight_has_attr(id, HL_INVERSE, modec);
11713 break;
11714
11715 case 's':
11716 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11717 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011718 /* strikeout */
11719 else if (TOLOWER_ASC(what[1]) == 't' &&
11720 TOLOWER_ASC(what[2]) == 'r')
11721 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011722 else /* standout */
11723 p = highlight_has_attr(id, HL_STANDOUT, modec);
11724 break;
11725
11726 case 'u':
11727 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11728 /* underline */
11729 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11730 else
11731 /* undercurl */
11732 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11733 break;
11734 }
11735
11736 if (p != NULL)
11737 p = vim_strsave(p);
11738#endif
11739 rettv->v_type = VAR_STRING;
11740 rettv->vval.v_string = p;
11741}
11742
11743/*
11744 * "synIDtrans(id)" function
11745 */
11746 static void
11747f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11748{
11749 int id;
11750
11751#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011752 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011753
11754 if (id > 0)
11755 id = syn_get_final_id(id);
11756 else
11757#endif
11758 id = 0;
11759
11760 rettv->vval.v_number = id;
11761}
11762
11763/*
11764 * "synconcealed(lnum, col)" function
11765 */
11766 static void
11767f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11768{
11769#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11770 linenr_T lnum;
11771 colnr_T col;
11772 int syntax_flags = 0;
11773 int cchar;
11774 int matchid = 0;
11775 char_u str[NUMBUFLEN];
11776#endif
11777
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011778 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011779
11780#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011781 lnum = tv_get_lnum(argvars); /* -1 on type error */
11782 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011783
11784 vim_memset(str, NUL, sizeof(str));
11785
11786 if (rettv_list_alloc(rettv) != FAIL)
11787 {
11788 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11789 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11790 && curwin->w_p_cole > 0)
11791 {
11792 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11793 syntax_flags = get_syntax_info(&matchid);
11794
11795 /* get the conceal character */
11796 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11797 {
11798 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011799 if (cchar == NUL && curwin->w_p_cole == 1)
11800 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011801 if (cchar != NUL)
11802 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011803 if (has_mbyte)
11804 (*mb_char2bytes)(cchar, str);
11805 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011806 str[0] = cchar;
11807 }
11808 }
11809 }
11810
11811 list_append_number(rettv->vval.v_list,
11812 (syntax_flags & HL_CONCEAL) != 0);
11813 /* -1 to auto-determine strlen */
11814 list_append_string(rettv->vval.v_list, str, -1);
11815 list_append_number(rettv->vval.v_list, matchid);
11816 }
11817#endif
11818}
11819
11820/*
11821 * "synstack(lnum, col)" function
11822 */
11823 static void
11824f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11825{
11826#ifdef FEAT_SYN_HL
11827 linenr_T lnum;
11828 colnr_T col;
11829 int i;
11830 int id;
11831#endif
11832
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011833 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011834
11835#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011836 lnum = tv_get_lnum(argvars); /* -1 on type error */
11837 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011838
11839 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11840 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11841 && rettv_list_alloc(rettv) != FAIL)
11842 {
11843 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11844 for (i = 0; ; ++i)
11845 {
11846 id = syn_get_stack_item(i);
11847 if (id < 0)
11848 break;
11849 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11850 break;
11851 }
11852 }
11853#endif
11854}
11855
11856 static void
11857get_cmd_output_as_rettv(
11858 typval_T *argvars,
11859 typval_T *rettv,
11860 int retlist)
11861{
11862 char_u *res = NULL;
11863 char_u *p;
11864 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011865 int err = FALSE;
11866 FILE *fd;
11867 list_T *list = NULL;
11868 int flags = SHELL_SILENT;
11869
11870 rettv->v_type = VAR_STRING;
11871 rettv->vval.v_string = NULL;
11872 if (check_restricted() || check_secure())
11873 goto errret;
11874
11875 if (argvars[1].v_type != VAR_UNKNOWN)
11876 {
11877 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011878 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011879 * command.
11880 */
11881 if ((infile = vim_tempname('i', TRUE)) == NULL)
11882 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011883 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011884 goto errret;
11885 }
11886
11887 fd = mch_fopen((char *)infile, WRITEBIN);
11888 if (fd == NULL)
11889 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011890 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011891 goto errret;
11892 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011893 if (argvars[1].v_type == VAR_NUMBER)
11894 {
11895 linenr_T lnum;
11896 buf_T *buf;
11897
11898 buf = buflist_findnr(argvars[1].vval.v_number);
11899 if (buf == NULL)
11900 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011901 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011902 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011903 goto errret;
11904 }
11905
11906 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11907 {
11908 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11909 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11910 {
11911 err = TRUE;
11912 break;
11913 }
11914 if (putc(NL, fd) == EOF)
11915 {
11916 err = TRUE;
11917 break;
11918 }
11919 }
11920 }
11921 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011922 {
11923 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11924 err = TRUE;
11925 }
11926 else
11927 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011928 size_t len;
11929 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011930
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011931 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011932 if (p == NULL)
11933 {
11934 fclose(fd);
11935 goto errret; /* type error; errmsg already given */
11936 }
11937 len = STRLEN(p);
11938 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11939 err = TRUE;
11940 }
11941 if (fclose(fd) != 0)
11942 err = TRUE;
11943 if (err)
11944 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011945 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011946 goto errret;
11947 }
11948 }
11949
11950 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11951 * echoes typeahead, that messes up the display. */
11952 if (!msg_silent)
11953 flags += SHELL_COOKED;
11954
11955 if (retlist)
11956 {
11957 int len;
11958 listitem_T *li;
11959 char_u *s = NULL;
11960 char_u *start;
11961 char_u *end;
11962 int i;
11963
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011964 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011965 if (res == NULL)
11966 goto errret;
11967
11968 list = list_alloc();
11969 if (list == NULL)
11970 goto errret;
11971
11972 for (i = 0; i < len; ++i)
11973 {
11974 start = res + i;
11975 while (i < len && res[i] != NL)
11976 ++i;
11977 end = res + i;
11978
Bram Moolenaar964b3742019-05-24 18:54:09 +020011979 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011980 if (s == NULL)
11981 goto errret;
11982
11983 for (p = s; start < end; ++p, ++start)
11984 *p = *start == NUL ? NL : *start;
11985 *p = NUL;
11986
11987 li = listitem_alloc();
11988 if (li == NULL)
11989 {
11990 vim_free(s);
11991 goto errret;
11992 }
11993 li->li_tv.v_type = VAR_STRING;
11994 li->li_tv.v_lock = 0;
11995 li->li_tv.vval.v_string = s;
11996 list_append(list, li);
11997 }
11998
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011999 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012000 list = NULL;
12001 }
12002 else
12003 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012004 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010012005#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012006 /* translate <CR><NL> into <NL> */
12007 if (res != NULL)
12008 {
12009 char_u *s, *d;
12010
12011 d = res;
12012 for (s = res; *s; ++s)
12013 {
12014 if (s[0] == CAR && s[1] == NL)
12015 ++s;
12016 *d++ = *s;
12017 }
12018 *d = NUL;
12019 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012020#endif
12021 rettv->vval.v_string = res;
12022 res = NULL;
12023 }
12024
12025errret:
12026 if (infile != NULL)
12027 {
12028 mch_remove(infile);
12029 vim_free(infile);
12030 }
12031 if (res != NULL)
12032 vim_free(res);
12033 if (list != NULL)
12034 list_free(list);
12035}
12036
12037/*
12038 * "system()" function
12039 */
12040 static void
12041f_system(typval_T *argvars, typval_T *rettv)
12042{
12043 get_cmd_output_as_rettv(argvars, rettv, FALSE);
12044}
12045
12046/*
12047 * "systemlist()" function
12048 */
12049 static void
12050f_systemlist(typval_T *argvars, typval_T *rettv)
12051{
12052 get_cmd_output_as_rettv(argvars, rettv, TRUE);
12053}
12054
12055/*
12056 * "tabpagebuflist()" function
12057 */
12058 static void
12059f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12060{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012061 tabpage_T *tp;
12062 win_T *wp = NULL;
12063
12064 if (argvars[0].v_type == VAR_UNKNOWN)
12065 wp = firstwin;
12066 else
12067 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012068 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012069 if (tp != NULL)
12070 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12071 }
12072 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
12073 {
12074 for (; wp != NULL; wp = wp->w_next)
12075 if (list_append_number(rettv->vval.v_list,
12076 wp->w_buffer->b_fnum) == FAIL)
12077 break;
12078 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079}
12080
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012081/*
12082 * "tabpagenr()" function
12083 */
12084 static void
12085f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
12086{
12087 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012088 char_u *arg;
12089
12090 if (argvars[0].v_type != VAR_UNKNOWN)
12091 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012092 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012093 nr = 0;
12094 if (arg != NULL)
12095 {
12096 if (STRCMP(arg, "$") == 0)
12097 nr = tabpage_index(NULL) - 1;
12098 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012099 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012100 }
12101 }
12102 else
12103 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012104 rettv->vval.v_number = nr;
12105}
12106
12107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012108/*
12109 * Common code for tabpagewinnr() and winnr().
12110 */
12111 static int
12112get_winnr(tabpage_T *tp, typval_T *argvar)
12113{
12114 win_T *twin;
12115 int nr = 1;
12116 win_T *wp;
12117 char_u *arg;
12118
12119 twin = (tp == curtab) ? curwin : tp->tp_curwin;
12120 if (argvar->v_type != VAR_UNKNOWN)
12121 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012122 int invalid_arg = FALSE;
12123
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012124 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012125 if (arg == NULL)
12126 nr = 0; /* type error; errmsg already given */
12127 else if (STRCMP(arg, "$") == 0)
12128 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
12129 else if (STRCMP(arg, "#") == 0)
12130 {
12131 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
12132 if (twin == NULL)
12133 nr = 0;
12134 }
12135 else
12136 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020012137 long count;
12138 char_u *endp;
12139
12140 // Extract the window count (if specified). e.g. winnr('3j')
12141 count = strtol((char *)arg, (char **)&endp, 10);
12142 if (count <= 0)
12143 count = 1; // if count is not specified, default to 1
12144 if (endp != NULL && *endp != '\0')
12145 {
12146 if (STRCMP(endp, "j") == 0)
12147 twin = win_vert_neighbor(tp, twin, FALSE, count);
12148 else if (STRCMP(endp, "k") == 0)
12149 twin = win_vert_neighbor(tp, twin, TRUE, count);
12150 else if (STRCMP(endp, "h") == 0)
12151 twin = win_horz_neighbor(tp, twin, TRUE, count);
12152 else if (STRCMP(endp, "l") == 0)
12153 twin = win_horz_neighbor(tp, twin, FALSE, count);
12154 else
12155 invalid_arg = TRUE;
12156 }
12157 else
12158 invalid_arg = TRUE;
12159 }
12160
12161 if (invalid_arg)
12162 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012163 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012164 nr = 0;
12165 }
12166 }
12167
12168 if (nr > 0)
12169 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
12170 wp != twin; wp = wp->w_next)
12171 {
12172 if (wp == NULL)
12173 {
12174 /* didn't find it in this tabpage */
12175 nr = 0;
12176 break;
12177 }
12178 ++nr;
12179 }
12180 return nr;
12181}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012182
12183/*
12184 * "tabpagewinnr()" function
12185 */
12186 static void
12187f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
12188{
12189 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012190 tabpage_T *tp;
12191
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012192 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012193 if (tp == NULL)
12194 nr = 0;
12195 else
12196 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012197 rettv->vval.v_number = nr;
12198}
12199
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012200/*
12201 * "tagfiles()" function
12202 */
12203 static void
12204f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
12205{
12206 char_u *fname;
12207 tagname_T tn;
12208 int first;
12209
12210 if (rettv_list_alloc(rettv) == FAIL)
12211 return;
12212 fname = alloc(MAXPATHL);
12213 if (fname == NULL)
12214 return;
12215
12216 for (first = TRUE; ; first = FALSE)
12217 if (get_tagfname(&tn, first, fname) == FAIL
12218 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12219 break;
12220 tagname_free(&tn);
12221 vim_free(fname);
12222}
12223
12224/*
12225 * "taglist()" function
12226 */
12227 static void
12228f_taglist(typval_T *argvars, typval_T *rettv)
12229{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012230 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012231 char_u *tag_pattern;
12232
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012233 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012234
12235 rettv->vval.v_number = FALSE;
12236 if (*tag_pattern == NUL)
12237 return;
12238
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012239 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012240 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012241 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012242 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012243}
12244
12245/*
12246 * "tempname()" function
12247 */
12248 static void
12249f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12250{
12251 static int x = 'A';
12252
12253 rettv->v_type = VAR_STRING;
12254 rettv->vval.v_string = vim_tempname(x, FALSE);
12255
12256 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12257 * names. Skip 'I' and 'O', they are used for shell redirection. */
12258 do
12259 {
12260 if (x == 'Z')
12261 x = '0';
12262 else if (x == '9')
12263 x = 'A';
12264 else
12265 {
12266#ifdef EBCDIC
12267 if (x == 'I')
12268 x = 'J';
12269 else if (x == 'R')
12270 x = 'S';
12271 else
12272#endif
12273 ++x;
12274 }
12275 } while (x == 'I' || x == 'O');
12276}
12277
12278#ifdef FEAT_FLOAT
12279/*
12280 * "tan()" function
12281 */
12282 static void
12283f_tan(typval_T *argvars, typval_T *rettv)
12284{
12285 float_T f = 0.0;
12286
12287 rettv->v_type = VAR_FLOAT;
12288 if (get_float_arg(argvars, &f) == OK)
12289 rettv->vval.v_float = tan(f);
12290 else
12291 rettv->vval.v_float = 0.0;
12292}
12293
12294/*
12295 * "tanh()" function
12296 */
12297 static void
12298f_tanh(typval_T *argvars, typval_T *rettv)
12299{
12300 float_T f = 0.0;
12301
12302 rettv->v_type = VAR_FLOAT;
12303 if (get_float_arg(argvars, &f) == OK)
12304 rettv->vval.v_float = tanh(f);
12305 else
12306 rettv->vval.v_float = 0.0;
12307}
12308#endif
12309
12310/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012311 * Get a callback from "arg". It can be a Funcref or a function name.
12312 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012313 * "cb_name" is not allocated.
12314 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012315 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012316 callback_T
12317get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012318{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012319 callback_T res;
12320
12321 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012322 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12323 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012324 res.cb_partial = arg->vval.v_partial;
12325 ++res.cb_partial->pt_refcount;
12326 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012327 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012328 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012329 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012330 res.cb_partial = NULL;
12331 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12332 {
12333 // Note that we don't make a copy of the string.
12334 res.cb_name = arg->vval.v_string;
12335 func_ref(res.cb_name);
12336 }
12337 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12338 {
12339 res.cb_name = (char_u *)"";
12340 }
12341 else
12342 {
12343 emsg(_("E921: Invalid callback argument"));
12344 res.cb_name = NULL;
12345 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012346 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012347 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012348}
12349
12350/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012351 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012352 */
12353 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012354put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012355{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012356 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012358 tv->v_type = VAR_PARTIAL;
12359 tv->vval.v_partial = cb->cb_partial;
12360 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012361 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012362 else
12363 {
12364 tv->v_type = VAR_FUNC;
12365 tv->vval.v_string = vim_strsave(cb->cb_name);
12366 func_ref(cb->cb_name);
12367 }
12368}
12369
12370/*
12371 * Make a copy of "src" into "dest", allocating the function name if needed,
12372 * without incrementing the refcount.
12373 */
12374 void
12375set_callback(callback_T *dest, callback_T *src)
12376{
12377 if (src->cb_partial == NULL)
12378 {
12379 // just a function name, make a copy
12380 dest->cb_name = vim_strsave(src->cb_name);
12381 dest->cb_free_name = TRUE;
12382 }
12383 else
12384 {
12385 // cb_name is a pointer into cb_partial
12386 dest->cb_name = src->cb_name;
12387 dest->cb_free_name = FALSE;
12388 }
12389 dest->cb_partial = src->cb_partial;
12390}
12391
12392/*
12393 * Unref/free "callback" returned by get_callback() or set_callback().
12394 */
12395 void
12396free_callback(callback_T *callback)
12397{
12398 if (callback->cb_partial != NULL)
12399 {
12400 partial_unref(callback->cb_partial);
12401 callback->cb_partial = NULL;
12402 }
12403 else if (callback->cb_name != NULL)
12404 func_unref(callback->cb_name);
12405 if (callback->cb_free_name)
12406 {
12407 vim_free(callback->cb_name);
12408 callback->cb_free_name = FALSE;
12409 }
12410 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012411}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012412
12413#ifdef FEAT_TIMERS
12414/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012415 * "timer_info([timer])" function
12416 */
12417 static void
12418f_timer_info(typval_T *argvars, typval_T *rettv)
12419{
12420 timer_T *timer = NULL;
12421
12422 if (rettv_list_alloc(rettv) != OK)
12423 return;
12424 if (argvars[0].v_type != VAR_UNKNOWN)
12425 {
12426 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012427 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012428 else
12429 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012430 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012431 if (timer != NULL)
12432 add_timer_info(rettv, timer);
12433 }
12434 }
12435 else
12436 add_timer_info_all(rettv);
12437}
12438
12439/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012440 * "timer_pause(timer, paused)" function
12441 */
12442 static void
12443f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12444{
12445 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012446 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012447
12448 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012449 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012450 else
12451 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012452 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012453 if (timer != NULL)
12454 timer->tr_paused = paused;
12455 }
12456}
12457
12458/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012459 * "timer_start(time, callback [, options])" function
12460 */
12461 static void
12462f_timer_start(typval_T *argvars, typval_T *rettv)
12463{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012464 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012465 timer_T *timer;
12466 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012467 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012468 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012469
Bram Moolenaar75537a92016-09-05 22:45:28 +020012470 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012471 if (check_secure())
12472 return;
12473 if (argvars[2].v_type != VAR_UNKNOWN)
12474 {
12475 if (argvars[2].v_type != VAR_DICT
12476 || (dict = argvars[2].vval.v_dict) == NULL)
12477 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012478 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012479 return;
12480 }
12481 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012482 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012483 }
12484
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012485 callback = get_callback(&argvars[1]);
12486 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012487 return;
12488
12489 timer = create_timer(msec, repeat);
12490 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012491 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012492 else
12493 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012494 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012495 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012496 }
12497}
12498
12499/*
12500 * "timer_stop(timer)" function
12501 */
12502 static void
12503f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12504{
12505 timer_T *timer;
12506
12507 if (argvars[0].v_type != VAR_NUMBER)
12508 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012509 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012510 return;
12511 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012512 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012513 if (timer != NULL)
12514 stop_timer(timer);
12515}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012516
12517/*
12518 * "timer_stopall()" function
12519 */
12520 static void
12521f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12522{
12523 stop_all_timers();
12524}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012525#endif
12526
12527/*
12528 * "tolower(string)" function
12529 */
12530 static void
12531f_tolower(typval_T *argvars, typval_T *rettv)
12532{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012533 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012534 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012535}
12536
12537/*
12538 * "toupper(string)" function
12539 */
12540 static void
12541f_toupper(typval_T *argvars, typval_T *rettv)
12542{
12543 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012544 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012545}
12546
12547/*
12548 * "tr(string, fromstr, tostr)" function
12549 */
12550 static void
12551f_tr(typval_T *argvars, typval_T *rettv)
12552{
12553 char_u *in_str;
12554 char_u *fromstr;
12555 char_u *tostr;
12556 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012557 int inlen;
12558 int fromlen;
12559 int tolen;
12560 int idx;
12561 char_u *cpstr;
12562 int cplen;
12563 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012564 char_u buf[NUMBUFLEN];
12565 char_u buf2[NUMBUFLEN];
12566 garray_T ga;
12567
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012568 in_str = tv_get_string(&argvars[0]);
12569 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12570 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012571
12572 /* Default return value: empty string. */
12573 rettv->v_type = VAR_STRING;
12574 rettv->vval.v_string = NULL;
12575 if (fromstr == NULL || tostr == NULL)
12576 return; /* type error; errmsg already given */
12577 ga_init2(&ga, (int)sizeof(char), 80);
12578
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012579 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012580 /* not multi-byte: fromstr and tostr must be the same length */
12581 if (STRLEN(fromstr) != STRLEN(tostr))
12582 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012583error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012584 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012585 ga_clear(&ga);
12586 return;
12587 }
12588
12589 /* fromstr and tostr have to contain the same number of chars */
12590 while (*in_str != NUL)
12591 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012592 if (has_mbyte)
12593 {
12594 inlen = (*mb_ptr2len)(in_str);
12595 cpstr = in_str;
12596 cplen = inlen;
12597 idx = 0;
12598 for (p = fromstr; *p != NUL; p += fromlen)
12599 {
12600 fromlen = (*mb_ptr2len)(p);
12601 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12602 {
12603 for (p = tostr; *p != NUL; p += tolen)
12604 {
12605 tolen = (*mb_ptr2len)(p);
12606 if (idx-- == 0)
12607 {
12608 cplen = tolen;
12609 cpstr = p;
12610 break;
12611 }
12612 }
12613 if (*p == NUL) /* tostr is shorter than fromstr */
12614 goto error;
12615 break;
12616 }
12617 ++idx;
12618 }
12619
12620 if (first && cpstr == in_str)
12621 {
12622 /* Check that fromstr and tostr have the same number of
12623 * (multi-byte) characters. Done only once when a character
12624 * of in_str doesn't appear in fromstr. */
12625 first = FALSE;
12626 for (p = tostr; *p != NUL; p += tolen)
12627 {
12628 tolen = (*mb_ptr2len)(p);
12629 --idx;
12630 }
12631 if (idx != 0)
12632 goto error;
12633 }
12634
12635 (void)ga_grow(&ga, cplen);
12636 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12637 ga.ga_len += cplen;
12638
12639 in_str += inlen;
12640 }
12641 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012642 {
12643 /* When not using multi-byte chars we can do it faster. */
12644 p = vim_strchr(fromstr, *in_str);
12645 if (p != NULL)
12646 ga_append(&ga, tostr[p - fromstr]);
12647 else
12648 ga_append(&ga, *in_str);
12649 ++in_str;
12650 }
12651 }
12652
12653 /* add a terminating NUL */
12654 (void)ga_grow(&ga, 1);
12655 ga_append(&ga, NUL);
12656
12657 rettv->vval.v_string = ga.ga_data;
12658}
12659
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012660/*
12661 * "trim({expr})" function
12662 */
12663 static void
12664f_trim(typval_T *argvars, typval_T *rettv)
12665{
12666 char_u buf1[NUMBUFLEN];
12667 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012668 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012669 char_u *mask = NULL;
12670 char_u *tail;
12671 char_u *prev;
12672 char_u *p;
12673 int c1;
12674
12675 rettv->v_type = VAR_STRING;
12676 if (head == NULL)
12677 {
12678 rettv->vval.v_string = NULL;
12679 return;
12680 }
12681
12682 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012683 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012684
12685 while (*head != NUL)
12686 {
12687 c1 = PTR2CHAR(head);
12688 if (mask == NULL)
12689 {
12690 if (c1 > ' ' && c1 != 0xa0)
12691 break;
12692 }
12693 else
12694 {
12695 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12696 if (c1 == PTR2CHAR(p))
12697 break;
12698 if (*p == NUL)
12699 break;
12700 }
12701 MB_PTR_ADV(head);
12702 }
12703
12704 for (tail = head + STRLEN(head); tail > head; tail = prev)
12705 {
12706 prev = tail;
12707 MB_PTR_BACK(head, prev);
12708 c1 = PTR2CHAR(prev);
12709 if (mask == NULL)
12710 {
12711 if (c1 > ' ' && c1 != 0xa0)
12712 break;
12713 }
12714 else
12715 {
12716 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12717 if (c1 == PTR2CHAR(p))
12718 break;
12719 if (*p == NUL)
12720 break;
12721 }
12722 }
12723 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12724}
12725
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012726#ifdef FEAT_FLOAT
12727/*
12728 * "trunc({float})" function
12729 */
12730 static void
12731f_trunc(typval_T *argvars, typval_T *rettv)
12732{
12733 float_T f = 0.0;
12734
12735 rettv->v_type = VAR_FLOAT;
12736 if (get_float_arg(argvars, &f) == OK)
12737 /* trunc() is not in C90, use floor() or ceil() instead. */
12738 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12739 else
12740 rettv->vval.v_float = 0.0;
12741}
12742#endif
12743
12744/*
12745 * "type(expr)" function
12746 */
12747 static void
12748f_type(typval_T *argvars, typval_T *rettv)
12749{
12750 int n = -1;
12751
12752 switch (argvars[0].v_type)
12753 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012754 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12755 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012756 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012757 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12758 case VAR_LIST: n = VAR_TYPE_LIST; break;
12759 case VAR_DICT: n = VAR_TYPE_DICT; break;
12760 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 case VAR_SPECIAL:
12762 if (argvars[0].vval.v_number == VVAL_FALSE
12763 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012764 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012765 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012766 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012767 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012768 case VAR_JOB: n = VAR_TYPE_JOB; break;
12769 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012770 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012772 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012773 n = -1;
12774 break;
12775 }
12776 rettv->vval.v_number = n;
12777}
12778
12779/*
12780 * "undofile(name)" function
12781 */
12782 static void
12783f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12784{
12785 rettv->v_type = VAR_STRING;
12786#ifdef FEAT_PERSISTENT_UNDO
12787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012788 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012789
12790 if (*fname == NUL)
12791 {
12792 /* If there is no file name there will be no undo file. */
12793 rettv->vval.v_string = NULL;
12794 }
12795 else
12796 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012797 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012798
12799 if (ffname != NULL)
12800 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12801 vim_free(ffname);
12802 }
12803 }
12804#else
12805 rettv->vval.v_string = NULL;
12806#endif
12807}
12808
12809/*
12810 * "undotree()" function
12811 */
12812 static void
12813f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12814{
12815 if (rettv_dict_alloc(rettv) == OK)
12816 {
12817 dict_T *dict = rettv->vval.v_dict;
12818 list_T *list;
12819
Bram Moolenaare0be1672018-07-08 16:50:37 +020012820 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12821 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12822 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12823 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12824 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12825 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012826
12827 list = list_alloc();
12828 if (list != NULL)
12829 {
12830 u_eval_tree(curbuf->b_u_oldhead, list);
12831 dict_add_list(dict, "entries", list);
12832 }
12833 }
12834}
12835
12836/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012837 * "virtcol(string)" function
12838 */
12839 static void
12840f_virtcol(typval_T *argvars, typval_T *rettv)
12841{
12842 colnr_T vcol = 0;
12843 pos_T *fp;
12844 int fnum = curbuf->b_fnum;
12845
12846 fp = var2fpos(&argvars[0], FALSE, &fnum);
12847 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12848 && fnum == curbuf->b_fnum)
12849 {
12850 getvvcol(curwin, fp, NULL, NULL, &vcol);
12851 ++vcol;
12852 }
12853
12854 rettv->vval.v_number = vcol;
12855}
12856
12857/*
12858 * "visualmode()" function
12859 */
12860 static void
12861f_visualmode(typval_T *argvars, typval_T *rettv)
12862{
12863 char_u str[2];
12864
12865 rettv->v_type = VAR_STRING;
12866 str[0] = curbuf->b_visual_mode_eval;
12867 str[1] = NUL;
12868 rettv->vval.v_string = vim_strsave(str);
12869
12870 /* A non-zero number or non-empty string argument: reset mode. */
12871 if (non_zero_arg(&argvars[0]))
12872 curbuf->b_visual_mode_eval = NUL;
12873}
12874
12875/*
12876 * "wildmenumode()" function
12877 */
12878 static void
12879f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12880{
12881#ifdef FEAT_WILDMENU
12882 if (wild_menu_showing)
12883 rettv->vval.v_number = 1;
12884#endif
12885}
12886
12887/*
12888 * "winbufnr(nr)" function
12889 */
12890 static void
12891f_winbufnr(typval_T *argvars, typval_T *rettv)
12892{
12893 win_T *wp;
12894
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012895 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012896 if (wp == NULL)
12897 rettv->vval.v_number = -1;
12898 else
12899 rettv->vval.v_number = wp->w_buffer->b_fnum;
12900}
12901
12902/*
12903 * "wincol()" function
12904 */
12905 static void
12906f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12907{
12908 validate_cursor();
12909 rettv->vval.v_number = curwin->w_wcol + 1;
12910}
12911
12912/*
12913 * "winheight(nr)" function
12914 */
12915 static void
12916f_winheight(typval_T *argvars, typval_T *rettv)
12917{
12918 win_T *wp;
12919
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012920 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012921 if (wp == NULL)
12922 rettv->vval.v_number = -1;
12923 else
12924 rettv->vval.v_number = wp->w_height;
12925}
12926
12927/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012928 * "winlayout()" function
12929 */
12930 static void
12931f_winlayout(typval_T *argvars, typval_T *rettv)
12932{
12933 tabpage_T *tp;
12934
12935 if (rettv_list_alloc(rettv) != OK)
12936 return;
12937
12938 if (argvars[0].v_type == VAR_UNKNOWN)
12939 tp = curtab;
12940 else
12941 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012942 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012943 if (tp == NULL)
12944 return;
12945 }
12946
12947 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12948}
12949
12950/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012951 * "winline()" function
12952 */
12953 static void
12954f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12955{
12956 validate_cursor();
12957 rettv->vval.v_number = curwin->w_wrow + 1;
12958}
12959
12960/*
12961 * "winnr()" function
12962 */
12963 static void
12964f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12965{
12966 int nr = 1;
12967
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012968 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012969 rettv->vval.v_number = nr;
12970}
12971
12972/*
12973 * "winrestcmd()" function
12974 */
12975 static void
12976f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12977{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012978 win_T *wp;
12979 int winnr = 1;
12980 garray_T ga;
12981 char_u buf[50];
12982
12983 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012984 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012985 {
12986 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12987 ga_concat(&ga, buf);
12988 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12989 ga_concat(&ga, buf);
12990 ++winnr;
12991 }
12992 ga_append(&ga, NUL);
12993
12994 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012995 rettv->v_type = VAR_STRING;
12996}
12997
12998/*
12999 * "winrestview()" function
13000 */
13001 static void
13002f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
13003{
13004 dict_T *dict;
13005
13006 if (argvars[0].v_type != VAR_DICT
13007 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013008 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013009 else
13010 {
13011 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013012 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013013 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013014 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013015 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013016 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013017 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
13018 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010013019 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013020 curwin->w_set_curswant = FALSE;
13021 }
13022
13023 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013024 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013025#ifdef FEAT_DIFF
13026 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013027 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013028#endif
13029 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013030 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013031 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010013032 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013033
13034 check_cursor();
13035 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020013036 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013037 changed_window_setting();
13038
13039 if (curwin->w_topline <= 0)
13040 curwin->w_topline = 1;
13041 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
13042 curwin->w_topline = curbuf->b_ml.ml_line_count;
13043#ifdef FEAT_DIFF
13044 check_topfill(curwin, TRUE);
13045#endif
13046 }
13047}
13048
13049/*
13050 * "winsaveview()" function
13051 */
13052 static void
13053f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
13054{
13055 dict_T *dict;
13056
13057 if (rettv_dict_alloc(rettv) == FAIL)
13058 return;
13059 dict = rettv->vval.v_dict;
13060
Bram Moolenaare0be1672018-07-08 16:50:37 +020013061 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
13062 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020013063 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013064 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020013065 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013066
Bram Moolenaare0be1672018-07-08 16:50:37 +020013067 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013068#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020013069 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013070#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020013071 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
13072 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013073}
13074
13075/*
13076 * "winwidth(nr)" function
13077 */
13078 static void
13079f_winwidth(typval_T *argvars, typval_T *rettv)
13080{
13081 win_T *wp;
13082
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020013083 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013084 if (wp == NULL)
13085 rettv->vval.v_number = -1;
13086 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013087 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013088}
13089
13090/*
13091 * "wordcount()" function
13092 */
13093 static void
13094f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
13095{
13096 if (rettv_dict_alloc(rettv) == FAIL)
13097 return;
13098 cursor_pos_info(rettv->vval.v_dict);
13099}
13100
13101/*
13102 * "writefile()" function
13103 */
13104 static void
13105f_writefile(typval_T *argvars, typval_T *rettv)
13106{
13107 int binary = FALSE;
13108 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013109#ifdef HAVE_FSYNC
13110 int do_fsync = p_fs;
13111#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013112 char_u *fname;
13113 FILE *fd;
13114 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013115 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013116 list_T *list = NULL;
13117 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013118
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013119 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010013120 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013121 return;
13122
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013123 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013124 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013125 list = argvars[0].vval.v_list;
13126 if (list == NULL)
13127 return;
13128 for (li = list->lv_first; li != NULL; li = li->li_next)
13129 if (tv_get_string_chk(&li->li_tv) == NULL)
13130 return;
13131 }
13132 else if (argvars[0].v_type == VAR_BLOB)
13133 {
13134 blob = argvars[0].vval.v_blob;
13135 if (blob == NULL)
13136 return;
13137 }
13138 else
13139 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013140 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013141 return;
13142 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013143
13144 if (argvars[2].v_type != VAR_UNKNOWN)
13145 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013146 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013147
13148 if (arg2 == NULL)
13149 return;
13150 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013151 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013152 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013153 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013154#ifdef HAVE_FSYNC
13155 if (vim_strchr(arg2, 's') != NULL)
13156 do_fsync = TRUE;
13157 else if (vim_strchr(arg2, 'S') != NULL)
13158 do_fsync = FALSE;
13159#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013160 }
13161
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013162 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013163 if (fname == NULL)
13164 return;
13165
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013166 /* Always open the file in binary mode, library functions have a mind of
13167 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013168 if (*fname == NUL || (fd = mch_fopen((char *)fname,
13169 append ? APPENDBIN : WRITEBIN)) == NULL)
13170 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013171 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013172 ret = -1;
13173 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013174 else if (blob)
13175 {
13176 if (write_blob(fd, blob) == FAIL)
13177 ret = -1;
13178#ifdef HAVE_FSYNC
13179 else if (do_fsync)
13180 // Ignore the error, the user wouldn't know what to do about it.
13181 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010013182 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010013183#endif
13184 fclose(fd);
13185 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013186 else
13187 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020013188 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013189 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013190#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010013191 else if (do_fsync)
13192 /* Ignore the error, the user wouldn't know what to do about it.
13193 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010013194 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010013195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013196 fclose(fd);
13197 }
13198
13199 rettv->vval.v_number = ret;
13200}
13201
13202/*
13203 * "xor(expr, expr)" function
13204 */
13205 static void
13206f_xor(typval_T *argvars, typval_T *rettv)
13207{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013208 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13209 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013210}
13211
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013212#endif /* FEAT_EVAL */