blob: 489ab424a941ea8011487035934bbb6670d56dd5 [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 Moolenaar10455d42019-11-21 15:36:18 +010023#if defined(MACOS_X)
Bram Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_confirm(typval_T *argvars, typval_T *rettv);
56static void f_copy(typval_T *argvars, typval_T *rettv);
57#ifdef FEAT_FLOAT
58static void f_cos(typval_T *argvars, typval_T *rettv);
59static void f_cosh(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010062#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020063static void f_debugbreak(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020065static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020068static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_escape(typval_T *argvars, typval_T *rettv);
70static void f_eval(typval_T *argvars, typval_T *rettv);
71static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_exists(typval_T *argvars, typval_T *rettv);
74#ifdef FEAT_FLOAT
75static void f_exp(typval_T *argvars, typval_T *rettv);
76#endif
77static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020078static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080#ifdef FEAT_FLOAT
81static void f_float2nr(typval_T *argvars, typval_T *rettv);
82static void f_floor(typval_T *argvars, typval_T *rettv);
83static void f_fmod(typval_T *argvars, typval_T *rettv);
84#endif
85static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020087static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_function(typval_T *argvars, typval_T *rettv);
89static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
90static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010091static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020094static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020095static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010096static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020097static void f_getpid(typval_T *argvars, typval_T *rettv);
98static void f_getcurpos(typval_T *argvars, typval_T *rettv);
99static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getreg(typval_T *argvars, typval_T *rettv);
101static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100102static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
105static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_hlID(typval_T *argvars, typval_T *rettv);
107static void f_hlexists(typval_T *argvars, typval_T *rettv);
108static void f_hostname(typval_T *argvars, typval_T *rettv);
109static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_index(typval_T *argvars, typval_T *rettv);
111static void f_input(typval_T *argvars, typval_T *rettv);
112static void f_inputdialog(typval_T *argvars, typval_T *rettv);
113static void f_inputlist(typval_T *argvars, typval_T *rettv);
114static void f_inputrestore(typval_T *argvars, typval_T *rettv);
115static void f_inputsave(typval_T *argvars, typval_T *rettv);
116static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100117static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_islocked(typval_T *argvars, typval_T *rettv);
120#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200121static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200122static void f_isnan(typval_T *argvars, typval_T *rettv);
123#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200124static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
125static void f_len(typval_T *argvars, typval_T *rettv);
126static void f_libcall(typval_T *argvars, typval_T *rettv);
127static void f_libcallnr(typval_T *argvars, typval_T *rettv);
128static void f_line(typval_T *argvars, typval_T *rettv);
129static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200130static void f_localtime(typval_T *argvars, typval_T *rettv);
131#ifdef FEAT_FLOAT
132static void f_log(typval_T *argvars, typval_T *rettv);
133static void f_log10(typval_T *argvars, typval_T *rettv);
134#endif
135#ifdef FEAT_LUA
136static void f_luaeval(typval_T *argvars, typval_T *rettv);
137#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_maparg(typval_T *argvars, typval_T *rettv);
139static void f_mapcheck(typval_T *argvars, typval_T *rettv);
140static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_matchend(typval_T *argvars, typval_T *rettv);
142static void f_matchlist(typval_T *argvars, typval_T *rettv);
143static void f_matchstr(typval_T *argvars, typval_T *rettv);
144static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
145static void f_max(typval_T *argvars, typval_T *rettv);
146static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_MZSCHEME
148static void f_mzeval(typval_T *argvars, typval_T *rettv);
149#endif
150static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
151static void f_nr2char(typval_T *argvars, typval_T *rettv);
152static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200153#ifdef FEAT_PERL
154static void f_perleval(typval_T *argvars, typval_T *rettv);
155#endif
156#ifdef FEAT_FLOAT
157static void f_pow(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
160static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200161static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_pumvisible(typval_T *argvars, typval_T *rettv);
163#ifdef FEAT_PYTHON3
164static void f_py3eval(typval_T *argvars, typval_T *rettv);
165#endif
166#ifdef FEAT_PYTHON
167static void f_pyeval(typval_T *argvars, typval_T *rettv);
168#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100169#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
170static void f_pyxeval(typval_T *argvars, typval_T *rettv);
171#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100172static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200174static void f_reg_executing(typval_T *argvars, typval_T *rettv);
175static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200176static void f_reltime(typval_T *argvars, typval_T *rettv);
177#ifdef FEAT_FLOAT
178static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
179#endif
180static void f_reltimestr(typval_T *argvars, typval_T *rettv);
181static void f_remote_expr(typval_T *argvars, typval_T *rettv);
182static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
183static void f_remote_peek(typval_T *argvars, typval_T *rettv);
184static void f_remote_read(typval_T *argvars, typval_T *rettv);
185static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100186static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_rename(typval_T *argvars, typval_T *rettv);
188static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200189#ifdef FEAT_FLOAT
190static void f_round(typval_T *argvars, typval_T *rettv);
191#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100192#ifdef FEAT_RUBY
193static void f_rubyeval(typval_T *argvars, typval_T *rettv);
194#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_screenattr(typval_T *argvars, typval_T *rettv);
196static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100197static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_screencol(typval_T *argvars, typval_T *rettv);
199static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100200static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_search(typval_T *argvars, typval_T *rettv);
202static void f_searchdecl(typval_T *argvars, typval_T *rettv);
203static void f_searchpair(typval_T *argvars, typval_T *rettv);
204static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
205static void f_searchpos(typval_T *argvars, typval_T *rettv);
206static void f_server2client(typval_T *argvars, typval_T *rettv);
207static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200208static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200209static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200210static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100213static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214#ifdef FEAT_CRYPT
215static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200216#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217static void f_shellescape(typval_T *argvars, typval_T *rettv);
218static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219#ifdef FEAT_FLOAT
220static void f_sin(typval_T *argvars, typval_T *rettv);
221static void f_sinh(typval_T *argvars, typval_T *rettv);
222#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223static void f_soundfold(typval_T *argvars, typval_T *rettv);
224static void f_spellbadword(typval_T *argvars, typval_T *rettv);
225static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
226static void f_split(typval_T *argvars, typval_T *rettv);
227#ifdef FEAT_FLOAT
228static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100229#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100230static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100231#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200232static void f_str2float(typval_T *argvars, typval_T *rettv);
233#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200234static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_str2nr(typval_T *argvars, typval_T *rettv);
236static void f_strchars(typval_T *argvars, typval_T *rettv);
237#ifdef HAVE_STRFTIME
238static void f_strftime(typval_T *argvars, typval_T *rettv);
239#endif
240static void f_strgetchar(typval_T *argvars, typval_T *rettv);
241static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242static void f_strlen(typval_T *argvars, typval_T *rettv);
243static void f_strcharpart(typval_T *argvars, typval_T *rettv);
244static void f_strpart(typval_T *argvars, typval_T *rettv);
Bram Moolenaar10455d42019-11-21 15:36:18 +0100245#ifdef HAVE_STRPTIME
246static void f_strptime(typval_T *argvars, typval_T *rettv);
247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248static void f_strridx(typval_T *argvars, typval_T *rettv);
249static void f_strtrans(typval_T *argvars, typval_T *rettv);
250static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
251static void f_strwidth(typval_T *argvars, typval_T *rettv);
252static void f_submatch(typval_T *argvars, typval_T *rettv);
253static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200254static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200255static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256static void f_synID(typval_T *argvars, typval_T *rettv);
257static void f_synIDattr(typval_T *argvars, typval_T *rettv);
258static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
259static void f_synstack(typval_T *argvars, typval_T *rettv);
260static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200262static void f_taglist(typval_T *argvars, typval_T *rettv);
263static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264#ifdef FEAT_FLOAT
265static void f_tan(typval_T *argvars, typval_T *rettv);
266static void f_tanh(typval_T *argvars, typval_T *rettv);
267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_tolower(typval_T *argvars, typval_T *rettv);
269static void f_toupper(typval_T *argvars, typval_T *rettv);
270static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100271static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272#ifdef FEAT_FLOAT
273static void f_trunc(typval_T *argvars, typval_T *rettv);
274#endif
275static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200276static void f_virtcol(typval_T *argvars, typval_T *rettv);
277static void f_visualmode(typval_T *argvars, typval_T *rettv);
278static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100279static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200280static void f_wordcount(typval_T *argvars, typval_T *rettv);
281static void f_xor(typval_T *argvars, typval_T *rettv);
282
283/*
284 * Array with names and number of arguments of all internal functions
285 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
286 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200287typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200289 char *f_name; // function name
290 char f_min_argc; // minimal number of arguments
291 char f_max_argc; // maximal number of arguments
292 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200293 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200294 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200295} funcentry_T;
296
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200297// values for f_argtype; zero means it cannot be used as a method
298#define FEARG_1 1 // base is the first argument
299#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200300#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200301#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200302#define FEARG_LAST 9 // base is the last argument
303
Bram Moolenaarac92e252019-08-03 21:58:38 +0200304static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200305{
306#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200307 {"abs", 1, 1, FEARG_1, f_abs},
308 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200310 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200311 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200312 {"append", 2, 2, FEARG_LAST, f_append},
313 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
314 {"argc", 0, 1, 0, f_argc},
315 {"argidx", 0, 0, 0, f_argidx},
316 {"arglistid", 0, 2, 0, f_arglistid},
317 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200318#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200319 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200321 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200322 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200323 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200324 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200325 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
326 {"assert_false", 1, 2, FEARG_1, f_assert_false},
327 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
328 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200329 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200330 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200331 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200332 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200334 {"atan", 1, 1, FEARG_1, f_atan},
335 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200336#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100337#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200338 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200339 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100340# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200341 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100342# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100343#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200344 {"browse", 4, 4, 0, f_browse},
345 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200346 {"bufadd", 1, 1, FEARG_1, f_bufadd},
347 {"bufexists", 1, 1, FEARG_1, f_bufexists},
348 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200349 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
350 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200351 {"buflisted", 1, 1, FEARG_1, f_buflisted},
352 {"bufload", 1, 1, FEARG_1, f_bufload},
353 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200354 {"bufname", 0, 1, FEARG_1, f_bufname},
355 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200356 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
357 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200358 {"byte2line", 1, 1, FEARG_1, f_byte2line},
359 {"byteidx", 2, 2, FEARG_1, f_byteidx},
360 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
361 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200362#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200363 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200364#endif
365#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200366 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
367 {"ch_close", 1, 1, FEARG_1, f_ch_close},
368 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
369 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
370 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
371 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
372 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
373 {"ch_info", 1, 1, FEARG_1, f_ch_info},
374 {"ch_log", 1, 2, FEARG_1, f_ch_log},
375 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
376 {"ch_open", 1, 2, FEARG_1, f_ch_open},
377 {"ch_read", 1, 2, FEARG_1, f_ch_read},
378 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
379 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
380 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
381 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
382 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
383 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200384#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200385 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200386 {"char2nr", 1, 2, FEARG_1, f_char2nr},
387 {"chdir", 1, 1, FEARG_1, f_chdir},
388 {"cindent", 1, 1, FEARG_1, f_cindent},
389 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
390 {"col", 1, 1, FEARG_1, f_col},
391 {"complete", 2, 2, FEARG_2, f_complete},
392 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200393 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200394 {"complete_info", 0, 1, FEARG_1, f_complete_info},
395 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200396 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200398 {"cos", 1, 1, FEARG_1, f_cos},
399 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200400#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200401 {"count", 2, 4, FEARG_1, f_count},
402 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200403 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100404#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200405 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200406#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200407 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
408 {"delete", 1, 2, FEARG_1, f_delete},
409 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200410 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200411 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
412 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413 {"empty", 1, 1, FEARG_1, f_empty},
414 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200415 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200416 {"eval", 1, 1, FEARG_1, f_eval},
417 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200418 {"executable", 1, 1, FEARG_1, f_executable},
419 {"execute", 1, 2, FEARG_1, f_execute},
420 {"exepath", 1, 1, FEARG_1, f_exepath},
421 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200422#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200423 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200424#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200425 {"expand", 1, 3, FEARG_1, f_expand},
426 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200427 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200428 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
429 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
430 {"filereadable", 1, 1, FEARG_1, f_filereadable},
431 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200432 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200433 {"finddir", 1, 3, FEARG_1, f_finddir},
434 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200436 {"float2nr", 1, 1, FEARG_1, f_float2nr},
437 {"floor", 1, 1, FEARG_1, f_floor},
438 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200440 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
441 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
442 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
443 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
444 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200445 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200446 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200448 {"funcref", 1, 3, FEARG_1, f_funcref},
449 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200450 {"garbagecollect", 0, 1, 0, f_garbagecollect},
451 {"get", 2, 3, FEARG_1, f_get},
452 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200453 {"getbufline", 2, 3, FEARG_1, f_getbufline},
454 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
455 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200456 {"getchar", 0, 1, 0, f_getchar},
457 {"getcharmod", 0, 0, 0, f_getcharmod},
458 {"getcharsearch", 0, 0, 0, f_getcharsearch},
459 {"getcmdline", 0, 0, 0, f_getcmdline},
460 {"getcmdpos", 0, 0, 0, f_getcmdpos},
461 {"getcmdtype", 0, 0, 0, f_getcmdtype},
462 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200463 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200464 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200465 {"getcwd", 0, 2, FEARG_1, f_getcwd},
466 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200467 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200468 {"getfperm", 1, 1, FEARG_1, f_getfperm},
469 {"getfsize", 1, 1, FEARG_1, f_getfsize},
470 {"getftime", 1, 1, FEARG_1, f_getftime},
471 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200472 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200473 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
474 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200475 {"getloclist", 1, 2, 0, f_getloclist},
476 {"getmatches", 0, 1, 0, f_getmatches},
Bram Moolenaardb3a2052019-11-16 18:22:41 +0100477 {"getmousepos", 0, 0, 0, f_getmousepos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200478 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200479 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200480 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200481 {"getreg", 0, 3, FEARG_1, f_getreg},
482 {"getregtype", 0, 1, FEARG_1, f_getregtype},
483 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
484 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
485 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200486 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
487 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
488 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200489 {"getwinposx", 0, 0, 0, f_getwinposx},
490 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200491 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
492 {"glob", 1, 4, FEARG_1, f_glob},
493 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
494 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200495 {"has", 1, 1, 0, f_has},
496 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200497 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
498 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
499 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
500 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
501 {"histadd", 2, 2, FEARG_2, f_histadd},
502 {"histdel", 1, 2, FEARG_1, f_histdel},
503 {"histget", 1, 2, FEARG_1, f_histget},
504 {"histnr", 1, 1, FEARG_1, f_histnr},
505 {"hlID", 1, 1, FEARG_1, f_hlID},
506 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200508 {"iconv", 3, 3, FEARG_1, f_iconv},
509 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200510 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200511 {"input", 1, 3, FEARG_1, f_input},
512 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
513 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200514 {"inputrestore", 0, 0, 0, f_inputrestore},
515 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200516 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200517 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100518 {"interrupt", 0, 0, 0, f_interrupt},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200519 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200520 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200521#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200522 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200523#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200524 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200526 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200528 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200530 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
531 {"job_info", 0, 1, FEARG_1, f_job_info},
532 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
533 {"job_start", 1, 2, FEARG_1, f_job_start},
534 {"job_status", 1, 1, FEARG_1, f_job_status},
535 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200537 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200538 {"js_decode", 1, 1, FEARG_1, f_js_decode},
539 {"js_encode", 1, 1, FEARG_1, f_js_encode},
540 {"json_decode", 1, 1, FEARG_1, f_json_decode},
541 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200542 {"keys", 1, 1, FEARG_1, f_keys},
543 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
544 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200545 {"libcall", 3, 3, FEARG_3, f_libcall},
546 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200547 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200548 {"line2byte", 1, 1, FEARG_1, f_line2byte},
549 {"lispindent", 1, 1, FEARG_1, f_lispindent},
550 {"list2str", 1, 2, FEARG_1, f_list2str},
551 {"listener_add", 1, 2, FEARG_2, f_listener_add},
552 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
553 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200554 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200555#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200556 {"log", 1, 1, FEARG_1, f_log},
557 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#endif
559#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200560 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200561#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200562 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200563 {"maparg", 1, 4, FEARG_1, f_maparg},
564 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
565 {"match", 2, 4, FEARG_1, f_match},
566 {"matchadd", 2, 5, FEARG_1, f_matchadd},
567 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
568 {"matcharg", 1, 1, FEARG_1, f_matcharg},
569 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
570 {"matchend", 2, 4, FEARG_1, f_matchend},
571 {"matchlist", 2, 4, FEARG_1, f_matchlist},
572 {"matchstr", 2, 4, FEARG_1, f_matchstr},
573 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200574 {"max", 1, 1, FEARG_1, f_max},
575 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200576 {"mkdir", 1, 3, FEARG_1, f_mkdir},
577 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200579 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200580#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200581 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
582 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200583 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200584 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200585#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200586 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200587#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100588#ifdef FEAT_PROP_POPUP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200589 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
590 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200591 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200592 {"popup_close", 1, 2, FEARG_1, f_popup_close},
593 {"popup_create", 2, 2, FEARG_1, f_popup_create},
594 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200595 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
596 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200597 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
598 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200599 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
600 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
601 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200602 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200603 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
604 {"popup_move", 2, 2, FEARG_1, f_popup_move},
605 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
606 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
607 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
608 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200609#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200611 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200612#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200613 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200614 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200615#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200616 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
617 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
618 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200619#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100620#ifdef FEAT_PROP_POPUP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200621 {"prop_add", 3, 3, FEARG_1, f_prop_add},
622 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
623 {"prop_list", 1, 2, FEARG_1, f_prop_list},
624 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
625 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
626 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
627 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
628 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
629 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100630#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200631 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200632 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200634 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
636#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200637 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200638#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100639#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200640 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100641#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100642 {"rand", 0, 1, FEARG_1, f_rand},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200643 {"range", 1, 3, FEARG_1, f_range},
644 {"readdir", 1, 2, FEARG_1, f_readdir},
645 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200646 {"reg_executing", 0, 0, 0, f_reg_executing},
647 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200648 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200650 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200652 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
653 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
654 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
655 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
656 {"remote_read", 1, 2, FEARG_1, f_remote_read},
657 {"remote_send", 2, 3, FEARG_1, f_remote_send},
658 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200659 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200660 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200661 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200662 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200663 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200664#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200665 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100667#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200668 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100669#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200670 {"screenattr", 2, 2, FEARG_1, f_screenattr},
671 {"screenchar", 2, 2, FEARG_1, f_screenchar},
672 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200673 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200674 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200675 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200676 {"screenstring", 2, 2, FEARG_1, f_screenstring},
677 {"search", 1, 4, FEARG_1, f_search},
678 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200679 {"searchpair", 3, 7, 0, f_searchpair},
680 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200681 {"searchpos", 1, 4, FEARG_1, f_searchpos},
682 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200683 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200684 {"setbufline", 3, 3, FEARG_3, f_setbufline},
685 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
686 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
687 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
688 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200689 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200690 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200691 {"setloclist", 2, 4, FEARG_2, f_setloclist},
692 {"setmatches", 1, 2, FEARG_1, f_setmatches},
693 {"setpos", 2, 2, FEARG_2, f_setpos},
694 {"setqflist", 1, 3, FEARG_1, f_setqflist},
695 {"setreg", 2, 3, FEARG_2, f_setreg},
696 {"settabvar", 3, 3, FEARG_3, f_settabvar},
697 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
698 {"settagstack", 2, 3, FEARG_2, f_settagstack},
699 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200700#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200701 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200702#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200703 {"shellescape", 1, 2, FEARG_1, f_shellescape},
704 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100705#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200706 {"sign_define", 1, 2, FEARG_1, f_sign_define},
707 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
708 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
709 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
710 {"sign_place", 4, 5, FEARG_1, f_sign_place},
711 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
712 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
713 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
714 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100715#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200716 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200717#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200718 {"sin", 1, 1, FEARG_1, f_sin},
719 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200720#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200721 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200722#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200723 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200724 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
725 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
726 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200727#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200728 {"soundfold", 1, 1, FEARG_1, f_soundfold},
729 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
730 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200731 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200732#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200733 {"sqrt", 1, 1, FEARG_1, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200734#endif
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100735 {"srand", 0, 1, FEARG_1, f_srand},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200736 {"state", 0, 1, FEARG_1, f_state},
737#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200738 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200739#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200740 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200741 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200742 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
743 {"strchars", 1, 2, FEARG_1, f_strchars},
744 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200745#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200746 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200748 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
749 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"string", 1, 1, FEARG_1, f_string},
751 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200752 {"strpart", 2, 3, FEARG_1, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100753#ifdef HAVE_STRPTIME
754 {"strptime", 2, 2, FEARG_1, f_strptime},
755#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200756 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"strtrans", 1, 1, FEARG_1, f_strtrans},
758 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200759 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200760 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200761 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
762 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200763 {"synID", 3, 3, 0, f_synID},
764 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
765 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
766 {"synconcealed", 2, 2, 0, f_synconcealed},
767 {"synstack", 2, 2, 0, f_synstack},
768 {"system", 1, 2, FEARG_1, f_system},
769 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200770 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200771 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200772 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200773 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200774 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200775#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200776 {"tan", 1, 1, FEARG_1, f_tan},
777 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200779 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200780#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200781 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
782 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
783 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
784 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200785# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200786 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200788 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
789 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
790 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
791 {"term_getline", 2, 2, FEARG_1, f_term_getline},
792 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
793 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
794 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
795 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
796 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200797 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200798 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
799 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200800# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200801 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200802# endif
Bram Moolenaard2842ea2019-09-26 23:08:54 +0200803 {"term_setapi", 2, 2, FEARG_1, f_term_setapi},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200804 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
805 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
806 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
807 {"term_start", 1, 2, FEARG_1, f_term_start},
808 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200809#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200810 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200811 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200812 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
813 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
814 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
815 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
816 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200817 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200818#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200819 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200821 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200823 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200825 {"test_null_list", 0, 0, 0, f_test_null_list},
826 {"test_null_partial", 0, 0, 0, f_test_null_partial},
827 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200828 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
829 {"test_override", 2, 2, FEARG_2, f_test_override},
830 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200831#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200832 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200833#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200834 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200835 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200837 {"timer_info", 0, 1, FEARG_1, f_timer_info},
838 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
839 {"timer_start", 2, 3, FEARG_1, f_timer_start},
840 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200841 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200843 {"tolower", 1, 1, FEARG_1, f_tolower},
844 {"toupper", 1, 1, FEARG_1, f_toupper},
845 {"tr", 3, 3, FEARG_1, f_tr},
846 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200848 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200850 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200851 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200852 {"undotree", 0, 0, 0, f_undotree},
853 {"uniq", 1, 3, FEARG_1, f_uniq},
854 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200855 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200856 {"visualmode", 0, 1, 0, f_visualmode},
857 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200858 {"win_execute", 2, 3, FEARG_2, f_win_execute},
859 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
860 {"win_getid", 0, 2, FEARG_1, f_win_getid},
861 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
862 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
863 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
864 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200865 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200866 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200867 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100868 {"windowsversion", 0, 0, 0, f_windowsversion},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200869 {"winheight", 1, 1, FEARG_1, f_winheight},
870 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200871 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200872 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200873 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200874 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200875 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200876 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200877 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200878 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200879 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200880};
881
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200882/*
883 * Function given to ExpandGeneric() to obtain the list of internal
884 * or user defined function names.
885 */
886 char_u *
887get_function_name(expand_T *xp, int idx)
888{
889 static int intidx = -1;
890 char_u *name;
891
892 if (idx == 0)
893 intidx = -1;
894 if (intidx < 0)
895 {
896 name = get_user_func_name(xp, idx);
897 if (name != NULL)
898 return name;
899 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200900 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200901 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200902 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200903 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200904 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200905 STRCAT(IObuff, ")");
906 return IObuff;
907 }
908
909 return NULL;
910}
911
912/*
913 * Function given to ExpandGeneric() to obtain the list of internal or
914 * user defined variable or function names.
915 */
916 char_u *
917get_expr_name(expand_T *xp, int idx)
918{
919 static int intidx = -1;
920 char_u *name;
921
922 if (idx == 0)
923 intidx = -1;
924 if (intidx < 0)
925 {
926 name = get_function_name(xp, idx);
927 if (name != NULL)
928 return name;
929 }
930 return get_user_var_name(xp, ++intidx);
931}
932
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200933/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200934 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935 * Return index, or -1 if not found
936 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200937 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939{
940 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200941 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200942 int cmp;
943 int x;
944
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200945 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200946
947 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948 while (first <= last)
949 {
950 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200951 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200952 if (cmp < 0)
953 last = x - 1;
954 else if (cmp > 0)
955 first = x + 1;
956 else
957 return x;
958 }
959 return -1;
960}
961
962 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200963has_internal_func(char_u *name)
964{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200965 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200966}
967
968 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200969call_internal_func(
970 char_u *name,
971 int argcount,
972 typval_T *argvars,
973 typval_T *rettv)
974{
975 int i;
976
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200977 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +0100979 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200980 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +0100981 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200982 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +0100983 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200984 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200985 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +0100986 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200987}
988
989/*
990 * Invoke a method for base->method().
991 */
992 int
993call_internal_method(
994 char_u *name,
995 int argcount,
996 typval_T *argvars,
997 typval_T *rettv,
998 typval_T *basetv)
999{
1000 int i;
1001 int fi;
1002 typval_T argv[MAX_FUNC_ARGS + 1];
1003
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001004 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001005 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001006 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001007 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001008 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001009 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001010 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001011 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001012 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001013
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001014 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001015 {
1016 // base value goes last
1017 for (i = 0; i < argcount; ++i)
1018 argv[i] = argvars[i];
1019 argv[argcount] = *basetv;
1020 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001021 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001022 {
1023 // base value goes second
1024 argv[0] = argvars[0];
1025 argv[1] = *basetv;
1026 for (i = 1; i < argcount; ++i)
1027 argv[i + 1] = argvars[i];
1028 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001029 else if (global_functions[fi].f_argtype == FEARG_3)
1030 {
1031 // base value goes third
1032 argv[0] = argvars[0];
1033 argv[1] = argvars[1];
1034 argv[2] = *basetv;
1035 for (i = 2; i < argcount; ++i)
1036 argv[i + 1] = argvars[i];
1037 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001038 else if (global_functions[fi].f_argtype == FEARG_4)
1039 {
1040 // base value goes fourth
1041 argv[0] = argvars[0];
1042 argv[1] = argvars[1];
1043 argv[2] = argvars[2];
1044 argv[3] = *basetv;
1045 for (i = 3; i < argcount; ++i)
1046 argv[i + 1] = argvars[i];
1047 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001048 else
1049 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001050 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001051 argv[0] = *basetv;
1052 for (i = 0; i < argcount; ++i)
1053 argv[i + 1] = argvars[i];
1054 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001055 argv[argcount + 1].v_type = VAR_UNKNOWN;
1056
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001057 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001058 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001059}
1060
1061/*
1062 * Return TRUE for a non-zero Number and a non-empty String.
1063 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001064 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001065non_zero_arg(typval_T *argvars)
1066{
1067 return ((argvars[0].v_type == VAR_NUMBER
1068 && argvars[0].vval.v_number != 0)
1069 || (argvars[0].v_type == VAR_SPECIAL
1070 && argvars[0].vval.v_number == VVAL_TRUE)
1071 || (argvars[0].v_type == VAR_STRING
1072 && argvars[0].vval.v_string != NULL
1073 && *argvars[0].vval.v_string != NUL));
1074}
1075
1076/*
1077 * Get the lnum from the first argument.
1078 * Also accepts ".", "$", etc., but that only works for the current buffer.
1079 * Returns -1 on error.
1080 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001081 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001082tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001083{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001084 linenr_T lnum;
1085
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001086 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001087 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001088 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001089 int fnum;
1090 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1091
1092 if (fp != NULL)
1093 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001094 }
1095 return lnum;
1096}
1097
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001098/*
1099 * Get the lnum from the first argument.
1100 * Also accepts "$", then "buf" is used.
1101 * Returns 0 on error.
1102 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001103 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001104tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1105{
1106 if (argvars[0].v_type == VAR_STRING
1107 && argvars[0].vval.v_string != NULL
1108 && argvars[0].vval.v_string[0] == '$'
1109 && buf != NULL)
1110 return buf->b_ml.ml_line_count;
1111 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1112}
1113
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001114#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001115/*
1116 * Get the float value of "argvars[0]" into "f".
1117 * Returns FAIL when the argument is not a Number or Float.
1118 */
1119 static int
1120get_float_arg(typval_T *argvars, float_T *f)
1121{
1122 if (argvars[0].v_type == VAR_FLOAT)
1123 {
1124 *f = argvars[0].vval.v_float;
1125 return OK;
1126 }
1127 if (argvars[0].v_type == VAR_NUMBER)
1128 {
1129 *f = (float_T)argvars[0].vval.v_number;
1130 return OK;
1131 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001132 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001133 return FAIL;
1134}
1135
1136/*
1137 * "abs(expr)" function
1138 */
1139 static void
1140f_abs(typval_T *argvars, typval_T *rettv)
1141{
1142 if (argvars[0].v_type == VAR_FLOAT)
1143 {
1144 rettv->v_type = VAR_FLOAT;
1145 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1146 }
1147 else
1148 {
1149 varnumber_T n;
1150 int error = FALSE;
1151
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001152 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001153 if (error)
1154 rettv->vval.v_number = -1;
1155 else if (n > 0)
1156 rettv->vval.v_number = n;
1157 else
1158 rettv->vval.v_number = -n;
1159 }
1160}
1161
1162/*
1163 * "acos()" function
1164 */
1165 static void
1166f_acos(typval_T *argvars, typval_T *rettv)
1167{
1168 float_T f = 0.0;
1169
1170 rettv->v_type = VAR_FLOAT;
1171 if (get_float_arg(argvars, &f) == OK)
1172 rettv->vval.v_float = acos(f);
1173 else
1174 rettv->vval.v_float = 0.0;
1175}
1176#endif
1177
1178/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001179 * "and(expr, expr)" function
1180 */
1181 static void
1182f_and(typval_T *argvars, typval_T *rettv)
1183{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001184 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1185 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001186}
1187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001188#ifdef FEAT_FLOAT
1189/*
1190 * "asin()" function
1191 */
1192 static void
1193f_asin(typval_T *argvars, typval_T *rettv)
1194{
1195 float_T f = 0.0;
1196
1197 rettv->v_type = VAR_FLOAT;
1198 if (get_float_arg(argvars, &f) == OK)
1199 rettv->vval.v_float = asin(f);
1200 else
1201 rettv->vval.v_float = 0.0;
1202}
1203
1204/*
1205 * "atan()" function
1206 */
1207 static void
1208f_atan(typval_T *argvars, typval_T *rettv)
1209{
1210 float_T f = 0.0;
1211
1212 rettv->v_type = VAR_FLOAT;
1213 if (get_float_arg(argvars, &f) == OK)
1214 rettv->vval.v_float = atan(f);
1215 else
1216 rettv->vval.v_float = 0.0;
1217}
1218
1219/*
1220 * "atan2()" function
1221 */
1222 static void
1223f_atan2(typval_T *argvars, typval_T *rettv)
1224{
1225 float_T fx = 0.0, fy = 0.0;
1226
1227 rettv->v_type = VAR_FLOAT;
1228 if (get_float_arg(argvars, &fx) == OK
1229 && get_float_arg(&argvars[1], &fy) == OK)
1230 rettv->vval.v_float = atan2(fx, fy);
1231 else
1232 rettv->vval.v_float = 0.0;
1233}
1234#endif
1235
1236/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001237 * "balloon_show()" function
1238 */
1239#ifdef FEAT_BEVAL
1240 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001241f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1242{
1243 rettv->v_type = VAR_STRING;
1244 if (balloonEval != NULL)
1245 {
1246 if (balloonEval->msg == NULL)
1247 rettv->vval.v_string = NULL;
1248 else
1249 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1250 }
1251}
1252
1253 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001254f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1255{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001256 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001257 {
1258 if (argvars[0].v_type == VAR_LIST
1259# ifdef FEAT_GUI
1260 && !gui.in_use
1261# endif
1262 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001263 {
1264 list_T *l = argvars[0].vval.v_list;
1265
1266 // empty list removes the balloon
1267 post_balloon(balloonEval, NULL,
1268 l == NULL || l->lv_len == 0 ? NULL : l);
1269 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001270 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001271 {
1272 char_u *mesg = tv_get_string_chk(&argvars[0]);
1273
1274 if (mesg != NULL)
1275 // empty string removes the balloon
1276 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1277 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001278 }
1279}
1280
Bram Moolenaar669a8282017-11-19 20:13:05 +01001281# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001282 static void
1283f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1284{
1285 if (rettv_list_alloc(rettv) == OK)
1286 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001287 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001288
1289 if (msg != NULL)
1290 {
1291 pumitem_T *array;
1292 int size = split_message(msg, &array);
1293 int i;
1294
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001295 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001296 for (i = 1; i < size - 1; ++i)
1297 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001298 while (size > 0)
1299 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001300 vim_free(array);
1301 }
1302 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001303}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001304# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001305#endif
1306
1307/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001308 * Get buffer by number or pattern.
1309 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001310 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001311tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001312{
1313 char_u *name = tv->vval.v_string;
1314 buf_T *buf;
1315
1316 if (tv->v_type == VAR_NUMBER)
1317 return buflist_findnr((int)tv->vval.v_number);
1318 if (tv->v_type != VAR_STRING)
1319 return NULL;
1320 if (name == NULL || *name == NUL)
1321 return curbuf;
1322 if (name[0] == '$' && name[1] == NUL)
1323 return lastbuf;
1324
1325 buf = buflist_find_by_name(name, curtab_only);
1326
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001327 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001328 if (buf == NULL)
1329 buf = find_buffer(tv);
1330
1331 return buf;
1332}
1333
1334/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001335 * Get the buffer from "arg" and give an error and return NULL if it is not
1336 * valid.
1337 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001338 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001339get_buf_arg(typval_T *arg)
1340{
1341 buf_T *buf;
1342
1343 ++emsg_off;
1344 buf = tv_get_buf(arg, FALSE);
1345 --emsg_off;
1346 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001347 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001348 return buf;
1349}
1350
1351/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352 * "byte2line(byte)" function
1353 */
1354 static void
1355f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1356{
1357#ifndef FEAT_BYTEOFF
1358 rettv->vval.v_number = -1;
1359#else
1360 long boff = 0;
1361
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001362 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001363 if (boff < 0)
1364 rettv->vval.v_number = -1;
1365 else
1366 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1367 (linenr_T)0, &boff);
1368#endif
1369}
1370
1371 static void
1372byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1373{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001374 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001375 char_u *str;
1376 varnumber_T idx;
1377
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001378 str = tv_get_string_chk(&argvars[0]);
1379 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380 rettv->vval.v_number = -1;
1381 if (str == NULL || idx < 0)
1382 return;
1383
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001384 t = str;
1385 for ( ; idx > 0; idx--)
1386 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001387 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001388 return;
1389 if (enc_utf8 && comp)
1390 t += utf_ptr2len(t);
1391 else
1392 t += (*mb_ptr2len)(t);
1393 }
1394 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001395}
1396
1397/*
1398 * "byteidx()" function
1399 */
1400 static void
1401f_byteidx(typval_T *argvars, typval_T *rettv)
1402{
1403 byteidx(argvars, rettv, FALSE);
1404}
1405
1406/*
1407 * "byteidxcomp()" function
1408 */
1409 static void
1410f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1411{
1412 byteidx(argvars, rettv, TRUE);
1413}
1414
1415/*
1416 * "call(func, arglist [, dict])" function
1417 */
1418 static void
1419f_call(typval_T *argvars, typval_T *rettv)
1420{
1421 char_u *func;
1422 partial_T *partial = NULL;
1423 dict_T *selfdict = NULL;
1424
1425 if (argvars[1].v_type != VAR_LIST)
1426 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001427 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001428 return;
1429 }
1430 if (argvars[1].vval.v_list == NULL)
1431 return;
1432
1433 if (argvars[0].v_type == VAR_FUNC)
1434 func = argvars[0].vval.v_string;
1435 else if (argvars[0].v_type == VAR_PARTIAL)
1436 {
1437 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001438 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001439 }
1440 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001441 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001442 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001443 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001444
1445 if (argvars[2].v_type != VAR_UNKNOWN)
1446 {
1447 if (argvars[2].v_type != VAR_DICT)
1448 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001449 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001450 return;
1451 }
1452 selfdict = argvars[2].vval.v_dict;
1453 }
1454
1455 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1456}
1457
1458#ifdef FEAT_FLOAT
1459/*
1460 * "ceil({float})" function
1461 */
1462 static void
1463f_ceil(typval_T *argvars, typval_T *rettv)
1464{
1465 float_T f = 0.0;
1466
1467 rettv->v_type = VAR_FLOAT;
1468 if (get_float_arg(argvars, &f) == OK)
1469 rettv->vval.v_float = ceil(f);
1470 else
1471 rettv->vval.v_float = 0.0;
1472}
1473#endif
1474
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001475/*
1476 * "changenr()" function
1477 */
1478 static void
1479f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1480{
1481 rettv->vval.v_number = curbuf->b_u_seq_cur;
1482}
1483
1484/*
1485 * "char2nr(string)" function
1486 */
1487 static void
1488f_char2nr(typval_T *argvars, typval_T *rettv)
1489{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490 if (has_mbyte)
1491 {
1492 int utf8 = 0;
1493
1494 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001495 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496
1497 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001498 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001500 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 }
1502 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001503 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504}
1505
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001506 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001507get_optional_window(typval_T *argvars, int idx)
1508{
1509 win_T *win = curwin;
1510
1511 if (argvars[idx].v_type != VAR_UNKNOWN)
1512 {
1513 win = find_win_by_nr_or_id(&argvars[idx]);
1514 if (win == NULL)
1515 {
1516 emsg(_(e_invalwindow));
1517 return NULL;
1518 }
1519 }
1520 return win;
1521}
1522
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001524 * "col(string)" function
1525 */
1526 static void
1527f_col(typval_T *argvars, typval_T *rettv)
1528{
1529 colnr_T col = 0;
1530 pos_T *fp;
1531 int fnum = curbuf->b_fnum;
1532
1533 fp = var2fpos(&argvars[0], FALSE, &fnum);
1534 if (fp != NULL && fnum == curbuf->b_fnum)
1535 {
1536 if (fp->col == MAXCOL)
1537 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001538 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001539 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1540 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1541 else
1542 col = MAXCOL;
1543 }
1544 else
1545 {
1546 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001547 // col(".") when the cursor is on the NUL at the end of the line
1548 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549 if (virtual_active() && fp == &curwin->w_cursor)
1550 {
1551 char_u *p = ml_get_cursor();
1552
1553 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1554 curwin->w_virtcol - curwin->w_cursor.coladd))
1555 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 int l;
1557
1558 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1559 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560 }
1561 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562 }
1563 }
1564 rettv->vval.v_number = col;
1565}
1566
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567/*
1568 * "confirm(message, buttons[, default [, type]])" function
1569 */
1570 static void
1571f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1572{
1573#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1574 char_u *message;
1575 char_u *buttons = NULL;
1576 char_u buf[NUMBUFLEN];
1577 char_u buf2[NUMBUFLEN];
1578 int def = 1;
1579 int type = VIM_GENERIC;
1580 char_u *typestr;
1581 int error = FALSE;
1582
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001583 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001584 if (message == NULL)
1585 error = TRUE;
1586 if (argvars[1].v_type != VAR_UNKNOWN)
1587 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001588 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001589 if (buttons == NULL)
1590 error = TRUE;
1591 if (argvars[2].v_type != VAR_UNKNOWN)
1592 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001593 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594 if (argvars[3].v_type != VAR_UNKNOWN)
1595 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001596 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 if (typestr == NULL)
1598 error = TRUE;
1599 else
1600 {
1601 switch (TOUPPER_ASC(*typestr))
1602 {
1603 case 'E': type = VIM_ERROR; break;
1604 case 'Q': type = VIM_QUESTION; break;
1605 case 'I': type = VIM_INFO; break;
1606 case 'W': type = VIM_WARNING; break;
1607 case 'G': type = VIM_GENERIC; break;
1608 }
1609 }
1610 }
1611 }
1612 }
1613
1614 if (buttons == NULL || *buttons == NUL)
1615 buttons = (char_u *)_("&Ok");
1616
1617 if (!error)
1618 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1619 def, NULL, FALSE);
1620#endif
1621}
1622
1623/*
1624 * "copy()" function
1625 */
1626 static void
1627f_copy(typval_T *argvars, typval_T *rettv)
1628{
1629 item_copy(&argvars[0], rettv, FALSE, 0);
1630}
1631
1632#ifdef FEAT_FLOAT
1633/*
1634 * "cos()" function
1635 */
1636 static void
1637f_cos(typval_T *argvars, typval_T *rettv)
1638{
1639 float_T f = 0.0;
1640
1641 rettv->v_type = VAR_FLOAT;
1642 if (get_float_arg(argvars, &f) == OK)
1643 rettv->vval.v_float = cos(f);
1644 else
1645 rettv->vval.v_float = 0.0;
1646}
1647
1648/*
1649 * "cosh()" function
1650 */
1651 static void
1652f_cosh(typval_T *argvars, typval_T *rettv)
1653{
1654 float_T f = 0.0;
1655
1656 rettv->v_type = VAR_FLOAT;
1657 if (get_float_arg(argvars, &f) == OK)
1658 rettv->vval.v_float = cosh(f);
1659 else
1660 rettv->vval.v_float = 0.0;
1661}
1662#endif
1663
1664/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665 * "cursor(lnum, col)" function, or
1666 * "cursor(list)"
1667 *
1668 * Moves the cursor to the specified line and column.
1669 * Returns 0 when the position could be set, -1 otherwise.
1670 */
1671 static void
1672f_cursor(typval_T *argvars, typval_T *rettv)
1673{
1674 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001676 int set_curswant = TRUE;
1677
1678 rettv->vval.v_number = -1;
1679 if (argvars[1].v_type == VAR_UNKNOWN)
1680 {
1681 pos_T pos;
1682 colnr_T curswant = -1;
1683
1684 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1685 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001686 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 return;
1688 }
1689 line = pos.lnum;
1690 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692 if (curswant >= 0)
1693 {
1694 curwin->w_curswant = curswant - 1;
1695 set_curswant = FALSE;
1696 }
1697 }
1698 else
1699 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001700 line = tv_get_lnum(argvars);
1701 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001703 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001704 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001705 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001706 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001707 if (line > 0)
1708 curwin->w_cursor.lnum = line;
1709 if (col > 0)
1710 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001711 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001713 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001715 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 if (has_mbyte)
1717 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718
1719 curwin->w_set_curswant = set_curswant;
1720 rettv->vval.v_number = 0;
1721}
1722
Bram Moolenaar4f974752019-02-17 17:44:42 +01001723#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001724/*
1725 * "debugbreak()" function
1726 */
1727 static void
1728f_debugbreak(typval_T *argvars, typval_T *rettv)
1729{
1730 int pid;
1731
1732 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001733 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001734 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001735 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001736 else
1737 {
1738 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1739
1740 if (hProcess != NULL)
1741 {
1742 DebugBreakProcess(hProcess);
1743 CloseHandle(hProcess);
1744 rettv->vval.v_number = OK;
1745 }
1746 }
1747}
1748#endif
1749
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001750/*
1751 * "deepcopy()" function
1752 */
1753 static void
1754f_deepcopy(typval_T *argvars, typval_T *rettv)
1755{
1756 int noref = 0;
1757 int copyID;
1758
1759 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001760 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001761 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001762 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001763 else
1764 {
1765 copyID = get_copyID();
1766 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1767 }
1768}
1769
1770/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771 * "did_filetype()" function
1772 */
1773 static void
1774f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1775{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001776 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001777}
1778
1779/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001780 * "empty({expr})" function
1781 */
1782 static void
1783f_empty(typval_T *argvars, typval_T *rettv)
1784{
1785 int n = FALSE;
1786
1787 switch (argvars[0].v_type)
1788 {
1789 case VAR_STRING:
1790 case VAR_FUNC:
1791 n = argvars[0].vval.v_string == NULL
1792 || *argvars[0].vval.v_string == NUL;
1793 break;
1794 case VAR_PARTIAL:
1795 n = FALSE;
1796 break;
1797 case VAR_NUMBER:
1798 n = argvars[0].vval.v_number == 0;
1799 break;
1800 case VAR_FLOAT:
1801#ifdef FEAT_FLOAT
1802 n = argvars[0].vval.v_float == 0.0;
1803 break;
1804#endif
1805 case VAR_LIST:
1806 n = argvars[0].vval.v_list == NULL
1807 || argvars[0].vval.v_list->lv_first == NULL;
1808 break;
1809 case VAR_DICT:
1810 n = argvars[0].vval.v_dict == NULL
1811 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1812 break;
1813 case VAR_SPECIAL:
1814 n = argvars[0].vval.v_number != VVAL_TRUE;
1815 break;
1816
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001817 case VAR_BLOB:
1818 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001819 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1820 break;
1821
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822 case VAR_JOB:
1823#ifdef FEAT_JOB_CHANNEL
1824 n = argvars[0].vval.v_job == NULL
1825 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1826 break;
1827#endif
1828 case VAR_CHANNEL:
1829#ifdef FEAT_JOB_CHANNEL
1830 n = argvars[0].vval.v_channel == NULL
1831 || !channel_is_open(argvars[0].vval.v_channel);
1832 break;
1833#endif
1834 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001835 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001836 n = TRUE;
1837 break;
1838 }
1839
1840 rettv->vval.v_number = n;
1841}
1842
1843/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001844 * "environ()" function
1845 */
1846 static void
1847f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1848{
1849#if !defined(AMIGA)
1850 int i = 0;
1851 char_u *entry, *value;
1852# ifdef MSWIN
1853 extern wchar_t **_wenviron;
1854# else
1855 extern char **environ;
1856# endif
1857
1858 if (rettv_dict_alloc(rettv) != OK)
1859 return;
1860
1861# ifdef MSWIN
1862 if (*_wenviron == NULL)
1863 return;
1864# else
1865 if (*environ == NULL)
1866 return;
1867# endif
1868
1869 for (i = 0; ; ++i)
1870 {
1871# ifdef MSWIN
1872 short_u *p;
1873
1874 if ((p = (short_u *)_wenviron[i]) == NULL)
1875 return;
1876 entry = utf16_to_enc(p, NULL);
1877# else
1878 if ((entry = (char_u *)environ[i]) == NULL)
1879 return;
1880 entry = vim_strsave(entry);
1881# endif
1882 if (entry == NULL) // out of memory
1883 return;
1884 if ((value = vim_strchr(entry, '=')) == NULL)
1885 {
1886 vim_free(entry);
1887 continue;
1888 }
1889 *value++ = NUL;
1890 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1891 vim_free(entry);
1892 }
1893#endif
1894}
1895
1896/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001897 * "escape({string}, {chars})" function
1898 */
1899 static void
1900f_escape(typval_T *argvars, typval_T *rettv)
1901{
1902 char_u buf[NUMBUFLEN];
1903
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001904 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1905 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001906 rettv->v_type = VAR_STRING;
1907}
1908
1909/*
1910 * "eval()" function
1911 */
1912 static void
1913f_eval(typval_T *argvars, typval_T *rettv)
1914{
1915 char_u *s, *p;
1916
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001917 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001918 if (s != NULL)
1919 s = skipwhite(s);
1920
1921 p = s;
1922 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1923 {
1924 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001925 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001926 need_clr_eos = FALSE;
1927 rettv->v_type = VAR_NUMBER;
1928 rettv->vval.v_number = 0;
1929 }
1930 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001931 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001932}
1933
1934/*
1935 * "eventhandler()" function
1936 */
1937 static void
1938f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1939{
1940 rettv->vval.v_number = vgetc_busy;
1941}
1942
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001943static garray_T redir_execute_ga;
1944
1945/*
1946 * Append "value[value_len]" to the execute() output.
1947 */
1948 void
1949execute_redir_str(char_u *value, int value_len)
1950{
1951 int len;
1952
1953 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001954 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001956 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 if (ga_grow(&redir_execute_ga, len) == OK)
1958 {
1959 mch_memmove((char *)redir_execute_ga.ga_data
1960 + redir_execute_ga.ga_len, value, len);
1961 redir_execute_ga.ga_len += len;
1962 }
1963}
1964
1965/*
1966 * Get next line from a list.
1967 * Called by do_cmdline() to get the next line.
1968 * Returns allocated string, or NULL for end of function.
1969 */
1970
1971 static char_u *
1972get_list_line(
1973 int c UNUSED,
1974 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001975 int indent UNUSED,
1976 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001977{
1978 listitem_T **p = (listitem_T **)cookie;
1979 listitem_T *item = *p;
1980 char_u buf[NUMBUFLEN];
1981 char_u *s;
1982
1983 if (item == NULL)
1984 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001985 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 *p = item->li_next;
1987 return s == NULL ? NULL : vim_strsave(s);
1988}
1989
1990/*
1991 * "execute()" function
1992 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001993 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001994execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995{
1996 char_u *cmd = NULL;
1997 list_T *list = NULL;
1998 int save_msg_silent = msg_silent;
1999 int save_emsg_silent = emsg_silent;
2000 int save_emsg_noredir = emsg_noredir;
2001 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002002 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002003 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002004 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002005 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006
2007 rettv->vval.v_string = NULL;
2008 rettv->v_type = VAR_STRING;
2009
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002010 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002012 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 if (list == NULL || list->lv_first == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002014 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002015 return;
2016 ++list->lv_refcount;
2017 }
2018 else
2019 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002020 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 if (cmd == NULL)
2022 return;
2023 }
2024
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002025 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002026 {
2027 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002028 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002029
2030 if (s == NULL)
2031 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002032 if (*s == NUL)
2033 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002034 if (STRNCMP(s, "silent", 6) == 0)
2035 ++msg_silent;
2036 if (STRCMP(s, "silent!") == 0)
2037 {
2038 emsg_silent = TRUE;
2039 emsg_noredir = TRUE;
2040 }
2041 }
2042 else
2043 ++msg_silent;
2044
2045 if (redir_execute)
2046 save_ga = redir_execute_ga;
2047 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2048 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002049 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002050 if (!echo_output)
2051 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052
2053 if (cmd != NULL)
2054 do_cmdline_cmd(cmd);
2055 else
2056 {
2057 listitem_T *item = list->lv_first;
2058
2059 do_cmdline(NULL, get_list_line, (void *)&item,
2060 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2061 --list->lv_refcount;
2062 }
2063
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002064 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002065 if (ga_grow(&redir_execute_ga, 1) == OK)
2066 {
2067 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2068 rettv->vval.v_string = redir_execute_ga.ga_data;
2069 }
2070 else
2071 {
2072 ga_clear(&redir_execute_ga);
2073 rettv->vval.v_string = NULL;
2074 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002075 msg_silent = save_msg_silent;
2076 emsg_silent = save_emsg_silent;
2077 emsg_noredir = save_emsg_noredir;
2078
2079 redir_execute = save_redir_execute;
2080 if (redir_execute)
2081 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002082 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002084 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002085 if (echo_output)
2086 // When not working silently: put it in column zero. A following
2087 // "echon" will overwrite the message, unavoidably.
2088 msg_col = 0;
2089 else
2090 // When working silently: Put it back where it was, since nothing
2091 // should have been written.
2092 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093}
2094
2095/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002096 * "execute()" function
2097 */
2098 static void
2099f_execute(typval_T *argvars, typval_T *rettv)
2100{
2101 execute_common(argvars, rettv, 0);
2102}
2103
2104/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002105 * "exists()" function
2106 */
2107 static void
2108f_exists(typval_T *argvars, typval_T *rettv)
2109{
2110 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002111 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002112
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002113 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002114 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002115 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002116 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002117 if (mch_getenv(p + 1) != NULL)
2118 n = TRUE;
2119 else
2120 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002121 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 p = expand_env_save(p);
2123 if (p != NULL && *p != '$')
2124 n = TRUE;
2125 vim_free(p);
2126 }
2127 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002128 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002129 {
2130 n = (get_option_tv(&p, NULL, TRUE) == OK);
2131 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002132 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002134 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002136 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137 }
2138 else if (*p == ':')
2139 {
2140 n = cmd_exists(p + 1);
2141 }
2142 else if (*p == '#')
2143 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002144 if (p[1] == '#')
2145 n = autocmd_supported(p + 2);
2146 else
2147 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002149 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002150 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002151 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 }
2153
2154 rettv->vval.v_number = n;
2155}
2156
2157#ifdef FEAT_FLOAT
2158/*
2159 * "exp()" function
2160 */
2161 static void
2162f_exp(typval_T *argvars, typval_T *rettv)
2163{
2164 float_T f = 0.0;
2165
2166 rettv->v_type = VAR_FLOAT;
2167 if (get_float_arg(argvars, &f) == OK)
2168 rettv->vval.v_float = exp(f);
2169 else
2170 rettv->vval.v_float = 0.0;
2171}
2172#endif
2173
2174/*
2175 * "expand()" function
2176 */
2177 static void
2178f_expand(typval_T *argvars, typval_T *rettv)
2179{
2180 char_u *s;
2181 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002182 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2184 expand_T xpc;
2185 int error = FALSE;
2186 char_u *result;
2187
2188 rettv->v_type = VAR_STRING;
2189 if (argvars[1].v_type != VAR_UNKNOWN
2190 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002191 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002193 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002194
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002195 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196 if (*s == '%' || *s == '#' || *s == '<')
2197 {
2198 ++emsg_off;
2199 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2200 --emsg_off;
2201 if (rettv->v_type == VAR_LIST)
2202 {
2203 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2204 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002205 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206 }
2207 else
2208 rettv->vval.v_string = result;
2209 }
2210 else
2211 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002212 // When the optional second argument is non-zero, don't remove matches
2213 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002214 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002215 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 options |= WILD_KEEP_ALL;
2217 if (!error)
2218 {
2219 ExpandInit(&xpc);
2220 xpc.xp_context = EXPAND_FILES;
2221 if (p_wic)
2222 options += WILD_ICASE;
2223 if (rettv->v_type == VAR_STRING)
2224 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2225 options, WILD_ALL);
2226 else if (rettv_list_alloc(rettv) != FAIL)
2227 {
2228 int i;
2229
2230 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2231 for (i = 0; i < xpc.xp_numfiles; i++)
2232 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2233 ExpandCleanup(&xpc);
2234 }
2235 }
2236 else
2237 rettv->vval.v_string = NULL;
2238 }
2239}
2240
2241/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002242 * "expandcmd()" function
2243 * Expand all the special characters in a command string.
2244 */
2245 static void
2246f_expandcmd(typval_T *argvars, typval_T *rettv)
2247{
2248 exarg_T eap;
2249 char_u *cmdstr;
2250 char *errormsg = NULL;
2251
2252 rettv->v_type = VAR_STRING;
2253 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2254
2255 memset(&eap, 0, sizeof(eap));
2256 eap.cmd = cmdstr;
2257 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002258 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002259 eap.usefilter = FALSE;
2260 eap.nextcmd = NULL;
2261 eap.cmdidx = CMD_USER;
2262
2263 expand_filename(&eap, &cmdstr, &errormsg);
2264 if (errormsg != NULL && *errormsg != NUL)
2265 emsg(errormsg);
2266
2267 rettv->vval.v_string = cmdstr;
2268}
2269
2270/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002271 * "feedkeys()" function
2272 */
2273 static void
2274f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2275{
2276 int remap = TRUE;
2277 int insert = FALSE;
2278 char_u *keys, *flags;
2279 char_u nbuf[NUMBUFLEN];
2280 int typed = FALSE;
2281 int execute = FALSE;
2282 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002283 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002284 char_u *keys_esc;
2285
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002286 // This is not allowed in the sandbox. If the commands would still be
2287 // executed in the sandbox it would be OK, but it probably happens later,
2288 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002289 if (check_secure())
2290 return;
2291
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002292 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293
2294 if (argvars[1].v_type != VAR_UNKNOWN)
2295 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002296 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 for ( ; *flags != NUL; ++flags)
2298 {
2299 switch (*flags)
2300 {
2301 case 'n': remap = FALSE; break;
2302 case 'm': remap = TRUE; break;
2303 case 't': typed = TRUE; break;
2304 case 'i': insert = TRUE; break;
2305 case 'x': execute = TRUE; break;
2306 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002307 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 }
2309 }
2310 }
2311
2312 if (*keys != NUL || execute)
2313 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002314 // Need to escape K_SPECIAL and CSI before putting the string in the
2315 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002316 keys_esc = vim_strsave_escape_csi(keys);
2317 if (keys_esc != NULL)
2318 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002319 if (lowlevel)
2320 {
2321#ifdef USE_INPUT_BUF
2322 add_to_input_buf(keys, (int)STRLEN(keys));
2323#else
2324 emsg(_("E980: lowlevel input not supported"));
2325#endif
2326 }
2327 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002328 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002329 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002330 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002331 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002332#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002333 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002334#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002335 )
2336 typebuf_was_filled = TRUE;
2337 }
2338 vim_free(keys_esc);
2339
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002340 if (execute)
2341 {
2342 int save_msg_scroll = msg_scroll;
2343
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002344 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 msg_scroll = FALSE;
2346
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002347 if (!dangerous)
2348 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002349 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002350 if (!dangerous)
2351 --ex_normal_busy;
2352
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 msg_scroll |= save_msg_scroll;
2354 }
2355 }
2356 }
2357}
2358
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359#ifdef FEAT_FLOAT
2360/*
2361 * "float2nr({float})" function
2362 */
2363 static void
2364f_float2nr(typval_T *argvars, typval_T *rettv)
2365{
2366 float_T f = 0.0;
2367
2368 if (get_float_arg(argvars, &f) == OK)
2369 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002370 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002371 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002372 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002373 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002374 else
2375 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002376 }
2377}
2378
2379/*
2380 * "floor({float})" function
2381 */
2382 static void
2383f_floor(typval_T *argvars, typval_T *rettv)
2384{
2385 float_T f = 0.0;
2386
2387 rettv->v_type = VAR_FLOAT;
2388 if (get_float_arg(argvars, &f) == OK)
2389 rettv->vval.v_float = floor(f);
2390 else
2391 rettv->vval.v_float = 0.0;
2392}
2393
2394/*
2395 * "fmod()" function
2396 */
2397 static void
2398f_fmod(typval_T *argvars, typval_T *rettv)
2399{
2400 float_T fx = 0.0, fy = 0.0;
2401
2402 rettv->v_type = VAR_FLOAT;
2403 if (get_float_arg(argvars, &fx) == OK
2404 && get_float_arg(&argvars[1], &fy) == OK)
2405 rettv->vval.v_float = fmod(fx, fy);
2406 else
2407 rettv->vval.v_float = 0.0;
2408}
2409#endif
2410
2411/*
2412 * "fnameescape({string})" function
2413 */
2414 static void
2415f_fnameescape(typval_T *argvars, typval_T *rettv)
2416{
2417 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002418 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419 rettv->v_type = VAR_STRING;
2420}
2421
2422/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423 * "foreground()" function
2424 */
2425 static void
2426f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2427{
2428#ifdef FEAT_GUI
2429 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002430 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002431 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002432 return;
2433 }
2434#endif
2435#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437#endif
2438}
2439
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002441common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442{
2443 char_u *s;
2444 char_u *name;
2445 int use_string = FALSE;
2446 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002447 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448
2449 if (argvars[0].v_type == VAR_FUNC)
2450 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002451 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 s = argvars[0].vval.v_string;
2453 }
2454 else if (argvars[0].v_type == VAR_PARTIAL
2455 && argvars[0].vval.v_partial != NULL)
2456 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002457 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002459 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 }
2461 else
2462 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002463 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002464 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 use_string = TRUE;
2466 }
2467
Bram Moolenaar843b8842016-08-21 14:36:15 +02002468 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002469 {
2470 name = s;
2471 trans_name = trans_function_name(&name, FALSE,
2472 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2473 if (*name != NUL)
2474 s = NULL;
2475 }
2476
Bram Moolenaar843b8842016-08-21 14:36:15 +02002477 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2478 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002479 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002480 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002481 else if (trans_name != NULL && (is_funcref
2482 ? find_func(trans_name) == NULL
2483 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002484 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002485 else
2486 {
2487 int dict_idx = 0;
2488 int arg_idx = 0;
2489 list_T *list = NULL;
2490
2491 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2492 {
2493 char sid_buf[25];
2494 int off = *s == 's' ? 2 : 5;
2495
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002496 // Expand s: and <SID> into <SNR>nr_, so that the function can
2497 // also be called from another script. Using trans_function_name()
2498 // would also work, but some plugins depend on the name being
2499 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002500 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002501 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002502 if (name != NULL)
2503 {
2504 STRCPY(name, sid_buf);
2505 STRCAT(name, s + off);
2506 }
2507 }
2508 else
2509 name = vim_strsave(s);
2510
2511 if (argvars[1].v_type != VAR_UNKNOWN)
2512 {
2513 if (argvars[2].v_type != VAR_UNKNOWN)
2514 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002515 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002516 arg_idx = 1;
2517 dict_idx = 2;
2518 }
2519 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002520 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521 dict_idx = 1;
2522 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002523 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 arg_idx = 1;
2525 if (dict_idx > 0)
2526 {
2527 if (argvars[dict_idx].v_type != VAR_DICT)
2528 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002529 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002530 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002531 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532 }
2533 if (argvars[dict_idx].vval.v_dict == NULL)
2534 dict_idx = 0;
2535 }
2536 if (arg_idx > 0)
2537 {
2538 if (argvars[arg_idx].v_type != VAR_LIST)
2539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002540 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002542 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 }
2544 list = argvars[arg_idx].vval.v_list;
2545 if (list == NULL || list->lv_len == 0)
2546 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002547 else if (list->lv_len > MAX_FUNC_ARGS)
2548 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002549 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002550 vim_free(name);
2551 goto theend;
2552 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002553 }
2554 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002555 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002556 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002557 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002558
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002559 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002560 if (pt == NULL)
2561 vim_free(name);
2562 else
2563 {
2564 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2565 {
2566 listitem_T *li;
2567 int i = 0;
2568 int arg_len = 0;
2569 int lv_len = 0;
2570
2571 if (arg_pt != NULL)
2572 arg_len = arg_pt->pt_argc;
2573 if (list != NULL)
2574 lv_len = list->lv_len;
2575 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002576 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002577 if (pt->pt_argv == NULL)
2578 {
2579 vim_free(pt);
2580 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002581 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002583 for (i = 0; i < arg_len; i++)
2584 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2585 if (lv_len > 0)
2586 for (li = list->lv_first; li != NULL;
2587 li = li->li_next)
2588 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002589 }
2590
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002591 // For "function(dict.func, [], dict)" and "func" is a partial
2592 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 if (dict_idx > 0)
2594 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002595 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002596 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2597 ++pt->pt_dict->dv_refcount;
2598 }
2599 else if (arg_pt != NULL)
2600 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002601 // If the dict was bound automatically the result is also
2602 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 pt->pt_dict = arg_pt->pt_dict;
2604 pt->pt_auto = arg_pt->pt_auto;
2605 if (pt->pt_dict != NULL)
2606 ++pt->pt_dict->dv_refcount;
2607 }
2608
2609 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002610 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2611 {
2612 pt->pt_func = arg_pt->pt_func;
2613 func_ptr_ref(pt->pt_func);
2614 vim_free(name);
2615 }
2616 else if (is_funcref)
2617 {
2618 pt->pt_func = find_func(trans_name);
2619 func_ptr_ref(pt->pt_func);
2620 vim_free(name);
2621 }
2622 else
2623 {
2624 pt->pt_name = name;
2625 func_ref(name);
2626 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 }
2628 rettv->v_type = VAR_PARTIAL;
2629 rettv->vval.v_partial = pt;
2630 }
2631 else
2632 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002633 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002634 rettv->v_type = VAR_FUNC;
2635 rettv->vval.v_string = name;
2636 func_ref(name);
2637 }
2638 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002639theend:
2640 vim_free(trans_name);
2641}
2642
2643/*
2644 * "funcref()" function
2645 */
2646 static void
2647f_funcref(typval_T *argvars, typval_T *rettv)
2648{
2649 common_function(argvars, rettv, TRUE);
2650}
2651
2652/*
2653 * "function()" function
2654 */
2655 static void
2656f_function(typval_T *argvars, typval_T *rettv)
2657{
2658 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002659}
2660
2661/*
2662 * "garbagecollect()" function
2663 */
2664 static void
2665f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2666{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002667 // This is postponed until we are back at the toplevel, because we may be
2668 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669 want_garbage_collect = TRUE;
2670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002671 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 garbage_collect_at_exit = TRUE;
2673}
2674
2675/*
2676 * "get()" function
2677 */
2678 static void
2679f_get(typval_T *argvars, typval_T *rettv)
2680{
2681 listitem_T *li;
2682 list_T *l;
2683 dictitem_T *di;
2684 dict_T *d;
2685 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002686 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002687
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002688 if (argvars[0].v_type == VAR_BLOB)
2689 {
2690 int error = FALSE;
2691 int idx = tv_get_number_chk(&argvars[1], &error);
2692
2693 if (!error)
2694 {
2695 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002696 if (idx < 0)
2697 idx = blob_len(argvars[0].vval.v_blob) + idx;
2698 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2699 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002700 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002701 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002702 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002703 tv = rettv;
2704 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002705 }
2706 }
2707 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002708 {
2709 if ((l = argvars[0].vval.v_list) != NULL)
2710 {
2711 int error = FALSE;
2712
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002713 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 if (!error && li != NULL)
2715 tv = &li->li_tv;
2716 }
2717 }
2718 else if (argvars[0].v_type == VAR_DICT)
2719 {
2720 if ((d = argvars[0].vval.v_dict) != NULL)
2721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002722 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002723 if (di != NULL)
2724 tv = &di->di_tv;
2725 }
2726 }
2727 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2728 {
2729 partial_T *pt;
2730 partial_T fref_pt;
2731
2732 if (argvars[0].v_type == VAR_PARTIAL)
2733 pt = argvars[0].vval.v_partial;
2734 else
2735 {
2736 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2737 fref_pt.pt_name = argvars[0].vval.v_string;
2738 pt = &fref_pt;
2739 }
2740
2741 if (pt != NULL)
2742 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002743 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002744 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002745
2746 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2747 {
2748 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002749 n = partial_name(pt);
2750 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002751 rettv->vval.v_string = NULL;
2752 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002753 {
2754 rettv->vval.v_string = vim_strsave(n);
2755 if (rettv->v_type == VAR_FUNC)
2756 func_ref(rettv->vval.v_string);
2757 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002758 }
2759 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002760 {
2761 what_is_dict = TRUE;
2762 if (pt->pt_dict != NULL)
2763 rettv_dict_set(rettv, pt->pt_dict);
2764 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002765 else if (STRCMP(what, "args") == 0)
2766 {
2767 rettv->v_type = VAR_LIST;
2768 if (rettv_list_alloc(rettv) == OK)
2769 {
2770 int i;
2771
2772 for (i = 0; i < pt->pt_argc; ++i)
2773 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2774 }
2775 }
2776 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002777 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002778
2779 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2780 // third argument
2781 if (!what_is_dict)
2782 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 }
2784 }
2785 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002786 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787
2788 if (tv == NULL)
2789 {
2790 if (argvars[2].v_type != VAR_UNKNOWN)
2791 copy_tv(&argvars[2], rettv);
2792 }
2793 else
2794 copy_tv(tv, rettv);
2795}
2796
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002797/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002798 * "getchangelist()" function
2799 */
2800 static void
2801f_getchangelist(typval_T *argvars, typval_T *rettv)
2802{
2803#ifdef FEAT_JUMPLIST
2804 buf_T *buf;
2805 int i;
2806 list_T *l;
2807 dict_T *d;
2808#endif
2809
2810 if (rettv_list_alloc(rettv) != OK)
2811 return;
2812
2813#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002814 if (argvars[0].v_type == VAR_UNKNOWN)
2815 buf = curbuf;
2816 else
2817 {
2818 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2819 ++emsg_off;
2820 buf = tv_get_buf(&argvars[0], FALSE);
2821 --emsg_off;
2822 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002823 if (buf == NULL)
2824 return;
2825
2826 l = list_alloc();
2827 if (l == NULL)
2828 return;
2829
2830 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2831 return;
2832 /*
2833 * The current window change list index tracks only the position in the
2834 * current buffer change list. For other buffers, use the change list
2835 * length as the current index.
2836 */
2837 list_append_number(rettv->vval.v_list,
2838 (varnumber_T)((buf == curwin->w_buffer)
2839 ? curwin->w_changelistidx : buf->b_changelistlen));
2840
2841 for (i = 0; i < buf->b_changelistlen; ++i)
2842 {
2843 if (buf->b_changelist[i].lnum == 0)
2844 continue;
2845 if ((d = dict_alloc()) == NULL)
2846 return;
2847 if (list_append_dict(l, d) == FAIL)
2848 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002849 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2850 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002851 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002852 }
2853#endif
2854}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855
2856/*
2857 * "getcharsearch()" function
2858 */
2859 static void
2860f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2861{
2862 if (rettv_dict_alloc(rettv) != FAIL)
2863 {
2864 dict_T *dict = rettv->vval.v_dict;
2865
Bram Moolenaare0be1672018-07-08 16:50:37 +02002866 dict_add_string(dict, "char", last_csearch());
2867 dict_add_number(dict, "forward", last_csearch_forward());
2868 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869 }
2870}
2871
2872/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002873 * "getcmdwintype()" function
2874 */
2875 static void
2876f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2877{
2878 rettv->v_type = VAR_STRING;
2879 rettv->vval.v_string = NULL;
2880#ifdef FEAT_CMDWIN
2881 rettv->vval.v_string = alloc(2);
2882 if (rettv->vval.v_string != NULL)
2883 {
2884 rettv->vval.v_string[0] = cmdwin_type;
2885 rettv->vval.v_string[1] = NUL;
2886 }
2887#endif
2888}
2889
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002890/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002891 * "getenv()" function
2892 */
2893 static void
2894f_getenv(typval_T *argvars, typval_T *rettv)
2895{
2896 int mustfree = FALSE;
2897 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2898
2899 if (p == NULL)
2900 {
2901 rettv->v_type = VAR_SPECIAL;
2902 rettv->vval.v_number = VVAL_NULL;
2903 return;
2904 }
2905 if (!mustfree)
2906 p = vim_strsave(p);
2907 rettv->vval.v_string = p;
2908 rettv->v_type = VAR_STRING;
2909}
2910
2911/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 * "getfontname()" function
2913 */
2914 static void
2915f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2916{
2917 rettv->v_type = VAR_STRING;
2918 rettv->vval.v_string = NULL;
2919#ifdef FEAT_GUI
2920 if (gui.in_use)
2921 {
2922 GuiFont font;
2923 char_u *name = NULL;
2924
2925 if (argvars[0].v_type == VAR_UNKNOWN)
2926 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002927 // Get the "Normal" font. Either the name saved by
2928 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929 font = gui.norm_font;
2930 name = hl_get_font_name();
2931 }
2932 else
2933 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002934 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002935 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002936 return;
2937 font = gui_mch_get_font(name, FALSE);
2938 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002939 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 }
2941 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2942 if (argvars[0].v_type != VAR_UNKNOWN)
2943 gui_mch_free_font(font);
2944 }
2945#endif
2946}
2947
2948/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002949 * "getjumplist()" function
2950 */
2951 static void
2952f_getjumplist(typval_T *argvars, typval_T *rettv)
2953{
2954#ifdef FEAT_JUMPLIST
2955 win_T *wp;
2956 int i;
2957 list_T *l;
2958 dict_T *d;
2959#endif
2960
2961 if (rettv_list_alloc(rettv) != OK)
2962 return;
2963
2964#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002965 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002966 if (wp == NULL)
2967 return;
2968
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002969 cleanup_jumplist(wp, TRUE);
2970
Bram Moolenaar4f505882018-02-10 21:06:32 +01002971 l = list_alloc();
2972 if (l == NULL)
2973 return;
2974
2975 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2976 return;
2977 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2978
2979 for (i = 0; i < wp->w_jumplistlen; ++i)
2980 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002981 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2982 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002983 if ((d = dict_alloc()) == NULL)
2984 return;
2985 if (list_append_dict(l, d) == FAIL)
2986 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002987 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2988 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002989 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002990 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002991 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002992 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002993 }
2994#endif
2995}
2996
2997/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002998 * "getpid()" function
2999 */
3000 static void
3001f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3002{
3003 rettv->vval.v_number = mch_get_pid();
3004}
3005
3006 static void
3007getpos_both(
3008 typval_T *argvars,
3009 typval_T *rettv,
3010 int getcurpos)
3011{
3012 pos_T *fp;
3013 list_T *l;
3014 int fnum = -1;
3015
3016 if (rettv_list_alloc(rettv) == OK)
3017 {
3018 l = rettv->vval.v_list;
3019 if (getcurpos)
3020 fp = &curwin->w_cursor;
3021 else
3022 fp = var2fpos(&argvars[0], TRUE, &fnum);
3023 if (fnum != -1)
3024 list_append_number(l, (varnumber_T)fnum);
3025 else
3026 list_append_number(l, (varnumber_T)0);
3027 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3028 : (varnumber_T)0);
3029 list_append_number(l, (fp != NULL)
3030 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3031 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003032 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003033 (varnumber_T)0);
3034 if (getcurpos)
3035 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003036 int save_set_curswant = curwin->w_set_curswant;
3037 colnr_T save_curswant = curwin->w_curswant;
3038 colnr_T save_virtcol = curwin->w_virtcol;
3039
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003040 update_curswant();
3041 list_append_number(l, curwin->w_curswant == MAXCOL ?
3042 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003043
3044 // Do not change "curswant", as it is unexpected that a get
3045 // function has a side effect.
3046 if (save_set_curswant)
3047 {
3048 curwin->w_set_curswant = save_set_curswant;
3049 curwin->w_curswant = save_curswant;
3050 curwin->w_virtcol = save_virtcol;
3051 curwin->w_valid &= ~VALID_VIRTCOL;
3052 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003053 }
3054 }
3055 else
3056 rettv->vval.v_number = FALSE;
3057}
3058
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059/*
3060 * "getcurpos()" function
3061 */
3062 static void
3063f_getcurpos(typval_T *argvars, typval_T *rettv)
3064{
3065 getpos_both(argvars, rettv, TRUE);
3066}
3067
3068/*
3069 * "getpos(string)" function
3070 */
3071 static void
3072f_getpos(typval_T *argvars, typval_T *rettv)
3073{
3074 getpos_both(argvars, rettv, FALSE);
3075}
3076
3077/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003078 * "getreg()" function
3079 */
3080 static void
3081f_getreg(typval_T *argvars, typval_T *rettv)
3082{
3083 char_u *strregname;
3084 int regname;
3085 int arg2 = FALSE;
3086 int return_list = FALSE;
3087 int error = FALSE;
3088
3089 if (argvars[0].v_type != VAR_UNKNOWN)
3090 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003091 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003092 error = strregname == NULL;
3093 if (argvars[1].v_type != VAR_UNKNOWN)
3094 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003095 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003097 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098 }
3099 }
3100 else
3101 strregname = get_vim_var_str(VV_REG);
3102
3103 if (error)
3104 return;
3105
3106 regname = (strregname == NULL ? '"' : *strregname);
3107 if (regname == 0)
3108 regname = '"';
3109
3110 if (return_list)
3111 {
3112 rettv->v_type = VAR_LIST;
3113 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3114 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3115 if (rettv->vval.v_list == NULL)
3116 (void)rettv_list_alloc(rettv);
3117 else
3118 ++rettv->vval.v_list->lv_refcount;
3119 }
3120 else
3121 {
3122 rettv->v_type = VAR_STRING;
3123 rettv->vval.v_string = get_reg_contents(regname,
3124 arg2 ? GREG_EXPR_SRC : 0);
3125 }
3126}
3127
3128/*
3129 * "getregtype()" function
3130 */
3131 static void
3132f_getregtype(typval_T *argvars, typval_T *rettv)
3133{
3134 char_u *strregname;
3135 int regname;
3136 char_u buf[NUMBUFLEN + 2];
3137 long reglen = 0;
3138
3139 if (argvars[0].v_type != VAR_UNKNOWN)
3140 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003141 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003142 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003143 {
3144 rettv->v_type = VAR_STRING;
3145 rettv->vval.v_string = NULL;
3146 return;
3147 }
3148 }
3149 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003150 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003151 strregname = get_vim_var_str(VV_REG);
3152
3153 regname = (strregname == NULL ? '"' : *strregname);
3154 if (regname == 0)
3155 regname = '"';
3156
3157 buf[0] = NUL;
3158 buf[1] = NUL;
3159 switch (get_reg_type(regname, &reglen))
3160 {
3161 case MLINE: buf[0] = 'V'; break;
3162 case MCHAR: buf[0] = 'v'; break;
3163 case MBLOCK:
3164 buf[0] = Ctrl_V;
3165 sprintf((char *)buf + 1, "%ld", reglen + 1);
3166 break;
3167 }
3168 rettv->v_type = VAR_STRING;
3169 rettv->vval.v_string = vim_strsave(buf);
3170}
3171
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003172/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003173 * "gettagstack()" function
3174 */
3175 static void
3176f_gettagstack(typval_T *argvars, typval_T *rettv)
3177{
3178 win_T *wp = curwin; // default is current window
3179
3180 if (rettv_dict_alloc(rettv) != OK)
3181 return;
3182
3183 if (argvars[0].v_type != VAR_UNKNOWN)
3184 {
3185 wp = find_win_by_nr_or_id(&argvars[0]);
3186 if (wp == NULL)
3187 return;
3188 }
3189
3190 get_tagstack(wp, rettv->vval.v_dict);
3191}
3192
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003193// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003194#include "version.h"
3195
3196/*
3197 * "has()" function
3198 */
3199 static void
3200f_has(typval_T *argvars, typval_T *rettv)
3201{
3202 int i;
3203 char_u *name;
3204 int n = FALSE;
3205 static char *(has_list[]) =
3206 {
3207#ifdef AMIGA
3208 "amiga",
3209# ifdef FEAT_ARP
3210 "arp",
3211# endif
3212#endif
3213#ifdef __BEOS__
3214 "beos",
3215#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003216#if defined(BSD) && !defined(MACOS_X)
3217 "bsd",
3218#endif
3219#ifdef hpux
3220 "hpux",
3221#endif
3222#ifdef __linux__
3223 "linux",
3224#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003225#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003226 "mac", // Mac OS X (and, once, Mac OS Classic)
3227 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003228# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003229 "macunix", // Mac OS X, with the darwin feature
3230 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003231# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003232#endif
3233#ifdef __QNX__
3234 "qnx",
3235#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003236#ifdef SUN_SYSTEM
3237 "sun",
3238#else
3239 "moon",
3240#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003241#ifdef UNIX
3242 "unix",
3243#endif
3244#ifdef VMS
3245 "vms",
3246#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003247#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248 "win32",
3249#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003250#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003251 "win32unix",
3252#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003253#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003254 "win64",
3255#endif
3256#ifdef EBCDIC
3257 "ebcdic",
3258#endif
3259#ifndef CASE_INSENSITIVE_FILENAME
3260 "fname_case",
3261#endif
3262#ifdef HAVE_ACL
3263 "acl",
3264#endif
3265#ifdef FEAT_ARABIC
3266 "arabic",
3267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003269#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003270 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003271#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003272#ifdef FEAT_AUTOSERVERNAME
3273 "autoservername",
3274#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003275#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003276 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003277# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003278 "balloon_multiline",
3279# endif
3280#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003281#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003282 "balloon_eval_term",
3283#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3285 "builtin_terms",
3286# ifdef ALL_BUILTIN_TCAPS
3287 "all_builtin_terms",
3288# endif
3289#endif
3290#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003291 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292 || defined(FEAT_GUI_MOTIF))
3293 "browsefilter",
3294#endif
3295#ifdef FEAT_BYTEOFF
3296 "byte_offset",
3297#endif
3298#ifdef FEAT_JOB_CHANNEL
3299 "channel",
3300#endif
3301#ifdef FEAT_CINDENT
3302 "cindent",
3303#endif
3304#ifdef FEAT_CLIENTSERVER
3305 "clientserver",
3306#endif
3307#ifdef FEAT_CLIPBOARD
3308 "clipboard",
3309#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003310 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003311 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003313#ifdef FEAT_CONCEAL
3314 "conceal",
3315#endif
3316#ifdef FEAT_CRYPT
3317 "cryptv",
3318 "crypt-blowfish",
3319 "crypt-blowfish2",
3320#endif
3321#ifdef FEAT_CSCOPE
3322 "cscope",
3323#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003324 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003325#ifdef CURSOR_SHAPE
3326 "cursorshape",
3327#endif
3328#ifdef DEBUG
3329 "debug",
3330#endif
3331#ifdef FEAT_CON_DIALOG
3332 "dialog_con",
3333#endif
3334#ifdef FEAT_GUI_DIALOG
3335 "dialog_gui",
3336#endif
3337#ifdef FEAT_DIFF
3338 "diff",
3339#endif
3340#ifdef FEAT_DIGRAPHS
3341 "digraphs",
3342#endif
3343#ifdef FEAT_DIRECTX
3344 "directx",
3345#endif
3346#ifdef FEAT_DND
3347 "dnd",
3348#endif
3349#ifdef FEAT_EMACS_TAGS
3350 "emacs_tags",
3351#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003352 "eval", // always present, of course!
3353 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003354#ifdef FEAT_SEARCH_EXTRA
3355 "extra_search",
3356#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003357#ifdef FEAT_SEARCHPATH
3358 "file_in_path",
3359#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003360#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003361 "filterpipe",
3362#endif
3363#ifdef FEAT_FIND_ID
3364 "find_in_path",
3365#endif
3366#ifdef FEAT_FLOAT
3367 "float",
3368#endif
3369#ifdef FEAT_FOLDING
3370 "folding",
3371#endif
3372#ifdef FEAT_FOOTER
3373 "footer",
3374#endif
3375#if !defined(USE_SYSTEM) && defined(UNIX)
3376 "fork",
3377#endif
3378#ifdef FEAT_GETTEXT
3379 "gettext",
3380#endif
3381#ifdef FEAT_GUI
3382 "gui",
3383#endif
3384#ifdef FEAT_GUI_ATHENA
3385# ifdef FEAT_GUI_NEXTAW
3386 "gui_neXtaw",
3387# else
3388 "gui_athena",
3389# endif
3390#endif
3391#ifdef FEAT_GUI_GTK
3392 "gui_gtk",
3393# ifdef USE_GTK3
3394 "gui_gtk3",
3395# else
3396 "gui_gtk2",
3397# endif
3398#endif
3399#ifdef FEAT_GUI_GNOME
3400 "gui_gnome",
3401#endif
3402#ifdef FEAT_GUI_MAC
3403 "gui_mac",
3404#endif
3405#ifdef FEAT_GUI_MOTIF
3406 "gui_motif",
3407#endif
3408#ifdef FEAT_GUI_PHOTON
3409 "gui_photon",
3410#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003411#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412 "gui_win32",
3413#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3415 "iconv",
3416#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003417 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003418#ifdef FEAT_JOB_CHANNEL
3419 "job",
3420#endif
3421#ifdef FEAT_JUMPLIST
3422 "jumplist",
3423#endif
3424#ifdef FEAT_KEYMAP
3425 "keymap",
3426#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003427 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428#ifdef FEAT_LANGMAP
3429 "langmap",
3430#endif
3431#ifdef FEAT_LIBCALL
3432 "libcall",
3433#endif
3434#ifdef FEAT_LINEBREAK
3435 "linebreak",
3436#endif
3437#ifdef FEAT_LISP
3438 "lispindent",
3439#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003442#ifdef FEAT_LUA
3443# ifndef DYNAMIC_LUA
3444 "lua",
3445# endif
3446#endif
3447#ifdef FEAT_MENU
3448 "menu",
3449#endif
3450#ifdef FEAT_SESSION
3451 "mksession",
3452#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003453 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003454 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003455#ifdef FEAT_MOUSESHAPE
3456 "mouseshape",
3457#endif
3458#if defined(UNIX) || defined(VMS)
3459# ifdef FEAT_MOUSE_DEC
3460 "mouse_dec",
3461# endif
3462# ifdef FEAT_MOUSE_GPM
3463 "mouse_gpm",
3464# endif
3465# ifdef FEAT_MOUSE_JSB
3466 "mouse_jsbterm",
3467# endif
3468# ifdef FEAT_MOUSE_NET
3469 "mouse_netterm",
3470# endif
3471# ifdef FEAT_MOUSE_PTERM
3472 "mouse_pterm",
3473# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003474# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475 "mouse_sgr",
3476# endif
3477# ifdef FEAT_SYSMOUSE
3478 "mouse_sysmouse",
3479# endif
3480# ifdef FEAT_MOUSE_URXVT
3481 "mouse_urxvt",
3482# endif
3483# ifdef FEAT_MOUSE_XTERM
3484 "mouse_xterm",
3485# endif
3486#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003487 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003488#ifdef FEAT_MBYTE_IME
3489 "multi_byte_ime",
3490#endif
3491#ifdef FEAT_MULTI_LANG
3492 "multi_lang",
3493#endif
3494#ifdef FEAT_MZSCHEME
3495#ifndef DYNAMIC_MZSCHEME
3496 "mzscheme",
3497#endif
3498#endif
3499#ifdef FEAT_NUM64
3500 "num64",
3501#endif
3502#ifdef FEAT_OLE
3503 "ole",
3504#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003505#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003507#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003508#ifdef FEAT_PATH_EXTRA
3509 "path_extra",
3510#endif
3511#ifdef FEAT_PERL
3512#ifndef DYNAMIC_PERL
3513 "perl",
3514#endif
3515#endif
3516#ifdef FEAT_PERSISTENT_UNDO
3517 "persistent_undo",
3518#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003519#if defined(FEAT_PYTHON)
3520 "python_compiled",
3521# if defined(DYNAMIC_PYTHON)
3522 "python_dynamic",
3523# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003524 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003525 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003526# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003527#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003528#if defined(FEAT_PYTHON3)
3529 "python3_compiled",
3530# if defined(DYNAMIC_PYTHON3)
3531 "python3_dynamic",
3532# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003533 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003534 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003535# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003536#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003537#ifdef FEAT_PROP_POPUP
3538 "popupwin",
3539#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003540#ifdef FEAT_POSTSCRIPT
3541 "postscript",
3542#endif
3543#ifdef FEAT_PRINTER
3544 "printer",
3545#endif
3546#ifdef FEAT_PROFILE
3547 "profile",
3548#endif
3549#ifdef FEAT_RELTIME
3550 "reltime",
3551#endif
3552#ifdef FEAT_QUICKFIX
3553 "quickfix",
3554#endif
3555#ifdef FEAT_RIGHTLEFT
3556 "rightleft",
3557#endif
3558#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3559 "ruby",
3560#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003562#ifdef FEAT_CMDL_INFO
3563 "showcmd",
3564 "cmdline_info",
3565#endif
3566#ifdef FEAT_SIGNS
3567 "signs",
3568#endif
3569#ifdef FEAT_SMARTINDENT
3570 "smartindent",
3571#endif
3572#ifdef STARTUPTIME
3573 "startuptime",
3574#endif
3575#ifdef FEAT_STL_OPT
3576 "statusline",
3577#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578#ifdef FEAT_NETBEANS_INTG
3579 "netbeans_intg",
3580#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003581#ifdef FEAT_SOUND
3582 "sound",
3583#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003584#ifdef FEAT_SPELL
3585 "spell",
3586#endif
3587#ifdef FEAT_SYN_HL
3588 "syntax",
3589#endif
3590#if defined(USE_SYSTEM) || !defined(UNIX)
3591 "system",
3592#endif
3593#ifdef FEAT_TAG_BINS
3594 "tag_binary",
3595#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003596#ifdef FEAT_TCL
3597# ifndef DYNAMIC_TCL
3598 "tcl",
3599# endif
3600#endif
3601#ifdef FEAT_TERMGUICOLORS
3602 "termguicolors",
3603#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003604#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003605 "terminal",
3606#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607#ifdef TERMINFO
3608 "terminfo",
3609#endif
3610#ifdef FEAT_TERMRESPONSE
3611 "termresponse",
3612#endif
3613#ifdef FEAT_TEXTOBJ
3614 "textobjects",
3615#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003616#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003617 "textprop",
3618#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003619#ifdef HAVE_TGETENT
3620 "tgetent",
3621#endif
3622#ifdef FEAT_TIMERS
3623 "timers",
3624#endif
3625#ifdef FEAT_TITLE
3626 "title",
3627#endif
3628#ifdef FEAT_TOOLBAR
3629 "toolbar",
3630#endif
3631#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3632 "unnamedplus",
3633#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003634 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003636#ifdef FEAT_VARTABS
3637 "vartabs",
3638#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003639 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003640#ifdef FEAT_VIMINFO
3641 "viminfo",
3642#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003643 "vimscript-1",
3644 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003645 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003646 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003651#ifdef FEAT_VTP
3652 "vtp",
3653#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654#ifdef FEAT_WILDIGN
3655 "wildignore",
3656#endif
3657#ifdef FEAT_WILDMENU
3658 "wildmenu",
3659#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003660 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661#ifdef FEAT_WAK
3662 "winaltkeys",
3663#endif
3664#ifdef FEAT_WRITEBACKUP
3665 "writebackup",
3666#endif
3667#ifdef FEAT_XIM
3668 "xim",
3669#endif
3670#ifdef FEAT_XFONTSET
3671 "xfontset",
3672#endif
3673#ifdef FEAT_XPM_W32
3674 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003675 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003676#else
3677# if defined(HAVE_XPM)
3678 "xpm",
3679# endif
3680#endif
3681#ifdef USE_XSMP
3682 "xsmp",
3683#endif
3684#ifdef USE_XSMP_INTERACT
3685 "xsmp_interact",
3686#endif
3687#ifdef FEAT_XCLIPBOARD
3688 "xterm_clipboard",
3689#endif
3690#ifdef FEAT_XTERM_SAVE
3691 "xterm_save",
3692#endif
3693#if defined(UNIX) && defined(FEAT_X11)
3694 "X11",
3695#endif
3696 NULL
3697 };
3698
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003699 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003700 for (i = 0; has_list[i] != NULL; ++i)
3701 if (STRICMP(name, has_list[i]) == 0)
3702 {
3703 n = TRUE;
3704 break;
3705 }
3706
3707 if (n == FALSE)
3708 {
3709 if (STRNICMP(name, "patch", 5) == 0)
3710 {
3711 if (name[5] == '-'
3712 && STRLEN(name) >= 11
3713 && vim_isdigit(name[6])
3714 && vim_isdigit(name[8])
3715 && vim_isdigit(name[10]))
3716 {
3717 int major = atoi((char *)name + 6);
3718 int minor = atoi((char *)name + 8);
3719
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003720 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003721 n = (major < VIM_VERSION_MAJOR
3722 || (major == VIM_VERSION_MAJOR
3723 && (minor < VIM_VERSION_MINOR
3724 || (minor == VIM_VERSION_MINOR
3725 && has_patch(atoi((char *)name + 10))))));
3726 }
3727 else
3728 n = has_patch(atoi((char *)name + 5));
3729 }
3730 else if (STRICMP(name, "vim_starting") == 0)
3731 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003732 else if (STRICMP(name, "ttyin") == 0)
3733 n = mch_input_isatty();
3734 else if (STRICMP(name, "ttyout") == 0)
3735 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003736 else if (STRICMP(name, "multi_byte_encoding") == 0)
3737 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003738#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003739 else if (STRICMP(name, "balloon_multiline") == 0)
3740 n = multiline_balloon_available();
3741#endif
3742#ifdef DYNAMIC_TCL
3743 else if (STRICMP(name, "tcl") == 0)
3744 n = tcl_enabled(FALSE);
3745#endif
3746#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3747 else if (STRICMP(name, "iconv") == 0)
3748 n = iconv_enabled(FALSE);
3749#endif
3750#ifdef DYNAMIC_LUA
3751 else if (STRICMP(name, "lua") == 0)
3752 n = lua_enabled(FALSE);
3753#endif
3754#ifdef DYNAMIC_MZSCHEME
3755 else if (STRICMP(name, "mzscheme") == 0)
3756 n = mzscheme_enabled(FALSE);
3757#endif
3758#ifdef DYNAMIC_RUBY
3759 else if (STRICMP(name, "ruby") == 0)
3760 n = ruby_enabled(FALSE);
3761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003762#ifdef DYNAMIC_PYTHON
3763 else if (STRICMP(name, "python") == 0)
3764 n = python_enabled(FALSE);
3765#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003766#ifdef DYNAMIC_PYTHON3
3767 else if (STRICMP(name, "python3") == 0)
3768 n = python3_enabled(FALSE);
3769#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003770#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3771 else if (STRICMP(name, "pythonx") == 0)
3772 {
3773# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3774 if (p_pyx == 0)
3775 n = python3_enabled(FALSE) || python_enabled(FALSE);
3776 else if (p_pyx == 3)
3777 n = python3_enabled(FALSE);
3778 else if (p_pyx == 2)
3779 n = python_enabled(FALSE);
3780# elif defined(DYNAMIC_PYTHON)
3781 n = python_enabled(FALSE);
3782# elif defined(DYNAMIC_PYTHON3)
3783 n = python3_enabled(FALSE);
3784# endif
3785 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003786#endif
3787#ifdef DYNAMIC_PERL
3788 else if (STRICMP(name, "perl") == 0)
3789 n = perl_enabled(FALSE);
3790#endif
3791#ifdef FEAT_GUI
3792 else if (STRICMP(name, "gui_running") == 0)
3793 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003794# ifdef FEAT_BROWSE
3795 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003796 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003797# endif
3798#endif
3799#ifdef FEAT_SYN_HL
3800 else if (STRICMP(name, "syntax_items") == 0)
3801 n = syntax_present(curwin);
3802#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003803#ifdef FEAT_VTP
3804 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003805 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003806#endif
3807#ifdef FEAT_NETBEANS_INTG
3808 else if (STRICMP(name, "netbeans_enabled") == 0)
3809 n = netbeans_active();
3810#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003811#ifdef FEAT_MOUSE_GPM
3812 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3813 n = gpm_enabled();
3814#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003815#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003816 else if (STRICMP(name, "terminal") == 0)
3817 n = terminal_enabled();
3818#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003819#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003820 else if (STRICMP(name, "conpty") == 0)
3821 n = use_conpty();
3822#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003823#ifdef FEAT_CLIPBOARD
3824 else if (STRICMP(name, "clipboard_working") == 0)
3825 n = clip_star.available;
3826#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003827#ifdef VIMDLL
3828 else if (STRICMP(name, "filterpipe") == 0)
3829 n = gui.in_use || gui.starting;
3830#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831 }
3832
3833 rettv->vval.v_number = n;
3834}
3835
3836/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003837 * "haslocaldir()" function
3838 */
3839 static void
3840f_haslocaldir(typval_T *argvars, typval_T *rettv)
3841{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003842 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003843 win_T *wp = NULL;
3844
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003845 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3846
3847 // Check for window-local and tab-local directories
3848 if (wp != NULL && wp->w_localdir != NULL)
3849 rettv->vval.v_number = 1;
3850 else if (tp != NULL && tp->tp_localdir != NULL)
3851 rettv->vval.v_number = 2;
3852 else
3853 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003854}
3855
3856/*
3857 * "hasmapto()" function
3858 */
3859 static void
3860f_hasmapto(typval_T *argvars, typval_T *rettv)
3861{
3862 char_u *name;
3863 char_u *mode;
3864 char_u buf[NUMBUFLEN];
3865 int abbr = FALSE;
3866
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003867 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003868 if (argvars[1].v_type == VAR_UNKNOWN)
3869 mode = (char_u *)"nvo";
3870 else
3871 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003872 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003873 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003874 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003875 }
3876
3877 if (map_to_exists(name, mode, abbr))
3878 rettv->vval.v_number = TRUE;
3879 else
3880 rettv->vval.v_number = FALSE;
3881}
3882
3883/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003884 * "highlightID(name)" function
3885 */
3886 static void
3887f_hlID(typval_T *argvars, typval_T *rettv)
3888{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003889 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003890}
3891
3892/*
3893 * "highlight_exists()" function
3894 */
3895 static void
3896f_hlexists(typval_T *argvars, typval_T *rettv)
3897{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003898 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003899}
3900
3901/*
3902 * "hostname()" function
3903 */
3904 static void
3905f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3906{
3907 char_u hostname[256];
3908
3909 mch_get_host_name(hostname, 256);
3910 rettv->v_type = VAR_STRING;
3911 rettv->vval.v_string = vim_strsave(hostname);
3912}
3913
3914/*
3915 * iconv() function
3916 */
3917 static void
3918f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3919{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920 char_u buf1[NUMBUFLEN];
3921 char_u buf2[NUMBUFLEN];
3922 char_u *from, *to, *str;
3923 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003924
3925 rettv->v_type = VAR_STRING;
3926 rettv->vval.v_string = NULL;
3927
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003928 str = tv_get_string(&argvars[0]);
3929 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3930 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 vimconv.vc_type = CONV_NONE;
3932 convert_setup(&vimconv, from, to);
3933
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003934 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003935 if (vimconv.vc_type == CONV_NONE)
3936 rettv->vval.v_string = vim_strsave(str);
3937 else
3938 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3939
3940 convert_setup(&vimconv, NULL, NULL);
3941 vim_free(from);
3942 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003943}
3944
3945/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003946 * "index()" function
3947 */
3948 static void
3949f_index(typval_T *argvars, typval_T *rettv)
3950{
3951 list_T *l;
3952 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003953 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954 long idx = 0;
3955 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003956 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957
3958 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003959 if (argvars[0].v_type == VAR_BLOB)
3960 {
3961 typval_T tv;
3962 int start = 0;
3963
3964 if (argvars[2].v_type != VAR_UNKNOWN)
3965 {
3966 start = tv_get_number_chk(&argvars[2], &error);
3967 if (error)
3968 return;
3969 }
3970 b = argvars[0].vval.v_blob;
3971 if (b == NULL)
3972 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003973 if (start < 0)
3974 {
3975 start = blob_len(b) + start;
3976 if (start < 0)
3977 start = 0;
3978 }
3979
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003980 for (idx = start; idx < blob_len(b); ++idx)
3981 {
3982 tv.v_type = VAR_NUMBER;
3983 tv.vval.v_number = blob_get(b, idx);
3984 if (tv_equal(&tv, &argvars[1], ic, FALSE))
3985 {
3986 rettv->vval.v_number = idx;
3987 return;
3988 }
3989 }
3990 return;
3991 }
3992 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003993 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003994 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003995 return;
3996 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003997
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003998 l = argvars[0].vval.v_list;
3999 if (l != NULL)
4000 {
4001 item = l->lv_first;
4002 if (argvars[2].v_type != VAR_UNKNOWN)
4003 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004004 // Start at specified item. Use the cached index that list_find()
4005 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004006 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007 idx = l->lv_idx;
4008 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004009 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004010 if (error)
4011 item = NULL;
4012 }
4013
4014 for ( ; item != NULL; item = item->li_next, ++idx)
4015 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4016 {
4017 rettv->vval.v_number = idx;
4018 break;
4019 }
4020 }
4021}
4022
4023static int inputsecret_flag = 0;
4024
4025/*
4026 * "input()" function
4027 * Also handles inputsecret() when inputsecret is set.
4028 */
4029 static void
4030f_input(typval_T *argvars, typval_T *rettv)
4031{
4032 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4033}
4034
4035/*
4036 * "inputdialog()" function
4037 */
4038 static void
4039f_inputdialog(typval_T *argvars, typval_T *rettv)
4040{
4041#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004042 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004043 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4044 {
4045 char_u *message;
4046 char_u buf[NUMBUFLEN];
4047 char_u *defstr = (char_u *)"";
4048
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004049 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004050 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004051 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004052 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4053 else
4054 IObuff[0] = NUL;
4055 if (message != NULL && defstr != NULL
4056 && do_dialog(VIM_QUESTION, NULL, message,
4057 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4058 rettv->vval.v_string = vim_strsave(IObuff);
4059 else
4060 {
4061 if (message != NULL && defstr != NULL
4062 && argvars[1].v_type != VAR_UNKNOWN
4063 && argvars[2].v_type != VAR_UNKNOWN)
4064 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004065 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004066 else
4067 rettv->vval.v_string = NULL;
4068 }
4069 rettv->v_type = VAR_STRING;
4070 }
4071 else
4072#endif
4073 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4074}
4075
4076/*
4077 * "inputlist()" function
4078 */
4079 static void
4080f_inputlist(typval_T *argvars, typval_T *rettv)
4081{
4082 listitem_T *li;
4083 int selected;
4084 int mouse_used;
4085
4086#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004087 // While starting up, there is no place to enter text. When running tests
4088 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004089 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004090 return;
4091#endif
4092 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4093 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004094 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004095 return;
4096 }
4097
4098 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004099 msg_row = Rows - 1; // for when 'cmdheight' > 1
4100 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004101 msg_scroll = TRUE;
4102 msg_clr_eos();
4103
4104 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4105 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004106 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107 msg_putchar('\n');
4108 }
4109
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004110 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004111 selected = prompt_for_number(&mouse_used);
4112 if (mouse_used)
4113 selected -= lines_left;
4114
4115 rettv->vval.v_number = selected;
4116}
4117
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004118static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4119
4120/*
4121 * "inputrestore()" function
4122 */
4123 static void
4124f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4125{
4126 if (ga_userinput.ga_len > 0)
4127 {
4128 --ga_userinput.ga_len;
4129 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4130 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004131 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004132 }
4133 else if (p_verbose > 1)
4134 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004135 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004136 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004137 }
4138}
4139
4140/*
4141 * "inputsave()" function
4142 */
4143 static void
4144f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4145{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004146 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004147 if (ga_grow(&ga_userinput, 1) == OK)
4148 {
4149 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4150 + ga_userinput.ga_len);
4151 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004152 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004153 }
4154 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004155 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156}
4157
4158/*
4159 * "inputsecret()" function
4160 */
4161 static void
4162f_inputsecret(typval_T *argvars, typval_T *rettv)
4163{
4164 ++cmdline_star;
4165 ++inputsecret_flag;
4166 f_input(argvars, rettv);
4167 --cmdline_star;
4168 --inputsecret_flag;
4169}
4170
4171/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004172 * "interrupt()" function
4173 */
4174 static void
4175f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4176{
4177 got_int = TRUE;
4178}
4179
4180/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004181 * "invert(expr)" function
4182 */
4183 static void
4184f_invert(typval_T *argvars, typval_T *rettv)
4185{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004186 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004187}
4188
4189/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004190 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4191 * or it refers to a List or Dictionary that is locked.
4192 */
4193 static int
4194tv_islocked(typval_T *tv)
4195{
4196 return (tv->v_lock & VAR_LOCKED)
4197 || (tv->v_type == VAR_LIST
4198 && tv->vval.v_list != NULL
4199 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4200 || (tv->v_type == VAR_DICT
4201 && tv->vval.v_dict != NULL
4202 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4203}
4204
4205/*
4206 * "islocked()" function
4207 */
4208 static void
4209f_islocked(typval_T *argvars, typval_T *rettv)
4210{
4211 lval_T lv;
4212 char_u *end;
4213 dictitem_T *di;
4214
4215 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004216 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004217 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218 if (end != NULL && lv.ll_name != NULL)
4219 {
4220 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004221 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004222 else
4223 {
4224 if (lv.ll_tv == NULL)
4225 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004226 di = find_var(lv.ll_name, NULL, TRUE);
4227 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004228 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004229 // Consider a variable locked when:
4230 // 1. the variable itself is locked
4231 // 2. the value of the variable is locked.
4232 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004233 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4234 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004235 }
4236 }
4237 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004238 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004239 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004240 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004241 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004242 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004243 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4244 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004245 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004246 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4247 }
4248 }
4249
4250 clear_lval(&lv);
4251}
4252
4253#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4254/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004255 * "isinf()" function
4256 */
4257 static void
4258f_isinf(typval_T *argvars, typval_T *rettv)
4259{
4260 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4261 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4262}
4263
4264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 * "isnan()" function
4266 */
4267 static void
4268f_isnan(typval_T *argvars, typval_T *rettv)
4269{
4270 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4271 && isnan(argvars[0].vval.v_float);
4272}
4273#endif
4274
4275/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004276 * "last_buffer_nr()" function.
4277 */
4278 static void
4279f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4280{
4281 int n = 0;
4282 buf_T *buf;
4283
Bram Moolenaar29323592016-07-24 22:04:11 +02004284 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004285 if (n < buf->b_fnum)
4286 n = buf->b_fnum;
4287
4288 rettv->vval.v_number = n;
4289}
4290
4291/*
4292 * "len()" function
4293 */
4294 static void
4295f_len(typval_T *argvars, typval_T *rettv)
4296{
4297 switch (argvars[0].v_type)
4298 {
4299 case VAR_STRING:
4300 case VAR_NUMBER:
4301 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004302 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004303 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004304 case VAR_BLOB:
4305 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4306 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307 case VAR_LIST:
4308 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4309 break;
4310 case VAR_DICT:
4311 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4312 break;
4313 case VAR_UNKNOWN:
4314 case VAR_SPECIAL:
4315 case VAR_FLOAT:
4316 case VAR_FUNC:
4317 case VAR_PARTIAL:
4318 case VAR_JOB:
4319 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004320 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004321 break;
4322 }
4323}
4324
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004325 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004326libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004327{
4328#ifdef FEAT_LIBCALL
4329 char_u *string_in;
4330 char_u **string_result;
4331 int nr_result;
4332#endif
4333
4334 rettv->v_type = type;
4335 if (type != VAR_NUMBER)
4336 rettv->vval.v_string = NULL;
4337
4338 if (check_restricted() || check_secure())
4339 return;
4340
4341#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004342 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004343 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4344 {
4345 string_in = NULL;
4346 if (argvars[2].v_type == VAR_STRING)
4347 string_in = argvars[2].vval.v_string;
4348 if (type == VAR_NUMBER)
4349 string_result = NULL;
4350 else
4351 string_result = &rettv->vval.v_string;
4352 if (mch_libcall(argvars[0].vval.v_string,
4353 argvars[1].vval.v_string,
4354 string_in,
4355 argvars[2].vval.v_number,
4356 string_result,
4357 &nr_result) == OK
4358 && type == VAR_NUMBER)
4359 rettv->vval.v_number = nr_result;
4360 }
4361#endif
4362}
4363
4364/*
4365 * "libcall()" function
4366 */
4367 static void
4368f_libcall(typval_T *argvars, typval_T *rettv)
4369{
4370 libcall_common(argvars, rettv, VAR_STRING);
4371}
4372
4373/*
4374 * "libcallnr()" function
4375 */
4376 static void
4377f_libcallnr(typval_T *argvars, typval_T *rettv)
4378{
4379 libcall_common(argvars, rettv, VAR_NUMBER);
4380}
4381
4382/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004383 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 */
4385 static void
4386f_line(typval_T *argvars, typval_T *rettv)
4387{
4388 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004389 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004390 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004391 int id;
4392 tabpage_T *tp;
4393 win_T *wp;
4394 win_T *save_curwin;
4395 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004396
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004397 if (argvars[1].v_type != VAR_UNKNOWN)
4398 {
4399 // use window specified in the second argument
4400 id = (int)tv_get_number(&argvars[1]);
4401 wp = win_id2wp_tp(id, &tp);
4402 if (wp != NULL && tp != NULL)
4403 {
4404 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4405 == OK)
4406 {
4407 check_cursor();
4408 fp = var2fpos(&argvars[0], TRUE, &fnum);
4409 }
4410 restore_win_noblock(save_curwin, save_curtab, TRUE);
4411 }
4412 }
4413 else
4414 // use current window
4415 fp = var2fpos(&argvars[0], TRUE, &fnum);
4416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004417 if (fp != NULL)
4418 lnum = fp->lnum;
4419 rettv->vval.v_number = lnum;
4420}
4421
4422/*
4423 * "line2byte(lnum)" function
4424 */
4425 static void
4426f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4427{
4428#ifndef FEAT_BYTEOFF
4429 rettv->vval.v_number = -1;
4430#else
4431 linenr_T lnum;
4432
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004433 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004434 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4435 rettv->vval.v_number = -1;
4436 else
4437 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4438 if (rettv->vval.v_number >= 0)
4439 ++rettv->vval.v_number;
4440#endif
4441}
4442
4443/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004444 * "localtime()" function
4445 */
4446 static void
4447f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4448{
4449 rettv->vval.v_number = (varnumber_T)time(NULL);
4450}
4451
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452#ifdef FEAT_FLOAT
4453/*
4454 * "log()" function
4455 */
4456 static void
4457f_log(typval_T *argvars, typval_T *rettv)
4458{
4459 float_T f = 0.0;
4460
4461 rettv->v_type = VAR_FLOAT;
4462 if (get_float_arg(argvars, &f) == OK)
4463 rettv->vval.v_float = log(f);
4464 else
4465 rettv->vval.v_float = 0.0;
4466}
4467
4468/*
4469 * "log10()" function
4470 */
4471 static void
4472f_log10(typval_T *argvars, typval_T *rettv)
4473{
4474 float_T f = 0.0;
4475
4476 rettv->v_type = VAR_FLOAT;
4477 if (get_float_arg(argvars, &f) == OK)
4478 rettv->vval.v_float = log10(f);
4479 else
4480 rettv->vval.v_float = 0.0;
4481}
4482#endif
4483
4484#ifdef FEAT_LUA
4485/*
4486 * "luaeval()" function
4487 */
4488 static void
4489f_luaeval(typval_T *argvars, typval_T *rettv)
4490{
4491 char_u *str;
4492 char_u buf[NUMBUFLEN];
4493
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004494 if (check_restricted() || check_secure())
4495 return;
4496
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004497 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004498 do_luaeval(str, argvars + 1, rettv);
4499}
4500#endif
4501
4502/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004503 * "maparg()" function
4504 */
4505 static void
4506f_maparg(typval_T *argvars, typval_T *rettv)
4507{
4508 get_maparg(argvars, rettv, TRUE);
4509}
4510
4511/*
4512 * "mapcheck()" function
4513 */
4514 static void
4515f_mapcheck(typval_T *argvars, typval_T *rettv)
4516{
4517 get_maparg(argvars, rettv, FALSE);
4518}
4519
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004520typedef enum
4521{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004522 MATCH_END, // matchend()
4523 MATCH_MATCH, // match()
4524 MATCH_STR, // matchstr()
4525 MATCH_LIST, // matchlist()
4526 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004527} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004528
4529 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004530find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004531{
4532 char_u *str = NULL;
4533 long len = 0;
4534 char_u *expr = NULL;
4535 char_u *pat;
4536 regmatch_T regmatch;
4537 char_u patbuf[NUMBUFLEN];
4538 char_u strbuf[NUMBUFLEN];
4539 char_u *save_cpo;
4540 long start = 0;
4541 long nth = 1;
4542 colnr_T startcol = 0;
4543 int match = 0;
4544 list_T *l = NULL;
4545 listitem_T *li = NULL;
4546 long idx = 0;
4547 char_u *tofree = NULL;
4548
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004549 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004550 save_cpo = p_cpo;
4551 p_cpo = (char_u *)"";
4552
4553 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004554 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004555 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004556 // type MATCH_LIST: return empty list when there are no matches.
4557 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004558 if (rettv_list_alloc(rettv) == FAIL)
4559 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004560 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004561 && (list_append_string(rettv->vval.v_list,
4562 (char_u *)"", 0) == FAIL
4563 || list_append_number(rettv->vval.v_list,
4564 (varnumber_T)-1) == FAIL
4565 || list_append_number(rettv->vval.v_list,
4566 (varnumber_T)-1) == FAIL
4567 || list_append_number(rettv->vval.v_list,
4568 (varnumber_T)-1) == FAIL))
4569 {
4570 list_free(rettv->vval.v_list);
4571 rettv->vval.v_list = NULL;
4572 goto theend;
4573 }
4574 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004575 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004576 {
4577 rettv->v_type = VAR_STRING;
4578 rettv->vval.v_string = NULL;
4579 }
4580
4581 if (argvars[0].v_type == VAR_LIST)
4582 {
4583 if ((l = argvars[0].vval.v_list) == NULL)
4584 goto theend;
4585 li = l->lv_first;
4586 }
4587 else
4588 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004589 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004590 len = (long)STRLEN(str);
4591 }
4592
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004593 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594 if (pat == NULL)
4595 goto theend;
4596
4597 if (argvars[2].v_type != VAR_UNKNOWN)
4598 {
4599 int error = FALSE;
4600
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004601 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004602 if (error)
4603 goto theend;
4604 if (l != NULL)
4605 {
4606 li = list_find(l, start);
4607 if (li == NULL)
4608 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004609 idx = l->lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004610 }
4611 else
4612 {
4613 if (start < 0)
4614 start = 0;
4615 if (start > len)
4616 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004617 // When "count" argument is there ignore matches before "start",
4618 // otherwise skip part of the string. Differs when pattern is "^"
4619 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004620 if (argvars[3].v_type != VAR_UNKNOWN)
4621 startcol = start;
4622 else
4623 {
4624 str += start;
4625 len -= start;
4626 }
4627 }
4628
4629 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004630 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 if (error)
4632 goto theend;
4633 }
4634
4635 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4636 if (regmatch.regprog != NULL)
4637 {
4638 regmatch.rm_ic = p_ic;
4639
4640 for (;;)
4641 {
4642 if (l != NULL)
4643 {
4644 if (li == NULL)
4645 {
4646 match = FALSE;
4647 break;
4648 }
4649 vim_free(tofree);
4650 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4651 if (str == NULL)
4652 break;
4653 }
4654
4655 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4656
4657 if (match && --nth <= 0)
4658 break;
4659 if (l == NULL && !match)
4660 break;
4661
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004662 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663 if (l != NULL)
4664 {
4665 li = li->li_next;
4666 ++idx;
4667 }
4668 else
4669 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004670 startcol = (colnr_T)(regmatch.startp[0]
4671 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672 if (startcol > (colnr_T)len
4673 || str + startcol <= regmatch.startp[0])
4674 {
4675 match = FALSE;
4676 break;
4677 }
4678 }
4679 }
4680
4681 if (match)
4682 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004683 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684 {
4685 listitem_T *li1 = rettv->vval.v_list->lv_first;
4686 listitem_T *li2 = li1->li_next;
4687 listitem_T *li3 = li2->li_next;
4688 listitem_T *li4 = li3->li_next;
4689
4690 vim_free(li1->li_tv.vval.v_string);
4691 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4692 (int)(regmatch.endp[0] - regmatch.startp[0]));
4693 li3->li_tv.vval.v_number =
4694 (varnumber_T)(regmatch.startp[0] - expr);
4695 li4->li_tv.vval.v_number =
4696 (varnumber_T)(regmatch.endp[0] - expr);
4697 if (l != NULL)
4698 li2->li_tv.vval.v_number = (varnumber_T)idx;
4699 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004700 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004701 {
4702 int i;
4703
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004704 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 for (i = 0; i < NSUBEXP; ++i)
4706 {
4707 if (regmatch.endp[i] == NULL)
4708 {
4709 if (list_append_string(rettv->vval.v_list,
4710 (char_u *)"", 0) == FAIL)
4711 break;
4712 }
4713 else if (list_append_string(rettv->vval.v_list,
4714 regmatch.startp[i],
4715 (int)(regmatch.endp[i] - regmatch.startp[i]))
4716 == FAIL)
4717 break;
4718 }
4719 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004720 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004722 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004723 if (l != NULL)
4724 copy_tv(&li->li_tv, rettv);
4725 else
4726 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4727 (int)(regmatch.endp[0] - regmatch.startp[0]));
4728 }
4729 else if (l != NULL)
4730 rettv->vval.v_number = idx;
4731 else
4732 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004733 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 rettv->vval.v_number =
4735 (varnumber_T)(regmatch.startp[0] - str);
4736 else
4737 rettv->vval.v_number =
4738 (varnumber_T)(regmatch.endp[0] - str);
4739 rettv->vval.v_number += (varnumber_T)(str - expr);
4740 }
4741 }
4742 vim_regfree(regmatch.regprog);
4743 }
4744
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004745theend:
4746 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004747 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748 listitem_remove(rettv->vval.v_list,
4749 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004750 vim_free(tofree);
4751 p_cpo = save_cpo;
4752}
4753
4754/*
4755 * "match()" function
4756 */
4757 static void
4758f_match(typval_T *argvars, typval_T *rettv)
4759{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004760 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004761}
4762
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004763/*
4764 * "matchend()" function
4765 */
4766 static void
4767f_matchend(typval_T *argvars, typval_T *rettv)
4768{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004769 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004770}
4771
4772/*
4773 * "matchlist()" function
4774 */
4775 static void
4776f_matchlist(typval_T *argvars, typval_T *rettv)
4777{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004778 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004779}
4780
4781/*
4782 * "matchstr()" function
4783 */
4784 static void
4785f_matchstr(typval_T *argvars, typval_T *rettv)
4786{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004787 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004788}
4789
4790/*
4791 * "matchstrpos()" function
4792 */
4793 static void
4794f_matchstrpos(typval_T *argvars, typval_T *rettv)
4795{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004796 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004797}
4798
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004799 static void
4800max_min(typval_T *argvars, typval_T *rettv, int domax)
4801{
4802 varnumber_T n = 0;
4803 varnumber_T i;
4804 int error = FALSE;
4805
4806 if (argvars[0].v_type == VAR_LIST)
4807 {
4808 list_T *l;
4809 listitem_T *li;
4810
4811 l = argvars[0].vval.v_list;
4812 if (l != NULL)
4813 {
4814 li = l->lv_first;
4815 if (li != NULL)
4816 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004817 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004818 for (;;)
4819 {
4820 li = li->li_next;
4821 if (li == NULL)
4822 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004823 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004824 if (domax ? i > n : i < n)
4825 n = i;
4826 }
4827 }
4828 }
4829 }
4830 else if (argvars[0].v_type == VAR_DICT)
4831 {
4832 dict_T *d;
4833 int first = TRUE;
4834 hashitem_T *hi;
4835 int todo;
4836
4837 d = argvars[0].vval.v_dict;
4838 if (d != NULL)
4839 {
4840 todo = (int)d->dv_hashtab.ht_used;
4841 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4842 {
4843 if (!HASHITEM_EMPTY(hi))
4844 {
4845 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004846 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847 if (first)
4848 {
4849 n = i;
4850 first = FALSE;
4851 }
4852 else if (domax ? i > n : i < n)
4853 n = i;
4854 }
4855 }
4856 }
4857 }
4858 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004859 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004860 rettv->vval.v_number = error ? 0 : n;
4861}
4862
4863/*
4864 * "max()" function
4865 */
4866 static void
4867f_max(typval_T *argvars, typval_T *rettv)
4868{
4869 max_min(argvars, rettv, TRUE);
4870}
4871
4872/*
4873 * "min()" function
4874 */
4875 static void
4876f_min(typval_T *argvars, typval_T *rettv)
4877{
4878 max_min(argvars, rettv, FALSE);
4879}
4880
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004881#if defined(FEAT_MZSCHEME) || defined(PROTO)
4882/*
4883 * "mzeval()" function
4884 */
4885 static void
4886f_mzeval(typval_T *argvars, typval_T *rettv)
4887{
4888 char_u *str;
4889 char_u buf[NUMBUFLEN];
4890
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004891 if (check_restricted() || check_secure())
4892 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004893 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894 do_mzeval(str, rettv);
4895}
4896
4897 void
4898mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4899{
4900 typval_T argvars[3];
4901
4902 argvars[0].v_type = VAR_STRING;
4903 argvars[0].vval.v_string = name;
4904 copy_tv(args, &argvars[1]);
4905 argvars[2].v_type = VAR_UNKNOWN;
4906 f_call(argvars, rettv);
4907 clear_tv(&argvars[1]);
4908}
4909#endif
4910
4911/*
4912 * "nextnonblank()" function
4913 */
4914 static void
4915f_nextnonblank(typval_T *argvars, typval_T *rettv)
4916{
4917 linenr_T lnum;
4918
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004919 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004920 {
4921 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4922 {
4923 lnum = 0;
4924 break;
4925 }
4926 if (*skipwhite(ml_get(lnum)) != NUL)
4927 break;
4928 }
4929 rettv->vval.v_number = lnum;
4930}
4931
4932/*
4933 * "nr2char()" function
4934 */
4935 static void
4936f_nr2char(typval_T *argvars, typval_T *rettv)
4937{
4938 char_u buf[NUMBUFLEN];
4939
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940 if (has_mbyte)
4941 {
4942 int utf8 = 0;
4943
4944 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004945 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01004947 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004948 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004949 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004950 }
4951 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004953 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004954 buf[1] = NUL;
4955 }
4956 rettv->v_type = VAR_STRING;
4957 rettv->vval.v_string = vim_strsave(buf);
4958}
4959
4960/*
4961 * "or(expr, expr)" function
4962 */
4963 static void
4964f_or(typval_T *argvars, typval_T *rettv)
4965{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004966 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
4967 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004968}
4969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970#ifdef FEAT_PERL
4971/*
4972 * "perleval()" function
4973 */
4974 static void
4975f_perleval(typval_T *argvars, typval_T *rettv)
4976{
4977 char_u *str;
4978 char_u buf[NUMBUFLEN];
4979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004980 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004981 do_perleval(str, rettv);
4982}
4983#endif
4984
4985#ifdef FEAT_FLOAT
4986/*
4987 * "pow()" function
4988 */
4989 static void
4990f_pow(typval_T *argvars, typval_T *rettv)
4991{
4992 float_T fx = 0.0, fy = 0.0;
4993
4994 rettv->v_type = VAR_FLOAT;
4995 if (get_float_arg(argvars, &fx) == OK
4996 && get_float_arg(&argvars[1], &fy) == OK)
4997 rettv->vval.v_float = pow(fx, fy);
4998 else
4999 rettv->vval.v_float = 0.0;
5000}
5001#endif
5002
5003/*
5004 * "prevnonblank()" function
5005 */
5006 static void
5007f_prevnonblank(typval_T *argvars, typval_T *rettv)
5008{
5009 linenr_T lnum;
5010
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005011 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005012 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5013 lnum = 0;
5014 else
5015 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5016 --lnum;
5017 rettv->vval.v_number = lnum;
5018}
5019
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005020// This dummy va_list is here because:
5021// - passing a NULL pointer doesn't work when va_list isn't a pointer
5022// - locally in the function results in a "used before set" warning
5023// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005024static va_list ap;
5025
5026/*
5027 * "printf()" function
5028 */
5029 static void
5030f_printf(typval_T *argvars, typval_T *rettv)
5031{
5032 char_u buf[NUMBUFLEN];
5033 int len;
5034 char_u *s;
5035 int saved_did_emsg = did_emsg;
5036 char *fmt;
5037
5038 rettv->v_type = VAR_STRING;
5039 rettv->vval.v_string = NULL;
5040
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005041 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005043 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005044 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005045 if (!did_emsg)
5046 {
5047 s = alloc(len + 1);
5048 if (s != NULL)
5049 {
5050 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005051 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5052 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053 }
5054 }
5055 did_emsg |= saved_did_emsg;
5056}
5057
5058/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005059 * "pum_getpos()" function
5060 */
5061 static void
5062f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5063{
5064 if (rettv_dict_alloc(rettv) != OK)
5065 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005066 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005067}
5068
5069/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005070 * "pumvisible()" function
5071 */
5072 static void
5073f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5074{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 if (pum_visible())
5076 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077}
5078
5079#ifdef FEAT_PYTHON3
5080/*
5081 * "py3eval()" function
5082 */
5083 static void
5084f_py3eval(typval_T *argvars, typval_T *rettv)
5085{
5086 char_u *str;
5087 char_u buf[NUMBUFLEN];
5088
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005089 if (check_restricted() || check_secure())
5090 return;
5091
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005092 if (p_pyx == 0)
5093 p_pyx = 3;
5094
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005095 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096 do_py3eval(str, rettv);
5097}
5098#endif
5099
5100#ifdef FEAT_PYTHON
5101/*
5102 * "pyeval()" function
5103 */
5104 static void
5105f_pyeval(typval_T *argvars, typval_T *rettv)
5106{
5107 char_u *str;
5108 char_u buf[NUMBUFLEN];
5109
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005110 if (check_restricted() || check_secure())
5111 return;
5112
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005113 if (p_pyx == 0)
5114 p_pyx = 2;
5115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005116 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 do_pyeval(str, rettv);
5118}
5119#endif
5120
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005121#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5122/*
5123 * "pyxeval()" function
5124 */
5125 static void
5126f_pyxeval(typval_T *argvars, typval_T *rettv)
5127{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005128 if (check_restricted() || check_secure())
5129 return;
5130
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005131# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5132 init_pyxversion();
5133 if (p_pyx == 2)
5134 f_pyeval(argvars, rettv);
5135 else
5136 f_py3eval(argvars, rettv);
5137# elif defined(FEAT_PYTHON)
5138 f_pyeval(argvars, rettv);
5139# elif defined(FEAT_PYTHON3)
5140 f_py3eval(argvars, rettv);
5141# endif
5142}
5143#endif
5144
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005146 * "rand()" function
5147 */
5148 static void
5149f_rand(typval_T *argvars, typval_T *rettv)
5150{
5151 list_T *l = NULL;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005152 static list_T *globl = NULL;
5153 UINT32_T x, y, z, w, t, result;
5154 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005155
5156 if (argvars[0].v_type == VAR_UNKNOWN)
5157 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005158 // When no argument is given use the global seed list.
5159 if (globl == NULL)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005160 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005161 // Initialize the global seed list.
5162 f_srand(argvars, rettv);
5163 l = rettv->vval.v_list;
5164 if (l == NULL || list_len(l) != 4)
5165 {
5166 clear_tv(rettv);
5167 goto theend;
5168 }
5169 globl = l;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005170 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005171 else
5172 l = globl;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005173 }
5174 else if (argvars[0].v_type == VAR_LIST)
5175 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005176 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005177 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005178 goto theend;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005179 }
5180 else
5181 goto theend;
5182
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005183 lx = list_find(l, 0L);
5184 ly = list_find(l, 1L);
5185 lz = list_find(l, 2L);
5186 lw = list_find(l, 3L);
5187 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5188 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5189 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5190 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5191 x = (UINT32_T)lx->li_tv.vval.v_number;
5192 y = (UINT32_T)ly->li_tv.vval.v_number;
5193 z = (UINT32_T)lz->li_tv.vval.v_number;
5194 w = (UINT32_T)lw->li_tv.vval.v_number;
5195
5196 // SHUFFLE_XOSHIRO128STARSTAR
5197#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5198 result = ROTL(y * 5, 7) * 9;
5199 t = y << 9;
5200 z ^= x;
5201 w ^= y;
5202 y ^= z, x ^= w;
5203 z ^= t;
5204 w = ROTL(w, 11);
5205#undef ROTL
5206
5207 lx->li_tv.vval.v_number = (varnumber_T)x;
5208 ly->li_tv.vval.v_number = (varnumber_T)y;
5209 lz->li_tv.vval.v_number = (varnumber_T)z;
5210 lw->li_tv.vval.v_number = (varnumber_T)w;
5211
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005212 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005213 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005214 return;
5215
5216theend:
5217 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005218 rettv->v_type = VAR_NUMBER;
5219 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005220}
5221
5222/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005223 * "range()" function
5224 */
5225 static void
5226f_range(typval_T *argvars, typval_T *rettv)
5227{
5228 varnumber_T start;
5229 varnumber_T end;
5230 varnumber_T stride = 1;
5231 varnumber_T i;
5232 int error = FALSE;
5233
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005234 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235 if (argvars[1].v_type == VAR_UNKNOWN)
5236 {
5237 end = start - 1;
5238 start = 0;
5239 }
5240 else
5241 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005242 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005243 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005244 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005245 }
5246
5247 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005248 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005249 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005250 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005251 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005252 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005253 else
5254 {
5255 if (rettv_list_alloc(rettv) == OK)
5256 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5257 if (list_append_number(rettv->vval.v_list,
5258 (varnumber_T)i) == FAIL)
5259 break;
5260 }
5261}
5262
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005263 static void
5264return_register(int regname, typval_T *rettv)
5265{
5266 char_u buf[2] = {0, 0};
5267
5268 buf[0] = (char_u)regname;
5269 rettv->v_type = VAR_STRING;
5270 rettv->vval.v_string = vim_strsave(buf);
5271}
5272
5273/*
5274 * "reg_executing()" function
5275 */
5276 static void
5277f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5278{
5279 return_register(reg_executing, rettv);
5280}
5281
5282/*
5283 * "reg_recording()" function
5284 */
5285 static void
5286f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5287{
5288 return_register(reg_recording, rettv);
5289}
5290
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005291#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292/*
5293 * Convert a List to proftime_T.
5294 * Return FAIL when there is something wrong.
5295 */
5296 static int
5297list2proftime(typval_T *arg, proftime_T *tm)
5298{
5299 long n1, n2;
5300 int error = FALSE;
5301
5302 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5303 || arg->vval.v_list->lv_len != 2)
5304 return FAIL;
5305 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5306 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005307# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005308 tm->HighPart = n1;
5309 tm->LowPart = n2;
5310# else
5311 tm->tv_sec = n1;
5312 tm->tv_usec = n2;
5313# endif
5314 return error ? FAIL : OK;
5315}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005316#endif // FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005317
5318/*
5319 * "reltime()" function
5320 */
5321 static void
5322f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5323{
5324#ifdef FEAT_RELTIME
5325 proftime_T res;
5326 proftime_T start;
5327
5328 if (argvars[0].v_type == VAR_UNKNOWN)
5329 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005330 // No arguments: get current time.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005331 profile_start(&res);
5332 }
5333 else if (argvars[1].v_type == VAR_UNKNOWN)
5334 {
5335 if (list2proftime(&argvars[0], &res) == FAIL)
5336 return;
5337 profile_end(&res);
5338 }
5339 else
5340 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005341 // Two arguments: compute the difference.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005342 if (list2proftime(&argvars[0], &start) == FAIL
5343 || list2proftime(&argvars[1], &res) == FAIL)
5344 return;
5345 profile_sub(&res, &start);
5346 }
5347
5348 if (rettv_list_alloc(rettv) == OK)
5349 {
5350 long n1, n2;
5351
Bram Moolenaar4f974752019-02-17 17:44:42 +01005352# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005353 n1 = res.HighPart;
5354 n2 = res.LowPart;
5355# else
5356 n1 = res.tv_sec;
5357 n2 = res.tv_usec;
5358# endif
5359 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5360 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5361 }
5362#endif
5363}
5364
5365#ifdef FEAT_FLOAT
5366/*
5367 * "reltimefloat()" function
5368 */
5369 static void
5370f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5371{
5372# ifdef FEAT_RELTIME
5373 proftime_T tm;
5374# endif
5375
5376 rettv->v_type = VAR_FLOAT;
5377 rettv->vval.v_float = 0;
5378# ifdef FEAT_RELTIME
5379 if (list2proftime(&argvars[0], &tm) == OK)
5380 rettv->vval.v_float = profile_float(&tm);
5381# endif
5382}
5383#endif
5384
5385/*
5386 * "reltimestr()" function
5387 */
5388 static void
5389f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5390{
5391#ifdef FEAT_RELTIME
5392 proftime_T tm;
5393#endif
5394
5395 rettv->v_type = VAR_STRING;
5396 rettv->vval.v_string = NULL;
5397#ifdef FEAT_RELTIME
5398 if (list2proftime(&argvars[0], &tm) == OK)
5399 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5400#endif
5401}
5402
5403#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005404 static void
5405make_connection(void)
5406{
5407 if (X_DISPLAY == NULL
5408# ifdef FEAT_GUI
5409 && !gui.in_use
5410# endif
5411 )
5412 {
5413 x_force_connect = TRUE;
5414 setup_term_clip();
5415 x_force_connect = FALSE;
5416 }
5417}
5418
5419 static int
5420check_connection(void)
5421{
5422 make_connection();
5423 if (X_DISPLAY == NULL)
5424 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005425 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005426 return FAIL;
5427 }
5428 return OK;
5429}
5430#endif
5431
5432#ifdef FEAT_CLIENTSERVER
5433 static void
5434remote_common(typval_T *argvars, typval_T *rettv, int expr)
5435{
5436 char_u *server_name;
5437 char_u *keys;
5438 char_u *r = NULL;
5439 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005440 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005441# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005442 HWND w;
5443# else
5444 Window w;
5445# endif
5446
5447 if (check_restricted() || check_secure())
5448 return;
5449
5450# ifdef FEAT_X11
5451 if (check_connection() == FAIL)
5452 return;
5453# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005454 if (argvars[2].v_type != VAR_UNKNOWN
5455 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005456 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005458 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005459 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005460 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005461 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005462# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005463 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005465 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5466 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005467# endif
5468 {
5469 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005470 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005471 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005472 vim_free(r);
5473 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005475 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476 return;
5477 }
5478
5479 rettv->vval.v_string = r;
5480
5481 if (argvars[2].v_type != VAR_UNKNOWN)
5482 {
5483 dictitem_T v;
5484 char_u str[30];
5485 char_u *idvar;
5486
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005487 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005488 if (idvar != NULL && *idvar != NUL)
5489 {
5490 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5491 v.di_tv.v_type = VAR_STRING;
5492 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005493 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005494 vim_free(v.di_tv.vval.v_string);
5495 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005496 }
5497}
5498#endif
5499
5500/*
5501 * "remote_expr()" function
5502 */
5503 static void
5504f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5505{
5506 rettv->v_type = VAR_STRING;
5507 rettv->vval.v_string = NULL;
5508#ifdef FEAT_CLIENTSERVER
5509 remote_common(argvars, rettv, TRUE);
5510#endif
5511}
5512
5513/*
5514 * "remote_foreground()" function
5515 */
5516 static void
5517f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5518{
5519#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005520# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005521 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005522 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005523 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005524
5525 if (server_name != NULL)
5526 serverForeground(server_name);
5527 }
5528# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005529 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005530 argvars[1].v_type = VAR_STRING;
5531 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5532 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005533 rettv->v_type = VAR_STRING;
5534 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005535 remote_common(argvars, rettv, TRUE);
5536 vim_free(argvars[1].vval.v_string);
5537# endif
5538#endif
5539}
5540
5541 static void
5542f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5543{
5544#ifdef FEAT_CLIENTSERVER
5545 dictitem_T v;
5546 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005547# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 long_u n = 0;
5549# endif
5550 char_u *serverid;
5551
5552 if (check_restricted() || check_secure())
5553 {
5554 rettv->vval.v_number = -1;
5555 return;
5556 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005557 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005558 if (serverid == NULL)
5559 {
5560 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005561 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005562 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005563# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005564 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5565 if (n == 0)
5566 rettv->vval.v_number = -1;
5567 else
5568 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005569 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005570 rettv->vval.v_number = (s != NULL);
5571 }
5572# else
5573 if (check_connection() == FAIL)
5574 return;
5575
5576 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5577 serverStrToWin(serverid), &s);
5578# endif
5579
5580 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5581 {
5582 char_u *retvar;
5583
5584 v.di_tv.v_type = VAR_STRING;
5585 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005586 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587 if (retvar != NULL)
5588 set_var(retvar, &v.di_tv, FALSE);
5589 vim_free(v.di_tv.vval.v_string);
5590 }
5591#else
5592 rettv->vval.v_number = -1;
5593#endif
5594}
5595
5596 static void
5597f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5598{
5599 char_u *r = NULL;
5600
5601#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005602 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005603
5604 if (serverid != NULL && !check_restricted() && !check_secure())
5605 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005606 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005607# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005608 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005609 long_u n = 0;
5610# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005611
5612 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005613 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005614
Bram Moolenaar4f974752019-02-17 17:44:42 +01005615# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005616 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5617 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005618 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005619 if (r == NULL)
5620# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005621 if (check_connection() == FAIL
5622 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5623 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005624# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005625 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005626 }
5627#endif
5628 rettv->v_type = VAR_STRING;
5629 rettv->vval.v_string = r;
5630}
5631
5632/*
5633 * "remote_send()" function
5634 */
5635 static void
5636f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5637{
5638 rettv->v_type = VAR_STRING;
5639 rettv->vval.v_string = NULL;
5640#ifdef FEAT_CLIENTSERVER
5641 remote_common(argvars, rettv, FALSE);
5642#endif
5643}
5644
5645/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005646 * "remote_startserver()" function
5647 */
5648 static void
5649f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5650{
5651#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005652 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005653
5654 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005655 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005656 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005657 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005658 else
5659 {
5660# ifdef FEAT_X11
5661 if (check_connection() == OK)
5662 serverRegisterName(X_DISPLAY, server);
5663# else
5664 serverSetName(server);
5665# endif
5666 }
5667#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005668 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005669#endif
5670}
5671
5672/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005673 * "rename({from}, {to})" function
5674 */
5675 static void
5676f_rename(typval_T *argvars, typval_T *rettv)
5677{
5678 char_u buf[NUMBUFLEN];
5679
5680 if (check_restricted() || check_secure())
5681 rettv->vval.v_number = -1;
5682 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005683 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5684 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685}
5686
5687/*
5688 * "repeat()" function
5689 */
5690 static void
5691f_repeat(typval_T *argvars, typval_T *rettv)
5692{
5693 char_u *p;
5694 int n;
5695 int slen;
5696 int len;
5697 char_u *r;
5698 int i;
5699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005700 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005701 if (argvars[0].v_type == VAR_LIST)
5702 {
5703 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5704 while (n-- > 0)
5705 if (list_extend(rettv->vval.v_list,
5706 argvars[0].vval.v_list, NULL) == FAIL)
5707 break;
5708 }
5709 else
5710 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005711 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005712 rettv->v_type = VAR_STRING;
5713 rettv->vval.v_string = NULL;
5714
5715 slen = (int)STRLEN(p);
5716 len = slen * n;
5717 if (len <= 0)
5718 return;
5719
5720 r = alloc(len + 1);
5721 if (r != NULL)
5722 {
5723 for (i = 0; i < n; i++)
5724 mch_memmove(r + i * slen, p, (size_t)slen);
5725 r[len] = NUL;
5726 }
5727
5728 rettv->vval.v_string = r;
5729 }
5730}
5731
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005732#define SP_NOMOVE 0x01 // don't move cursor
5733#define SP_REPEAT 0x02 // repeat to find outer pair
5734#define SP_RETCOUNT 0x04 // return matchcount
5735#define SP_SETPCMARK 0x08 // set previous context mark
5736#define SP_START 0x10 // accept match at start position
5737#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5738#define SP_END 0x40 // leave cursor at end of match
5739#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005741/*
5742 * Get flags for a search function.
5743 * Possibly sets "p_ws".
5744 * Returns BACKWARD, FORWARD or zero (for an error).
5745 */
5746 static int
5747get_search_arg(typval_T *varp, int *flagsp)
5748{
5749 int dir = FORWARD;
5750 char_u *flags;
5751 char_u nbuf[NUMBUFLEN];
5752 int mask;
5753
5754 if (varp->v_type != VAR_UNKNOWN)
5755 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005756 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005757 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005758 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005759 while (*flags != NUL)
5760 {
5761 switch (*flags)
5762 {
5763 case 'b': dir = BACKWARD; break;
5764 case 'w': p_ws = TRUE; break;
5765 case 'W': p_ws = FALSE; break;
5766 default: mask = 0;
5767 if (flagsp != NULL)
5768 switch (*flags)
5769 {
5770 case 'c': mask = SP_START; break;
5771 case 'e': mask = SP_END; break;
5772 case 'm': mask = SP_RETCOUNT; break;
5773 case 'n': mask = SP_NOMOVE; break;
5774 case 'p': mask = SP_SUBPAT; break;
5775 case 'r': mask = SP_REPEAT; break;
5776 case 's': mask = SP_SETPCMARK; break;
5777 case 'z': mask = SP_COLUMN; break;
5778 }
5779 if (mask == 0)
5780 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005781 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 dir = 0;
5783 }
5784 else
5785 *flagsp |= mask;
5786 }
5787 if (dir == 0)
5788 break;
5789 ++flags;
5790 }
5791 }
5792 return dir;
5793}
5794
5795/*
5796 * Shared by search() and searchpos() functions.
5797 */
5798 static int
5799search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5800{
5801 int flags;
5802 char_u *pat;
5803 pos_T pos;
5804 pos_T save_cursor;
5805 int save_p_ws = p_ws;
5806 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005807 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005809#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005810 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005811 long time_limit = 0;
5812#endif
5813 int options = SEARCH_KEEP;
5814 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005815 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005816
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005817 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005818 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005819 if (dir == 0)
5820 goto theend;
5821 flags = *flagsp;
5822 if (flags & SP_START)
5823 options |= SEARCH_START;
5824 if (flags & SP_END)
5825 options |= SEARCH_END;
5826 if (flags & SP_COLUMN)
5827 options |= SEARCH_COL;
5828
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005829 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005830 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5831 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005832 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005833 if (lnum_stop < 0)
5834 goto theend;
5835#ifdef FEAT_RELTIME
5836 if (argvars[3].v_type != VAR_UNKNOWN)
5837 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005838 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839 if (time_limit < 0)
5840 goto theend;
5841 }
5842#endif
5843 }
5844
5845#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005846 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005847 profile_setlimit(time_limit, &tm);
5848#endif
5849
5850 /*
5851 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5852 * Check to make sure only those flags are set.
5853 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5854 * flags cannot be set. Check for that condition also.
5855 */
5856 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5857 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5858 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005859 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005860 goto theend;
5861 }
5862
5863 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005864 vim_memset(&sia, 0, sizeof(sia));
5865 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5866#ifdef FEAT_RELTIME
5867 sia.sa_tm = &tm;
5868#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005869 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005870 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005871 if (subpatnum != FAIL)
5872 {
5873 if (flags & SP_SUBPAT)
5874 retval = subpatnum;
5875 else
5876 retval = pos.lnum;
5877 if (flags & SP_SETPCMARK)
5878 setpcmark();
5879 curwin->w_cursor = pos;
5880 if (match_pos != NULL)
5881 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005882 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883 match_pos->lnum = pos.lnum;
5884 match_pos->col = pos.col + 1;
5885 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005886 // "/$" will put the cursor after the end of the line, may need to
5887 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888 check_cursor();
5889 }
5890
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005891 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005892 if (flags & SP_NOMOVE)
5893 curwin->w_cursor = save_cursor;
5894 else
5895 curwin->w_set_curswant = TRUE;
5896theend:
5897 p_ws = save_p_ws;
5898
5899 return retval;
5900}
5901
5902#ifdef FEAT_FLOAT
5903
5904/*
5905 * round() is not in C90, use ceil() or floor() instead.
5906 */
5907 float_T
5908vim_round(float_T f)
5909{
5910 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5911}
5912
5913/*
5914 * "round({float})" function
5915 */
5916 static void
5917f_round(typval_T *argvars, typval_T *rettv)
5918{
5919 float_T f = 0.0;
5920
5921 rettv->v_type = VAR_FLOAT;
5922 if (get_float_arg(argvars, &f) == OK)
5923 rettv->vval.v_float = vim_round(f);
5924 else
5925 rettv->vval.v_float = 0.0;
5926}
5927#endif
5928
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005929#ifdef FEAT_RUBY
5930/*
5931 * "rubyeval()" function
5932 */
5933 static void
5934f_rubyeval(typval_T *argvars, typval_T *rettv)
5935{
5936 char_u *str;
5937 char_u buf[NUMBUFLEN];
5938
5939 str = tv_get_string_buf(&argvars[0], buf);
5940 do_rubyeval(str, rettv);
5941}
5942#endif
5943
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005944/*
5945 * "screenattr()" function
5946 */
5947 static void
5948f_screenattr(typval_T *argvars, typval_T *rettv)
5949{
5950 int row;
5951 int col;
5952 int c;
5953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005954 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5955 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005956 if (row < 0 || row >= screen_Rows
5957 || col < 0 || col >= screen_Columns)
5958 c = -1;
5959 else
5960 c = ScreenAttrs[LineOffset[row] + col];
5961 rettv->vval.v_number = c;
5962}
5963
5964/*
5965 * "screenchar()" function
5966 */
5967 static void
5968f_screenchar(typval_T *argvars, typval_T *rettv)
5969{
5970 int row;
5971 int col;
5972 int off;
5973 int c;
5974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005975 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5976 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005977 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978 c = -1;
5979 else
5980 {
5981 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005982 if (enc_utf8 && ScreenLinesUC[off] != 0)
5983 c = ScreenLinesUC[off];
5984 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985 c = ScreenLines[off];
5986 }
5987 rettv->vval.v_number = c;
5988}
5989
5990/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005991 * "screenchars()" function
5992 */
5993 static void
5994f_screenchars(typval_T *argvars, typval_T *rettv)
5995{
5996 int row;
5997 int col;
5998 int off;
5999 int c;
6000 int i;
6001
6002 if (rettv_list_alloc(rettv) == FAIL)
6003 return;
6004 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6005 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6006 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6007 return;
6008
6009 off = LineOffset[row] + col;
6010 if (enc_utf8 && ScreenLinesUC[off] != 0)
6011 c = ScreenLinesUC[off];
6012 else
6013 c = ScreenLines[off];
6014 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6015
6016 if (enc_utf8)
6017
6018 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6019 list_append_number(rettv->vval.v_list,
6020 (varnumber_T)ScreenLinesC[i][off]);
6021}
6022
6023/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024 * "screencol()" function
6025 *
6026 * First column is 1 to be consistent with virtcol().
6027 */
6028 static void
6029f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6030{
6031 rettv->vval.v_number = screen_screencol() + 1;
6032}
6033
6034/*
6035 * "screenrow()" function
6036 */
6037 static void
6038f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6039{
6040 rettv->vval.v_number = screen_screenrow() + 1;
6041}
6042
6043/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006044 * "screenstring()" function
6045 */
6046 static void
6047f_screenstring(typval_T *argvars, typval_T *rettv)
6048{
6049 int row;
6050 int col;
6051 int off;
6052 int c;
6053 int i;
6054 char_u buf[MB_MAXBYTES + 1];
6055 int buflen = 0;
6056
6057 rettv->vval.v_string = NULL;
6058 rettv->v_type = VAR_STRING;
6059
6060 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6061 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6062 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6063 return;
6064
6065 off = LineOffset[row] + col;
6066 if (enc_utf8 && ScreenLinesUC[off] != 0)
6067 c = ScreenLinesUC[off];
6068 else
6069 c = ScreenLines[off];
6070 buflen += mb_char2bytes(c, buf);
6071
6072 if (enc_utf8)
6073 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6074 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6075
6076 buf[buflen] = NUL;
6077 rettv->vval.v_string = vim_strsave(buf);
6078}
6079
6080/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081 * "search()" function
6082 */
6083 static void
6084f_search(typval_T *argvars, typval_T *rettv)
6085{
6086 int flags = 0;
6087
6088 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6089}
6090
6091/*
6092 * "searchdecl()" function
6093 */
6094 static void
6095f_searchdecl(typval_T *argvars, typval_T *rettv)
6096{
6097 int locally = 1;
6098 int thisblock = 0;
6099 int error = FALSE;
6100 char_u *name;
6101
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006102 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006103
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006104 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006105 if (argvars[1].v_type != VAR_UNKNOWN)
6106 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006107 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006108 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006109 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006110 }
6111 if (!error && name != NULL)
6112 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6113 locally, thisblock, SEARCH_KEEP) == FAIL;
6114}
6115
6116/*
6117 * Used by searchpair() and searchpairpos()
6118 */
6119 static int
6120searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6121{
6122 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006123 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006124 int save_p_ws = p_ws;
6125 int dir;
6126 int flags = 0;
6127 char_u nbuf1[NUMBUFLEN];
6128 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006129 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006130 long lnum_stop = 0;
6131 long time_limit = 0;
6132
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006133 // Get the three pattern arguments: start, middle, end. Will result in an
6134 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006135 spat = tv_get_string_chk(&argvars[0]);
6136 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6137 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006138 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006139 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006140
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006141 // Handle the optional fourth argument: flags
6142 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143 if (dir == 0)
6144 goto theend;
6145
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006146 // Don't accept SP_END or SP_SUBPAT.
6147 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006148 if ((flags & (SP_END | SP_SUBPAT)) != 0
6149 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6150 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006151 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006152 goto theend;
6153 }
6154
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006155 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006156 if (flags & SP_REPEAT)
6157 p_ws = FALSE;
6158
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006159 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 if (argvars[3].v_type == VAR_UNKNOWN
6161 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006162 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006163 else
6164 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006165 skip = &argvars[4];
6166 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6167 && skip->v_type != VAR_STRING)
6168 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006169 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006170 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006171 goto theend;
6172 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006173 if (argvars[5].v_type != VAR_UNKNOWN)
6174 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006175 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006177 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006178 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006179 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006180 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181#ifdef FEAT_RELTIME
6182 if (argvars[6].v_type != VAR_UNKNOWN)
6183 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006184 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006186 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006187 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006189 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190 }
6191#endif
6192 }
6193 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194
6195 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6196 match_pos, lnum_stop, time_limit);
6197
6198theend:
6199 p_ws = save_p_ws;
6200
6201 return retval;
6202}
6203
6204/*
6205 * "searchpair()" function
6206 */
6207 static void
6208f_searchpair(typval_T *argvars, typval_T *rettv)
6209{
6210 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6211}
6212
6213/*
6214 * "searchpairpos()" function
6215 */
6216 static void
6217f_searchpairpos(typval_T *argvars, typval_T *rettv)
6218{
6219 pos_T match_pos;
6220 int lnum = 0;
6221 int col = 0;
6222
6223 if (rettv_list_alloc(rettv) == FAIL)
6224 return;
6225
6226 if (searchpair_cmn(argvars, &match_pos) > 0)
6227 {
6228 lnum = match_pos.lnum;
6229 col = match_pos.col;
6230 }
6231
6232 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6233 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6234}
6235
6236/*
6237 * Search for a start/middle/end thing.
6238 * Used by searchpair(), see its documentation for the details.
6239 * Returns 0 or -1 for no match,
6240 */
6241 long
6242do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006243 char_u *spat, // start pattern
6244 char_u *mpat, // middle pattern
6245 char_u *epat, // end pattern
6246 int dir, // BACKWARD or FORWARD
6247 typval_T *skip, // skip expression
6248 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006249 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006250 linenr_T lnum_stop, // stop at this line if not zero
6251 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006252{
6253 char_u *save_cpo;
6254 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6255 long retval = 0;
6256 pos_T pos;
6257 pos_T firstpos;
6258 pos_T foundpos;
6259 pos_T save_cursor;
6260 pos_T save_pos;
6261 int n;
6262 int r;
6263 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006264 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006265 int err;
6266 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006267#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006269#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006271 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 save_cpo = p_cpo;
6273 p_cpo = empty_option;
6274
6275#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006276 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006277 profile_setlimit(time_limit, &tm);
6278#endif
6279
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006280 // Make two search patterns: start/end (pat2, for in nested pairs) and
6281 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006282 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6283 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006284 if (pat2 == NULL || pat3 == NULL)
6285 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006286 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006287 if (*mpat == NUL)
6288 STRCPY(pat3, pat2);
6289 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006290 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291 spat, epat, mpat);
6292 if (flags & SP_START)
6293 options |= SEARCH_START;
6294
Bram Moolenaar48570482017-10-30 21:48:41 +01006295 if (skip != NULL)
6296 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006297 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006298 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6299 use_skip = skip->vval.v_string != NULL
6300 && *skip->vval.v_string != NUL;
6301 }
6302
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006303 save_cursor = curwin->w_cursor;
6304 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006305 CLEAR_POS(&firstpos);
6306 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 pat = pat3;
6308 for (;;)
6309 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006310 searchit_arg_T sia;
6311
6312 vim_memset(&sia, 0, sizeof(sia));
6313 sia.sa_stop_lnum = lnum_stop;
6314#ifdef FEAT_RELTIME
6315 sia.sa_tm = &tm;
6316#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006317 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006318 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006319 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006320 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321 break;
6322
6323 if (firstpos.lnum == 0)
6324 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006325 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006327 // Found the same position again. Can happen with a pattern that
6328 // has "\zs" at the end and searching backwards. Advance one
6329 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006330 if (dir == BACKWARD)
6331 decl(&pos);
6332 else
6333 incl(&pos);
6334 }
6335 foundpos = pos;
6336
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006337 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338 options &= ~SEARCH_START;
6339
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006340 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006341 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342 {
6343 save_pos = curwin->w_cursor;
6344 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006345 err = FALSE;
6346 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006347 curwin->w_cursor = save_pos;
6348 if (err)
6349 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006350 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 curwin->w_cursor = save_cursor;
6352 retval = -1;
6353 break;
6354 }
6355 if (r)
6356 continue;
6357 }
6358
6359 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6360 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006361 // Found end when searching backwards or start when searching
6362 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006364 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365 }
6366 else
6367 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006368 // Found end when searching forward or start when searching
6369 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006370 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006371 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372 }
6373
6374 if (nest == 0)
6375 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006376 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006377 if (flags & SP_RETCOUNT)
6378 ++retval;
6379 else
6380 retval = pos.lnum;
6381 if (flags & SP_SETPCMARK)
6382 setpcmark();
6383 curwin->w_cursor = pos;
6384 if (!(flags & SP_REPEAT))
6385 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006386 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387 }
6388 }
6389
6390 if (match_pos != NULL)
6391 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006392 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 match_pos->lnum = curwin->w_cursor.lnum;
6394 match_pos->col = curwin->w_cursor.col + 1;
6395 }
6396
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006397 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006398 if ((flags & SP_NOMOVE) || retval == 0)
6399 curwin->w_cursor = save_cursor;
6400
6401theend:
6402 vim_free(pat2);
6403 vim_free(pat3);
6404 if (p_cpo == empty_option)
6405 p_cpo = save_cpo;
6406 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006407 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408 free_string_option(save_cpo);
6409
6410 return retval;
6411}
6412
6413/*
6414 * "searchpos()" function
6415 */
6416 static void
6417f_searchpos(typval_T *argvars, typval_T *rettv)
6418{
6419 pos_T match_pos;
6420 int lnum = 0;
6421 int col = 0;
6422 int n;
6423 int flags = 0;
6424
6425 if (rettv_list_alloc(rettv) == FAIL)
6426 return;
6427
6428 n = search_cmn(argvars, &match_pos, &flags);
6429 if (n > 0)
6430 {
6431 lnum = match_pos.lnum;
6432 col = match_pos.col;
6433 }
6434
6435 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6436 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6437 if (flags & SP_SUBPAT)
6438 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6439}
6440
6441 static void
6442f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6443{
6444#ifdef FEAT_CLIENTSERVER
6445 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006446 char_u *server = tv_get_string_chk(&argvars[0]);
6447 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006448
6449 rettv->vval.v_number = -1;
6450 if (server == NULL || reply == NULL)
6451 return;
6452 if (check_restricted() || check_secure())
6453 return;
6454# ifdef FEAT_X11
6455 if (check_connection() == FAIL)
6456 return;
6457# endif
6458
6459 if (serverSendReply(server, reply) < 0)
6460 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006461 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 return;
6463 }
6464 rettv->vval.v_number = 0;
6465#else
6466 rettv->vval.v_number = -1;
6467#endif
6468}
6469
6470 static void
6471f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6472{
6473 char_u *r = NULL;
6474
6475#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006476# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477 r = serverGetVimNames();
6478# else
6479 make_connection();
6480 if (X_DISPLAY != NULL)
6481 r = serverGetVimNames(X_DISPLAY);
6482# endif
6483#endif
6484 rettv->v_type = VAR_STRING;
6485 rettv->vval.v_string = r;
6486}
6487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006488 static void
6489f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6490{
6491 dict_T *d;
6492 dictitem_T *di;
6493 char_u *csearch;
6494
6495 if (argvars[0].v_type != VAR_DICT)
6496 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006497 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006498 return;
6499 }
6500
6501 if ((d = argvars[0].vval.v_dict) != NULL)
6502 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006503 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 if (csearch != NULL)
6505 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006506 if (enc_utf8)
6507 {
6508 int pcc[MAX_MCO];
6509 int c = utfc_ptr2char(csearch, pcc);
6510
6511 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6512 }
6513 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006515 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006516 }
6517
6518 di = dict_find(d, (char_u *)"forward", -1);
6519 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006520 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521 ? FORWARD : BACKWARD);
6522
6523 di = dict_find(d, (char_u *)"until", -1);
6524 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006525 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526 }
6527}
6528
6529/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006530 * "setenv()" function
6531 */
6532 static void
6533f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6534{
6535 char_u namebuf[NUMBUFLEN];
6536 char_u valbuf[NUMBUFLEN];
6537 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6538
6539 if (argvars[1].v_type == VAR_SPECIAL
6540 && argvars[1].vval.v_number == VVAL_NULL)
6541 vim_unsetenv(name);
6542 else
6543 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6544}
6545
6546/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006547 * "setfperm({fname}, {mode})" function
6548 */
6549 static void
6550f_setfperm(typval_T *argvars, typval_T *rettv)
6551{
6552 char_u *fname;
6553 char_u modebuf[NUMBUFLEN];
6554 char_u *mode_str;
6555 int i;
6556 int mask;
6557 int mode = 0;
6558
6559 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006560 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006561 if (fname == NULL)
6562 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006563 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006564 if (mode_str == NULL)
6565 return;
6566 if (STRLEN(mode_str) != 9)
6567 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006568 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006569 return;
6570 }
6571
6572 mask = 1;
6573 for (i = 8; i >= 0; --i)
6574 {
6575 if (mode_str[i] != '-')
6576 mode |= mask;
6577 mask = mask << 1;
6578 }
6579 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6580}
6581
6582/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 * "setpos()" function
6584 */
6585 static void
6586f_setpos(typval_T *argvars, typval_T *rettv)
6587{
6588 pos_T pos;
6589 int fnum;
6590 char_u *name;
6591 colnr_T curswant = -1;
6592
6593 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006594 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006595 if (name != NULL)
6596 {
6597 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6598 {
6599 if (--pos.col < 0)
6600 pos.col = 0;
6601 if (name[0] == '.' && name[1] == NUL)
6602 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006603 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006604 curwin->w_cursor = pos;
6605 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006606 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006607 curwin->w_curswant = curswant - 1;
6608 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006609 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006610 check_cursor();
6611 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006612 }
6613 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6614 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006615 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616 if (setmark_pos(name[1], &pos, fnum) == OK)
6617 rettv->vval.v_number = 0;
6618 }
6619 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006620 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006621 }
6622 }
6623}
6624
6625/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006626 * "setreg()" function
6627 */
6628 static void
6629f_setreg(typval_T *argvars, typval_T *rettv)
6630{
6631 int regname;
6632 char_u *strregname;
6633 char_u *stropt;
6634 char_u *strval;
6635 int append;
6636 char_u yank_type;
6637 long block_len;
6638
6639 block_len = -1;
6640 yank_type = MAUTO;
6641 append = FALSE;
6642
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006643 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006644 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645
6646 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006647 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006648 regname = *strregname;
6649 if (regname == 0 || regname == '@')
6650 regname = '"';
6651
6652 if (argvars[2].v_type != VAR_UNKNOWN)
6653 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006654 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006655 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006656 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657 for (; *stropt != NUL; ++stropt)
6658 switch (*stropt)
6659 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006660 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006661 append = TRUE;
6662 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006663 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664 yank_type = MCHAR;
6665 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006666 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006667 yank_type = MLINE;
6668 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006669 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006670 yank_type = MBLOCK;
6671 if (VIM_ISDIGIT(stropt[1]))
6672 {
6673 ++stropt;
6674 block_len = getdigits(&stropt) - 1;
6675 --stropt;
6676 }
6677 break;
6678 }
6679 }
6680
6681 if (argvars[1].v_type == VAR_LIST)
6682 {
6683 char_u **lstval;
6684 char_u **allocval;
6685 char_u buf[NUMBUFLEN];
6686 char_u **curval;
6687 char_u **curallocval;
6688 list_T *ll = argvars[1].vval.v_list;
6689 listitem_T *li;
6690 int len;
6691
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006692 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 len = ll == NULL ? 0 : ll->lv_len;
6694
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006695 // First half: use for pointers to result lines; second half: use for
6696 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006697 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006698 if (lstval == NULL)
6699 return;
6700 curval = lstval;
6701 allocval = lstval + len + 2;
6702 curallocval = allocval;
6703
6704 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6705 li = li->li_next)
6706 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006707 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006708 if (strval == NULL)
6709 goto free_lstval;
6710 if (strval == buf)
6711 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006712 // Need to make a copy, next tv_get_string_buf_chk() will
6713 // overwrite the string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006714 strval = vim_strsave(buf);
6715 if (strval == NULL)
6716 goto free_lstval;
6717 *curallocval++ = strval;
6718 }
6719 *curval++ = strval;
6720 }
6721 *curval++ = NULL;
6722
6723 write_reg_contents_lst(regname, lstval, -1,
6724 append, yank_type, block_len);
6725free_lstval:
6726 while (curallocval > allocval)
6727 vim_free(*--curallocval);
6728 vim_free(lstval);
6729 }
6730 else
6731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006732 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006733 if (strval == NULL)
6734 return;
6735 write_reg_contents_ex(regname, strval, -1,
6736 append, yank_type, block_len);
6737 }
6738 rettv->vval.v_number = 0;
6739}
6740
6741/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006742 * "settagstack()" function
6743 */
6744 static void
6745f_settagstack(typval_T *argvars, typval_T *rettv)
6746{
6747 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6748 win_T *wp;
6749 dict_T *d;
6750 int action = 'r';
6751
6752 rettv->vval.v_number = -1;
6753
6754 // first argument: window number or id
6755 wp = find_win_by_nr_or_id(&argvars[0]);
6756 if (wp == NULL)
6757 return;
6758
6759 // second argument: dict with items to set in the tag stack
6760 if (argvars[1].v_type != VAR_DICT)
6761 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006762 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006763 return;
6764 }
6765 d = argvars[1].vval.v_dict;
6766 if (d == NULL)
6767 return;
6768
6769 // third argument: action - 'a' for append and 'r' for replace.
6770 // default is to replace the stack.
6771 if (argvars[2].v_type == VAR_UNKNOWN)
6772 action = 'r';
6773 else if (argvars[2].v_type == VAR_STRING)
6774 {
6775 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006776 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006777 if (actstr == NULL)
6778 return;
6779 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6780 action = *actstr;
6781 else
6782 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006783 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006784 return;
6785 }
6786 }
6787 else
6788 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006789 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006790 return;
6791 }
6792
6793 if (set_tagstack(wp, d, action) == OK)
6794 rettv->vval.v_number = 0;
6795}
6796
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797#ifdef FEAT_CRYPT
6798/*
6799 * "sha256({string})" function
6800 */
6801 static void
6802f_sha256(typval_T *argvars, typval_T *rettv)
6803{
6804 char_u *p;
6805
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006806 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006807 rettv->vval.v_string = vim_strsave(
6808 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6809 rettv->v_type = VAR_STRING;
6810}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006811#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812
6813/*
6814 * "shellescape({string})" function
6815 */
6816 static void
6817f_shellescape(typval_T *argvars, typval_T *rettv)
6818{
Bram Moolenaar20615522017-06-05 18:46:26 +02006819 int do_special = non_zero_arg(&argvars[1]);
6820
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006822 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 rettv->v_type = VAR_STRING;
6824}
6825
6826/*
6827 * shiftwidth() function
6828 */
6829 static void
6830f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6831{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006832 rettv->vval.v_number = 0;
6833
6834 if (argvars[0].v_type != VAR_UNKNOWN)
6835 {
6836 long col;
6837
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006838 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006839 if (col < 0)
6840 return; // type error; errmsg already given
6841#ifdef FEAT_VARTABS
6842 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6843 return;
6844#endif
6845 }
6846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006847 rettv->vval.v_number = get_sw_value(curbuf);
6848}
6849
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850#ifdef FEAT_FLOAT
6851/*
6852 * "sin()" function
6853 */
6854 static void
6855f_sin(typval_T *argvars, typval_T *rettv)
6856{
6857 float_T f = 0.0;
6858
6859 rettv->v_type = VAR_FLOAT;
6860 if (get_float_arg(argvars, &f) == OK)
6861 rettv->vval.v_float = sin(f);
6862 else
6863 rettv->vval.v_float = 0.0;
6864}
6865
6866/*
6867 * "sinh()" function
6868 */
6869 static void
6870f_sinh(typval_T *argvars, typval_T *rettv)
6871{
6872 float_T f = 0.0;
6873
6874 rettv->v_type = VAR_FLOAT;
6875 if (get_float_arg(argvars, &f) == OK)
6876 rettv->vval.v_float = sinh(f);
6877 else
6878 rettv->vval.v_float = 0.0;
6879}
6880#endif
6881
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882/*
6883 * "soundfold({word})" function
6884 */
6885 static void
6886f_soundfold(typval_T *argvars, typval_T *rettv)
6887{
6888 char_u *s;
6889
6890 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006891 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892#ifdef FEAT_SPELL
6893 rettv->vval.v_string = eval_soundfold(s);
6894#else
6895 rettv->vval.v_string = vim_strsave(s);
6896#endif
6897}
6898
6899/*
6900 * "spellbadword()" function
6901 */
6902 static void
6903f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6904{
6905 char_u *word = (char_u *)"";
6906 hlf_T attr = HLF_COUNT;
6907 int len = 0;
6908
6909 if (rettv_list_alloc(rettv) == FAIL)
6910 return;
6911
6912#ifdef FEAT_SPELL
6913 if (argvars[0].v_type == VAR_UNKNOWN)
6914 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006915 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6917 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006918 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006920 curwin->w_set_curswant = TRUE;
6921 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922 }
6923 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006925 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 int capcol = -1;
6927
6928 if (str != NULL)
6929 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006930 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006931 while (*str != NUL)
6932 {
6933 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6934 if (attr != HLF_COUNT)
6935 {
6936 word = str;
6937 break;
6938 }
6939 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006940 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006941 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006942 }
6943 }
6944 }
6945#endif
6946
6947 list_append_string(rettv->vval.v_list, word, len);
6948 list_append_string(rettv->vval.v_list, (char_u *)(
6949 attr == HLF_SPB ? "bad" :
6950 attr == HLF_SPR ? "rare" :
6951 attr == HLF_SPL ? "local" :
6952 attr == HLF_SPC ? "caps" :
6953 ""), -1);
6954}
6955
6956/*
6957 * "spellsuggest()" function
6958 */
6959 static void
6960f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6961{
6962#ifdef FEAT_SPELL
6963 char_u *str;
6964 int typeerr = FALSE;
6965 int maxcount;
6966 garray_T ga;
6967 int i;
6968 listitem_T *li;
6969 int need_capital = FALSE;
6970#endif
6971
6972 if (rettv_list_alloc(rettv) == FAIL)
6973 return;
6974
6975#ifdef FEAT_SPELL
6976 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6977 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006978 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979 if (argvars[1].v_type != VAR_UNKNOWN)
6980 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006981 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 if (maxcount <= 0)
6983 return;
6984 if (argvars[2].v_type != VAR_UNKNOWN)
6985 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006986 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006987 if (typeerr)
6988 return;
6989 }
6990 }
6991 else
6992 maxcount = 25;
6993
6994 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6995
6996 for (i = 0; i < ga.ga_len; ++i)
6997 {
6998 str = ((char_u **)ga.ga_data)[i];
6999
7000 li = listitem_alloc();
7001 if (li == NULL)
7002 vim_free(str);
7003 else
7004 {
7005 li->li_tv.v_type = VAR_STRING;
7006 li->li_tv.v_lock = 0;
7007 li->li_tv.vval.v_string = str;
7008 list_append(rettv->vval.v_list, li);
7009 }
7010 }
7011 ga_clear(&ga);
7012 }
7013#endif
7014}
7015
7016 static void
7017f_split(typval_T *argvars, typval_T *rettv)
7018{
7019 char_u *str;
7020 char_u *end;
7021 char_u *pat = NULL;
7022 regmatch_T regmatch;
7023 char_u patbuf[NUMBUFLEN];
7024 char_u *save_cpo;
7025 int match;
7026 colnr_T col = 0;
7027 int keepempty = FALSE;
7028 int typeerr = FALSE;
7029
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007030 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 save_cpo = p_cpo;
7032 p_cpo = (char_u *)"";
7033
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007034 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007035 if (argvars[1].v_type != VAR_UNKNOWN)
7036 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007037 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 if (pat == NULL)
7039 typeerr = TRUE;
7040 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007041 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007042 }
7043 if (pat == NULL || *pat == NUL)
7044 pat = (char_u *)"[\\x01- ]\\+";
7045
7046 if (rettv_list_alloc(rettv) == FAIL)
7047 return;
7048 if (typeerr)
7049 return;
7050
7051 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7052 if (regmatch.regprog != NULL)
7053 {
7054 regmatch.rm_ic = FALSE;
7055 while (*str != NUL || keepempty)
7056 {
7057 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007058 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007059 else
7060 match = vim_regexec_nl(&regmatch, str, col);
7061 if (match)
7062 end = regmatch.startp[0];
7063 else
7064 end = str + STRLEN(str);
7065 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7066 && *str != NUL && match && end < regmatch.endp[0]))
7067 {
7068 if (list_append_string(rettv->vval.v_list, str,
7069 (int)(end - str)) == FAIL)
7070 break;
7071 }
7072 if (!match)
7073 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007074 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 if (regmatch.endp[0] > str)
7076 col = 0;
7077 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007078 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007079 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 str = regmatch.endp[0];
7081 }
7082
7083 vim_regfree(regmatch.regprog);
7084 }
7085
7086 p_cpo = save_cpo;
7087}
7088
7089#ifdef FEAT_FLOAT
7090/*
7091 * "sqrt()" function
7092 */
7093 static void
7094f_sqrt(typval_T *argvars, typval_T *rettv)
7095{
7096 float_T f = 0.0;
7097
7098 rettv->v_type = VAR_FLOAT;
7099 if (get_float_arg(argvars, &f) == OK)
7100 rettv->vval.v_float = sqrt(f);
7101 else
7102 rettv->vval.v_float = 0.0;
7103}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007104#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007105
7106/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007107 * "srand()" function
7108 */
7109 static void
7110f_srand(typval_T *argvars, typval_T *rettv)
7111{
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007112 static int dev_urandom_state = -1; // FAIL or OK once tried
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007113 UINT32_T x = 0, z;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007114
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007115 if (rettv_list_alloc(rettv) == FAIL)
7116 return;
7117 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007118 {
7119 if (dev_urandom_state != FAIL)
7120 {
7121 int fd = open("/dev/urandom", O_RDONLY);
7122 struct {
7123 union {
7124 UINT32_T number;
7125 char bytes[sizeof(UINT32_T)];
7126 } cont;
7127 } buf;
7128
7129 // Attempt reading /dev/urandom.
7130 if (fd == -1)
7131 dev_urandom_state = FAIL;
7132 else
7133 {
7134 buf.cont.number = 0;
7135 if (read(fd, buf.cont.bytes, sizeof(UINT32_T))
7136 != sizeof(UINT32_T))
7137 dev_urandom_state = FAIL;
7138 else
7139 {
7140 dev_urandom_state = OK;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007141 x = buf.cont.number;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007142 }
7143 close(fd);
7144 }
7145
7146 }
7147 if (dev_urandom_state != OK)
7148 // Reading /dev/urandom doesn't work, fall back to time().
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007149 x = vim_time();
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007150 }
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007151 else
7152 {
7153 int error = FALSE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007154
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007155 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007156 if (error)
7157 return;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007158 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007159
7160#define SPLITMIX32 ( \
7161 z = (x += 0x9e3779b9), \
7162 z = (z ^ (z >> 16)) * 0x85ebca6b, \
7163 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7164 z ^ (z >> 16) \
7165 )
7166
7167 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7168 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7169 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7170 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007171}
7172
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007173#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007174/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175 * "str2float()" function
7176 */
7177 static void
7178f_str2float(typval_T *argvars, typval_T *rettv)
7179{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007180 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007181 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007182
Bram Moolenaar08243d22017-01-10 16:12:29 +01007183 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007184 p = skipwhite(p + 1);
7185 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007186 if (isneg)
7187 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 rettv->v_type = VAR_FLOAT;
7189}
7190#endif
7191
7192/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007193 * "str2list()" function
7194 */
7195 static void
7196f_str2list(typval_T *argvars, typval_T *rettv)
7197{
7198 char_u *p;
7199 int utf8 = FALSE;
7200
7201 if (rettv_list_alloc(rettv) == FAIL)
7202 return;
7203
7204 if (argvars[1].v_type != VAR_UNKNOWN)
7205 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7206
7207 p = tv_get_string(&argvars[0]);
7208
7209 if (has_mbyte || utf8)
7210 {
7211 int (*ptr2len)(char_u *);
7212 int (*ptr2char)(char_u *);
7213
7214 if (utf8 || enc_utf8)
7215 {
7216 ptr2len = utf_ptr2len;
7217 ptr2char = utf_ptr2char;
7218 }
7219 else
7220 {
7221 ptr2len = mb_ptr2len;
7222 ptr2char = mb_ptr2char;
7223 }
7224
7225 for ( ; *p != NUL; p += (*ptr2len)(p))
7226 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7227 }
7228 else
7229 for ( ; *p != NUL; ++p)
7230 list_append_number(rettv->vval.v_list, *p);
7231}
7232
7233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007234 * "str2nr()" function
7235 */
7236 static void
7237f_str2nr(typval_T *argvars, typval_T *rettv)
7238{
7239 int base = 10;
7240 char_u *p;
7241 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007242 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007243 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244
7245 if (argvars[1].v_type != VAR_UNKNOWN)
7246 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007247 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 if (base != 2 && base != 8 && base != 10 && base != 16)
7249 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007250 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251 return;
7252 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007253 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7254 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 }
7256
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007257 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007258 isneg = (*p == '-');
7259 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007260 p = skipwhite(p + 1);
7261 switch (base)
7262 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007263 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7264 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7265 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007267 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7268 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007269 if (isneg)
7270 rettv->vval.v_number = -n;
7271 else
7272 rettv->vval.v_number = n;
7273
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274}
7275
7276#ifdef HAVE_STRFTIME
7277/*
7278 * "strftime({format}[, {time}])" function
7279 */
7280 static void
7281f_strftime(typval_T *argvars, typval_T *rettv)
7282{
7283 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007284 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 struct tm *curtime;
7286 time_t seconds;
7287 char_u *p;
7288
7289 rettv->v_type = VAR_STRING;
7290
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007291 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292 if (argvars[1].v_type == VAR_UNKNOWN)
7293 seconds = time(NULL);
7294 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007295 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007296 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007297 // MSVC returns NULL for an invalid value of seconds.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007298 if (curtime == NULL)
7299 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7300 else
7301 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302 vimconv_T conv;
7303 char_u *enc;
7304
7305 conv.vc_type = CONV_NONE;
7306 enc = enc_locale();
7307 convert_setup(&conv, p_enc, enc);
7308 if (conv.vc_type != CONV_NONE)
7309 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007310 if (p != NULL)
7311 (void)strftime((char *)result_buf, sizeof(result_buf),
7312 (char *)p, curtime);
7313 else
7314 result_buf[0] = NUL;
7315
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007316 if (conv.vc_type != CONV_NONE)
7317 vim_free(p);
7318 convert_setup(&conv, enc, p_enc);
7319 if (conv.vc_type != CONV_NONE)
7320 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7321 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007322 rettv->vval.v_string = vim_strsave(result_buf);
7323
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007324 // Release conversion descriptors
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 convert_setup(&conv, NULL, NULL);
7326 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007327 }
7328}
7329#endif
7330
7331/*
7332 * "strgetchar()" function
7333 */
7334 static void
7335f_strgetchar(typval_T *argvars, typval_T *rettv)
7336{
7337 char_u *str;
7338 int len;
7339 int error = FALSE;
7340 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007341 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342
7343 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007344 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 if (str == NULL)
7346 return;
7347 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007348 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007349 if (error)
7350 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351
Bram Moolenaar13505972019-01-24 15:04:48 +01007352 while (charidx >= 0 && byteidx < len)
7353 {
7354 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007355 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007356 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7357 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007359 --charidx;
7360 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007361 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362}
7363
7364/*
7365 * "stridx()" function
7366 */
7367 static void
7368f_stridx(typval_T *argvars, typval_T *rettv)
7369{
7370 char_u buf[NUMBUFLEN];
7371 char_u *needle;
7372 char_u *haystack;
7373 char_u *save_haystack;
7374 char_u *pos;
7375 int start_idx;
7376
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 needle = tv_get_string_chk(&argvars[1]);
7378 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379 rettv->vval.v_number = -1;
7380 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007381 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382
7383 if (argvars[2].v_type != VAR_UNKNOWN)
7384 {
7385 int error = FALSE;
7386
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007387 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 if (error || start_idx >= (int)STRLEN(haystack))
7389 return;
7390 if (start_idx >= 0)
7391 haystack += start_idx;
7392 }
7393
7394 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7395 if (pos != NULL)
7396 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7397}
7398
7399/*
7400 * "string()" function
7401 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007402 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403f_string(typval_T *argvars, typval_T *rettv)
7404{
7405 char_u *tofree;
7406 char_u numbuf[NUMBUFLEN];
7407
7408 rettv->v_type = VAR_STRING;
7409 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7410 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007411 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 if (rettv->vval.v_string != NULL && tofree == NULL)
7413 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7414}
7415
7416/*
7417 * "strlen()" function
7418 */
7419 static void
7420f_strlen(typval_T *argvars, typval_T *rettv)
7421{
7422 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007423 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424}
7425
7426/*
7427 * "strchars()" function
7428 */
7429 static void
7430f_strchars(typval_T *argvars, typval_T *rettv)
7431{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007432 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 varnumber_T len = 0;
7435 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436
7437 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007438 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007440 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 else
7442 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007443 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7444 while (*s != NUL)
7445 {
7446 func_mb_ptr2char_adv(&s);
7447 ++len;
7448 }
7449 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007450 }
7451}
7452
7453/*
7454 * "strdisplaywidth()" function
7455 */
7456 static void
7457f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7458{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007459 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460 int col = 0;
7461
7462 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007463 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464
7465 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7466}
7467
7468/*
7469 * "strwidth()" function
7470 */
7471 static void
7472f_strwidth(typval_T *argvars, typval_T *rettv)
7473{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007474 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007475
Bram Moolenaar13505972019-01-24 15:04:48 +01007476 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007477}
7478
7479/*
7480 * "strcharpart()" function
7481 */
7482 static void
7483f_strcharpart(typval_T *argvars, typval_T *rettv)
7484{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007485 char_u *p;
7486 int nchar;
7487 int nbyte = 0;
7488 int charlen;
7489 int len = 0;
7490 int slen;
7491 int error = FALSE;
7492
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007493 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007494 slen = (int)STRLEN(p);
7495
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007496 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497 if (!error)
7498 {
7499 if (nchar > 0)
7500 while (nchar > 0 && nbyte < slen)
7501 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007502 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503 --nchar;
7504 }
7505 else
7506 nbyte = nchar;
7507 if (argvars[2].v_type != VAR_UNKNOWN)
7508 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007509 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510 while (charlen > 0 && nbyte + len < slen)
7511 {
7512 int off = nbyte + len;
7513
7514 if (off < 0)
7515 len += 1;
7516 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007517 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 --charlen;
7519 }
7520 }
7521 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007522 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007523 }
7524
7525 /*
7526 * Only return the overlap between the specified part and the actual
7527 * string.
7528 */
7529 if (nbyte < 0)
7530 {
7531 len += nbyte;
7532 nbyte = 0;
7533 }
7534 else if (nbyte > slen)
7535 nbyte = slen;
7536 if (len < 0)
7537 len = 0;
7538 else if (nbyte + len > slen)
7539 len = slen - nbyte;
7540
7541 rettv->v_type = VAR_STRING;
7542 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007543}
7544
7545/*
7546 * "strpart()" function
7547 */
7548 static void
7549f_strpart(typval_T *argvars, typval_T *rettv)
7550{
7551 char_u *p;
7552 int n;
7553 int len;
7554 int slen;
7555 int error = FALSE;
7556
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007557 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558 slen = (int)STRLEN(p);
7559
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007560 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561 if (error)
7562 len = 0;
7563 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007564 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007565 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007566 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567
7568 /*
7569 * Only return the overlap between the specified part and the actual
7570 * string.
7571 */
7572 if (n < 0)
7573 {
7574 len += n;
7575 n = 0;
7576 }
7577 else if (n > slen)
7578 n = slen;
7579 if (len < 0)
7580 len = 0;
7581 else if (n + len > slen)
7582 len = slen - n;
7583
7584 rettv->v_type = VAR_STRING;
7585 rettv->vval.v_string = vim_strnsave(p + n, len);
7586}
7587
Bram Moolenaar10455d42019-11-21 15:36:18 +01007588#ifdef HAVE_STRPTIME
7589/*
7590 * "strptime({format}, {timestring})" function
7591 */
7592 static void
7593f_strptime(typval_T *argvars, typval_T *rettv)
7594{
7595 struct tm tmval;
7596 char_u *fmt;
7597 char_u *str;
7598 vimconv_T conv;
7599 char_u *enc;
7600
7601 vim_memset(&tmval, NUL, sizeof(tmval));
7602 fmt = tv_get_string(&argvars[0]);
7603 str = tv_get_string(&argvars[1]);
7604
7605 conv.vc_type = CONV_NONE;
7606 enc = enc_locale();
7607 convert_setup(&conv, p_enc, enc);
7608 if (conv.vc_type != CONV_NONE)
7609 fmt = string_convert(&conv, fmt, NULL);
7610 if (fmt == NULL
7611 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7612 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7613 rettv->vval.v_number = 0;
7614
7615 if (conv.vc_type != CONV_NONE)
7616 vim_free(fmt);
7617 convert_setup(&conv, NULL, NULL);
7618 vim_free(enc);
7619}
7620#endif
7621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007622/*
7623 * "strridx()" function
7624 */
7625 static void
7626f_strridx(typval_T *argvars, typval_T *rettv)
7627{
7628 char_u buf[NUMBUFLEN];
7629 char_u *needle;
7630 char_u *haystack;
7631 char_u *rest;
7632 char_u *lastmatch = NULL;
7633 int haystack_len, end_idx;
7634
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007635 needle = tv_get_string_chk(&argvars[1]);
7636 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007637
7638 rettv->vval.v_number = -1;
7639 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007640 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007641
7642 haystack_len = (int)STRLEN(haystack);
7643 if (argvars[2].v_type != VAR_UNKNOWN)
7644 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007645 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007648 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649 }
7650 else
7651 end_idx = haystack_len;
7652
7653 if (*needle == NUL)
7654 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007655 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007656 lastmatch = haystack + end_idx;
7657 }
7658 else
7659 {
7660 for (rest = haystack; *rest != '\0'; ++rest)
7661 {
7662 rest = (char_u *)strstr((char *)rest, (char *)needle);
7663 if (rest == NULL || rest > haystack + end_idx)
7664 break;
7665 lastmatch = rest;
7666 }
7667 }
7668
7669 if (lastmatch == NULL)
7670 rettv->vval.v_number = -1;
7671 else
7672 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7673}
7674
7675/*
7676 * "strtrans()" function
7677 */
7678 static void
7679f_strtrans(typval_T *argvars, typval_T *rettv)
7680{
7681 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007682 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007683}
7684
7685/*
7686 * "submatch()" function
7687 */
7688 static void
7689f_submatch(typval_T *argvars, typval_T *rettv)
7690{
7691 int error = FALSE;
7692 int no;
7693 int retList = 0;
7694
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007695 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007696 if (error)
7697 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007698 if (no < 0 || no >= NSUBEXP)
7699 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007700 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007701 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007702 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007703 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007704 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007705 if (error)
7706 return;
7707
7708 if (retList == 0)
7709 {
7710 rettv->v_type = VAR_STRING;
7711 rettv->vval.v_string = reg_submatch(no);
7712 }
7713 else
7714 {
7715 rettv->v_type = VAR_LIST;
7716 rettv->vval.v_list = reg_submatch_list(no);
7717 }
7718}
7719
7720/*
7721 * "substitute()" function
7722 */
7723 static void
7724f_substitute(typval_T *argvars, typval_T *rettv)
7725{
7726 char_u patbuf[NUMBUFLEN];
7727 char_u subbuf[NUMBUFLEN];
7728 char_u flagsbuf[NUMBUFLEN];
7729
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007730 char_u *str = tv_get_string_chk(&argvars[0]);
7731 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007732 char_u *sub = NULL;
7733 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007734 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007735
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007736 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7737 expr = &argvars[2];
7738 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007739 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007742 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7743 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 rettv->vval.v_string = NULL;
7745 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007746 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747}
7748
7749/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007750 * "swapinfo(swap_filename)" function
7751 */
7752 static void
7753f_swapinfo(typval_T *argvars, typval_T *rettv)
7754{
7755 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007756 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007757}
7758
7759/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007760 * "swapname(expr)" function
7761 */
7762 static void
7763f_swapname(typval_T *argvars, typval_T *rettv)
7764{
7765 buf_T *buf;
7766
7767 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007768 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007769 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7770 || buf->b_ml.ml_mfp->mf_fname == NULL)
7771 rettv->vval.v_string = NULL;
7772 else
7773 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7774}
7775
7776/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 * "synID(lnum, col, trans)" function
7778 */
7779 static void
7780f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7781{
7782 int id = 0;
7783#ifdef FEAT_SYN_HL
7784 linenr_T lnum;
7785 colnr_T col;
7786 int trans;
7787 int transerr = FALSE;
7788
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007789 lnum = tv_get_lnum(argvars); // -1 on type error
7790 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007791 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007792
7793 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7794 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7795 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7796#endif
7797
7798 rettv->vval.v_number = id;
7799}
7800
7801/*
7802 * "synIDattr(id, what [, mode])" function
7803 */
7804 static void
7805f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7806{
7807 char_u *p = NULL;
7808#ifdef FEAT_SYN_HL
7809 int id;
7810 char_u *what;
7811 char_u *mode;
7812 char_u modebuf[NUMBUFLEN];
7813 int modec;
7814
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007815 id = (int)tv_get_number(&argvars[0]);
7816 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007817 if (argvars[2].v_type != VAR_UNKNOWN)
7818 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007819 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007820 modec = TOLOWER_ASC(mode[0]);
7821 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007822 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007823 }
7824 else
7825 {
7826#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7827 if (USE_24BIT)
7828 modec = 'g';
7829 else
7830#endif
7831 if (t_colors > 1)
7832 modec = 'c';
7833 else
7834 modec = 't';
7835 }
7836
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007837 switch (TOLOWER_ASC(what[0]))
7838 {
7839 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007840 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007842 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 p = highlight_has_attr(id, HL_BOLD, modec);
7844 break;
7845
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007846 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007847 p = highlight_color(id, what, modec);
7848 break;
7849
7850 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007851 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007853 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 p = highlight_has_attr(id, HL_ITALIC, modec);
7855 break;
7856
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007857 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007858 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 break;
7860
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007861 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007862 p = highlight_has_attr(id, HL_INVERSE, modec);
7863 break;
7864
7865 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007866 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007868 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007869 else if (TOLOWER_ASC(what[1]) == 't' &&
7870 TOLOWER_ASC(what[2]) == 'r')
7871 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007872 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007873 p = highlight_has_attr(id, HL_STANDOUT, modec);
7874 break;
7875
7876 case 'u':
7877 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007878 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007879 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7880 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007881 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7883 break;
7884 }
7885
7886 if (p != NULL)
7887 p = vim_strsave(p);
7888#endif
7889 rettv->v_type = VAR_STRING;
7890 rettv->vval.v_string = p;
7891}
7892
7893/*
7894 * "synIDtrans(id)" function
7895 */
7896 static void
7897f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7898{
7899 int id;
7900
7901#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007902 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903
7904 if (id > 0)
7905 id = syn_get_final_id(id);
7906 else
7907#endif
7908 id = 0;
7909
7910 rettv->vval.v_number = id;
7911}
7912
7913/*
7914 * "synconcealed(lnum, col)" function
7915 */
7916 static void
7917f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7918{
7919#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7920 linenr_T lnum;
7921 colnr_T col;
7922 int syntax_flags = 0;
7923 int cchar;
7924 int matchid = 0;
7925 char_u str[NUMBUFLEN];
7926#endif
7927
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007928 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929
7930#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007931 lnum = tv_get_lnum(argvars); // -1 on type error
7932 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007933
7934 vim_memset(str, NUL, sizeof(str));
7935
7936 if (rettv_list_alloc(rettv) != FAIL)
7937 {
7938 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7939 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7940 && curwin->w_p_cole > 0)
7941 {
7942 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7943 syntax_flags = get_syntax_info(&matchid);
7944
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007945 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007946 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7947 {
7948 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007949 if (cchar == NUL && curwin->w_p_cole == 1)
7950 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 if (cchar != NUL)
7952 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007953 if (has_mbyte)
7954 (*mb_char2bytes)(cchar, str);
7955 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956 str[0] = cchar;
7957 }
7958 }
7959 }
7960
7961 list_append_number(rettv->vval.v_list,
7962 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007963 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964 list_append_string(rettv->vval.v_list, str, -1);
7965 list_append_number(rettv->vval.v_list, matchid);
7966 }
7967#endif
7968}
7969
7970/*
7971 * "synstack(lnum, col)" function
7972 */
7973 static void
7974f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7975{
7976#ifdef FEAT_SYN_HL
7977 linenr_T lnum;
7978 colnr_T col;
7979 int i;
7980 int id;
7981#endif
7982
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007983 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984
7985#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007986 lnum = tv_get_lnum(argvars); // -1 on type error
7987 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007988
7989 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7990 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7991 && rettv_list_alloc(rettv) != FAIL)
7992 {
7993 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7994 for (i = 0; ; ++i)
7995 {
7996 id = syn_get_stack_item(i);
7997 if (id < 0)
7998 break;
7999 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8000 break;
8001 }
8002 }
8003#endif
8004}
8005
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006/*
8007 * "tabpagebuflist()" function
8008 */
8009 static void
8010f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8011{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008012 tabpage_T *tp;
8013 win_T *wp = NULL;
8014
8015 if (argvars[0].v_type == VAR_UNKNOWN)
8016 wp = firstwin;
8017 else
8018 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008019 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020 if (tp != NULL)
8021 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8022 }
8023 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8024 {
8025 for (; wp != NULL; wp = wp->w_next)
8026 if (list_append_number(rettv->vval.v_list,
8027 wp->w_buffer->b_fnum) == FAIL)
8028 break;
8029 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030}
8031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 * "tagfiles()" function
8034 */
8035 static void
8036f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8037{
8038 char_u *fname;
8039 tagname_T tn;
8040 int first;
8041
8042 if (rettv_list_alloc(rettv) == FAIL)
8043 return;
8044 fname = alloc(MAXPATHL);
8045 if (fname == NULL)
8046 return;
8047
8048 for (first = TRUE; ; first = FALSE)
8049 if (get_tagfname(&tn, first, fname) == FAIL
8050 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8051 break;
8052 tagname_free(&tn);
8053 vim_free(fname);
8054}
8055
8056/*
8057 * "taglist()" function
8058 */
8059 static void
8060f_taglist(typval_T *argvars, typval_T *rettv)
8061{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008062 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063 char_u *tag_pattern;
8064
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008065 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066
8067 rettv->vval.v_number = FALSE;
8068 if (*tag_pattern == NUL)
8069 return;
8070
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008071 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008072 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008073 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008074 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008075}
8076
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008077#ifdef FEAT_FLOAT
8078/*
8079 * "tan()" function
8080 */
8081 static void
8082f_tan(typval_T *argvars, typval_T *rettv)
8083{
8084 float_T f = 0.0;
8085
8086 rettv->v_type = VAR_FLOAT;
8087 if (get_float_arg(argvars, &f) == OK)
8088 rettv->vval.v_float = tan(f);
8089 else
8090 rettv->vval.v_float = 0.0;
8091}
8092
8093/*
8094 * "tanh()" function
8095 */
8096 static void
8097f_tanh(typval_T *argvars, typval_T *rettv)
8098{
8099 float_T f = 0.0;
8100
8101 rettv->v_type = VAR_FLOAT;
8102 if (get_float_arg(argvars, &f) == OK)
8103 rettv->vval.v_float = tanh(f);
8104 else
8105 rettv->vval.v_float = 0.0;
8106}
8107#endif
8108
8109/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110 * "tolower(string)" function
8111 */
8112 static void
8113f_tolower(typval_T *argvars, typval_T *rettv)
8114{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008115 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008116 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008117}
8118
8119/*
8120 * "toupper(string)" function
8121 */
8122 static void
8123f_toupper(typval_T *argvars, typval_T *rettv)
8124{
8125 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008126 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008127}
8128
8129/*
8130 * "tr(string, fromstr, tostr)" function
8131 */
8132 static void
8133f_tr(typval_T *argvars, typval_T *rettv)
8134{
8135 char_u *in_str;
8136 char_u *fromstr;
8137 char_u *tostr;
8138 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008139 int inlen;
8140 int fromlen;
8141 int tolen;
8142 int idx;
8143 char_u *cpstr;
8144 int cplen;
8145 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 char_u buf[NUMBUFLEN];
8147 char_u buf2[NUMBUFLEN];
8148 garray_T ga;
8149
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008150 in_str = tv_get_string(&argvars[0]);
8151 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8152 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008154 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008155 rettv->v_type = VAR_STRING;
8156 rettv->vval.v_string = NULL;
8157 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008158 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 ga_init2(&ga, (int)sizeof(char), 80);
8160
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008162 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 if (STRLEN(fromstr) != STRLEN(tostr))
8164 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008166 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 ga_clear(&ga);
8168 return;
8169 }
8170
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008171 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008172 while (*in_str != NUL)
8173 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 if (has_mbyte)
8175 {
8176 inlen = (*mb_ptr2len)(in_str);
8177 cpstr = in_str;
8178 cplen = inlen;
8179 idx = 0;
8180 for (p = fromstr; *p != NUL; p += fromlen)
8181 {
8182 fromlen = (*mb_ptr2len)(p);
8183 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8184 {
8185 for (p = tostr; *p != NUL; p += tolen)
8186 {
8187 tolen = (*mb_ptr2len)(p);
8188 if (idx-- == 0)
8189 {
8190 cplen = tolen;
8191 cpstr = p;
8192 break;
8193 }
8194 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008195 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008196 goto error;
8197 break;
8198 }
8199 ++idx;
8200 }
8201
8202 if (first && cpstr == in_str)
8203 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008204 // Check that fromstr and tostr have the same number of
8205 // (multi-byte) characters. Done only once when a character
8206 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008207 first = FALSE;
8208 for (p = tostr; *p != NUL; p += tolen)
8209 {
8210 tolen = (*mb_ptr2len)(p);
8211 --idx;
8212 }
8213 if (idx != 0)
8214 goto error;
8215 }
8216
8217 (void)ga_grow(&ga, cplen);
8218 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8219 ga.ga_len += cplen;
8220
8221 in_str += inlen;
8222 }
8223 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008224 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008225 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 p = vim_strchr(fromstr, *in_str);
8227 if (p != NULL)
8228 ga_append(&ga, tostr[p - fromstr]);
8229 else
8230 ga_append(&ga, *in_str);
8231 ++in_str;
8232 }
8233 }
8234
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008235 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008236 (void)ga_grow(&ga, 1);
8237 ga_append(&ga, NUL);
8238
8239 rettv->vval.v_string = ga.ga_data;
8240}
8241
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008242/*
8243 * "trim({expr})" function
8244 */
8245 static void
8246f_trim(typval_T *argvars, typval_T *rettv)
8247{
8248 char_u buf1[NUMBUFLEN];
8249 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008250 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008251 char_u *mask = NULL;
8252 char_u *tail;
8253 char_u *prev;
8254 char_u *p;
8255 int c1;
8256
8257 rettv->v_type = VAR_STRING;
8258 if (head == NULL)
8259 {
8260 rettv->vval.v_string = NULL;
8261 return;
8262 }
8263
8264 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008265 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008266
8267 while (*head != NUL)
8268 {
8269 c1 = PTR2CHAR(head);
8270 if (mask == NULL)
8271 {
8272 if (c1 > ' ' && c1 != 0xa0)
8273 break;
8274 }
8275 else
8276 {
8277 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8278 if (c1 == PTR2CHAR(p))
8279 break;
8280 if (*p == NUL)
8281 break;
8282 }
8283 MB_PTR_ADV(head);
8284 }
8285
8286 for (tail = head + STRLEN(head); tail > head; tail = prev)
8287 {
8288 prev = tail;
8289 MB_PTR_BACK(head, prev);
8290 c1 = PTR2CHAR(prev);
8291 if (mask == NULL)
8292 {
8293 if (c1 > ' ' && c1 != 0xa0)
8294 break;
8295 }
8296 else
8297 {
8298 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8299 if (c1 == PTR2CHAR(p))
8300 break;
8301 if (*p == NUL)
8302 break;
8303 }
8304 }
8305 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8306}
8307
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308#ifdef FEAT_FLOAT
8309/*
8310 * "trunc({float})" function
8311 */
8312 static void
8313f_trunc(typval_T *argvars, typval_T *rettv)
8314{
8315 float_T f = 0.0;
8316
8317 rettv->v_type = VAR_FLOAT;
8318 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008319 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008320 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8321 else
8322 rettv->vval.v_float = 0.0;
8323}
8324#endif
8325
8326/*
8327 * "type(expr)" function
8328 */
8329 static void
8330f_type(typval_T *argvars, typval_T *rettv)
8331{
8332 int n = -1;
8333
8334 switch (argvars[0].v_type)
8335 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008336 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8337 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008338 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008339 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8340 case VAR_LIST: n = VAR_TYPE_LIST; break;
8341 case VAR_DICT: n = VAR_TYPE_DICT; break;
8342 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343 case VAR_SPECIAL:
8344 if (argvars[0].vval.v_number == VVAL_FALSE
8345 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008346 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008347 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008348 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008349 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008350 case VAR_JOB: n = VAR_TYPE_JOB; break;
8351 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008352 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008354 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 n = -1;
8356 break;
8357 }
8358 rettv->vval.v_number = n;
8359}
8360
8361/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008362 * "virtcol(string)" function
8363 */
8364 static void
8365f_virtcol(typval_T *argvars, typval_T *rettv)
8366{
8367 colnr_T vcol = 0;
8368 pos_T *fp;
8369 int fnum = curbuf->b_fnum;
8370
8371 fp = var2fpos(&argvars[0], FALSE, &fnum);
8372 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8373 && fnum == curbuf->b_fnum)
8374 {
8375 getvvcol(curwin, fp, NULL, NULL, &vcol);
8376 ++vcol;
8377 }
8378
8379 rettv->vval.v_number = vcol;
8380}
8381
8382/*
8383 * "visualmode()" function
8384 */
8385 static void
8386f_visualmode(typval_T *argvars, typval_T *rettv)
8387{
8388 char_u str[2];
8389
8390 rettv->v_type = VAR_STRING;
8391 str[0] = curbuf->b_visual_mode_eval;
8392 str[1] = NUL;
8393 rettv->vval.v_string = vim_strsave(str);
8394
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008395 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008396 if (non_zero_arg(&argvars[0]))
8397 curbuf->b_visual_mode_eval = NUL;
8398}
8399
8400/*
8401 * "wildmenumode()" function
8402 */
8403 static void
8404f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8405{
8406#ifdef FEAT_WILDMENU
8407 if (wild_menu_showing)
8408 rettv->vval.v_number = 1;
8409#endif
8410}
8411
8412/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008413 * "windowsversion()" function
8414 */
8415 static void
8416f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8417{
8418 rettv->v_type = VAR_STRING;
8419 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8420}
8421
8422/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423 * "wordcount()" function
8424 */
8425 static void
8426f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8427{
8428 if (rettv_dict_alloc(rettv) == FAIL)
8429 return;
8430 cursor_pos_info(rettv->vval.v_dict);
8431}
8432
8433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008434 * "xor(expr, expr)" function
8435 */
8436 static void
8437f_xor(typval_T *argvars, typval_T *rettv)
8438{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008439 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8440 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008441}
8442
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008443#endif // FEAT_EVAL