blob: ae17038cceb00e3feca29db804588a22af8ca60a [file] [log] [blame]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001/* vi:set ts=8 sts=4 sw=4:
2 *
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
19#ifdef AMIGA
20# include <time.h> /* for strftime() */
21#endif
22
23#ifdef VMS
24# include <float.h>
25#endif
26
27#ifdef MACOS
28# include <time.h> /* for time_t */
29#endif
30
31static char *e_listarg = N_("E686: Argument of %s must be a List");
32#ifdef FEAT_QUICKFIX
33static char *e_stringreq = N_("E928: String required");
34#endif
35
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
43static void f_argc(typval_T *argvars, typval_T *rettv);
44static void f_argidx(typval_T *argvars, typval_T *rettv);
45static void f_arglistid(typval_T *argvars, typval_T *rettv);
46static void f_argv(typval_T *argvars, typval_T *rettv);
47static void f_assert_equal(typval_T *argvars, typval_T *rettv);
48static void f_assert_exception(typval_T *argvars, typval_T *rettv);
49static void f_assert_fails(typval_T *argvars, typval_T *rettv);
50static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020051static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_assert_match(typval_T *argvars, typval_T *rettv);
53static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
54static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
55static void f_assert_true(typval_T *argvars, typval_T *rettv);
56#ifdef FEAT_FLOAT
57static void f_asin(typval_T *argvars, typval_T *rettv);
58static void f_atan(typval_T *argvars, typval_T *rettv);
59static void f_atan2(typval_T *argvars, typval_T *rettv);
60#endif
61static void f_browse(typval_T *argvars, typval_T *rettv);
62static void f_browsedir(typval_T *argvars, typval_T *rettv);
63static void f_bufexists(typval_T *argvars, typval_T *rettv);
64static void f_buflisted(typval_T *argvars, typval_T *rettv);
65static void f_bufloaded(typval_T *argvars, typval_T *rettv);
66static void f_bufname(typval_T *argvars, typval_T *rettv);
67static void f_bufnr(typval_T *argvars, typval_T *rettv);
68static void f_bufwinid(typval_T *argvars, typval_T *rettv);
69static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
70static void f_byte2line(typval_T *argvars, typval_T *rettv);
71static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
72static void f_byteidx(typval_T *argvars, typval_T *rettv);
73static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
74static void f_call(typval_T *argvars, typval_T *rettv);
75#ifdef FEAT_FLOAT
76static void f_ceil(typval_T *argvars, typval_T *rettv);
77#endif
78#ifdef FEAT_JOB_CHANNEL
79static void f_ch_close(typval_T *argvars, typval_T *rettv);
80static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
81static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
82static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
83static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
84static void f_ch_info(typval_T *argvars, typval_T *rettv);
85static void f_ch_log(typval_T *argvars, typval_T *rettv);
86static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
87static void f_ch_open(typval_T *argvars, typval_T *rettv);
88static void f_ch_read(typval_T *argvars, typval_T *rettv);
89static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
90static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
91static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
92static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
93static void f_ch_status(typval_T *argvars, typval_T *rettv);
94#endif
95static void f_changenr(typval_T *argvars, typval_T *rettv);
96static void f_char2nr(typval_T *argvars, typval_T *rettv);
97static void f_cindent(typval_T *argvars, typval_T *rettv);
98static void f_clearmatches(typval_T *argvars, typval_T *rettv);
99static void f_col(typval_T *argvars, typval_T *rettv);
100#if defined(FEAT_INS_EXPAND)
101static void f_complete(typval_T *argvars, typval_T *rettv);
102static void f_complete_add(typval_T *argvars, typval_T *rettv);
103static void f_complete_check(typval_T *argvars, typval_T *rettv);
104#endif
105static void f_confirm(typval_T *argvars, typval_T *rettv);
106static void f_copy(typval_T *argvars, typval_T *rettv);
107#ifdef FEAT_FLOAT
108static void f_cos(typval_T *argvars, typval_T *rettv);
109static void f_cosh(typval_T *argvars, typval_T *rettv);
110#endif
111static void f_count(typval_T *argvars, typval_T *rettv);
112static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
113static void f_cursor(typval_T *argsvars, typval_T *rettv);
114static void f_deepcopy(typval_T *argvars, typval_T *rettv);
115static void f_delete(typval_T *argvars, typval_T *rettv);
116static void f_did_filetype(typval_T *argvars, typval_T *rettv);
117static void f_diff_filler(typval_T *argvars, typval_T *rettv);
118static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
119static void f_empty(typval_T *argvars, typval_T *rettv);
120static void f_escape(typval_T *argvars, typval_T *rettv);
121static void f_eval(typval_T *argvars, typval_T *rettv);
122static void f_eventhandler(typval_T *argvars, typval_T *rettv);
123static void f_executable(typval_T *argvars, typval_T *rettv);
124static void f_execute(typval_T *argvars, typval_T *rettv);
125static void f_exepath(typval_T *argvars, typval_T *rettv);
126static void f_exists(typval_T *argvars, typval_T *rettv);
127#ifdef FEAT_FLOAT
128static void f_exp(typval_T *argvars, typval_T *rettv);
129#endif
130static void f_expand(typval_T *argvars, typval_T *rettv);
131static void f_extend(typval_T *argvars, typval_T *rettv);
132static void f_feedkeys(typval_T *argvars, typval_T *rettv);
133static void f_filereadable(typval_T *argvars, typval_T *rettv);
134static void f_filewritable(typval_T *argvars, typval_T *rettv);
135static void f_filter(typval_T *argvars, typval_T *rettv);
136static void f_finddir(typval_T *argvars, typval_T *rettv);
137static void f_findfile(typval_T *argvars, typval_T *rettv);
138#ifdef FEAT_FLOAT
139static void f_float2nr(typval_T *argvars, typval_T *rettv);
140static void f_floor(typval_T *argvars, typval_T *rettv);
141static void f_fmod(typval_T *argvars, typval_T *rettv);
142#endif
143static void f_fnameescape(typval_T *argvars, typval_T *rettv);
144static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
145static void f_foldclosed(typval_T *argvars, typval_T *rettv);
146static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
147static void f_foldlevel(typval_T *argvars, typval_T *rettv);
148static void f_foldtext(typval_T *argvars, typval_T *rettv);
149static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
150static void f_foreground(typval_T *argvars, typval_T *rettv);
151static void f_function(typval_T *argvars, typval_T *rettv);
152static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
153static void f_get(typval_T *argvars, typval_T *rettv);
154static void f_getbufline(typval_T *argvars, typval_T *rettv);
155static void f_getbufvar(typval_T *argvars, typval_T *rettv);
156static void f_getchar(typval_T *argvars, typval_T *rettv);
157static void f_getcharmod(typval_T *argvars, typval_T *rettv);
158static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
159static void f_getcmdline(typval_T *argvars, typval_T *rettv);
160#if defined(FEAT_CMDL_COMPL)
161static void f_getcompletion(typval_T *argvars, typval_T *rettv);
162#endif
163static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
164static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
165static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
166static void f_getcwd(typval_T *argvars, typval_T *rettv);
167static void f_getfontname(typval_T *argvars, typval_T *rettv);
168static void f_getfperm(typval_T *argvars, typval_T *rettv);
169static void f_getfsize(typval_T *argvars, typval_T *rettv);
170static void f_getftime(typval_T *argvars, typval_T *rettv);
171static void f_getftype(typval_T *argvars, typval_T *rettv);
172static void f_getline(typval_T *argvars, typval_T *rettv);
173static void f_getmatches(typval_T *argvars, typval_T *rettv);
174static void f_getpid(typval_T *argvars, typval_T *rettv);
175static void f_getcurpos(typval_T *argvars, typval_T *rettv);
176static void f_getpos(typval_T *argvars, typval_T *rettv);
177static void f_getqflist(typval_T *argvars, typval_T *rettv);
178static void f_getreg(typval_T *argvars, typval_T *rettv);
179static void f_getregtype(typval_T *argvars, typval_T *rettv);
180static void f_gettabvar(typval_T *argvars, typval_T *rettv);
181static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
182static void f_getwinposx(typval_T *argvars, typval_T *rettv);
183static void f_getwinposy(typval_T *argvars, typval_T *rettv);
184static void f_getwinvar(typval_T *argvars, typval_T *rettv);
185static void f_glob(typval_T *argvars, typval_T *rettv);
186static void f_globpath(typval_T *argvars, typval_T *rettv);
187static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
188static void f_has(typval_T *argvars, typval_T *rettv);
189static void f_has_key(typval_T *argvars, typval_T *rettv);
190static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
191static void f_hasmapto(typval_T *argvars, typval_T *rettv);
192static void f_histadd(typval_T *argvars, typval_T *rettv);
193static void f_histdel(typval_T *argvars, typval_T *rettv);
194static void f_histget(typval_T *argvars, typval_T *rettv);
195static void f_histnr(typval_T *argvars, typval_T *rettv);
196static void f_hlID(typval_T *argvars, typval_T *rettv);
197static void f_hlexists(typval_T *argvars, typval_T *rettv);
198static void f_hostname(typval_T *argvars, typval_T *rettv);
199static void f_iconv(typval_T *argvars, typval_T *rettv);
200static void f_indent(typval_T *argvars, typval_T *rettv);
201static void f_index(typval_T *argvars, typval_T *rettv);
202static void f_input(typval_T *argvars, typval_T *rettv);
203static void f_inputdialog(typval_T *argvars, typval_T *rettv);
204static void f_inputlist(typval_T *argvars, typval_T *rettv);
205static void f_inputrestore(typval_T *argvars, typval_T *rettv);
206static void f_inputsave(typval_T *argvars, typval_T *rettv);
207static void f_inputsecret(typval_T *argvars, typval_T *rettv);
208static void f_insert(typval_T *argvars, typval_T *rettv);
209static void f_invert(typval_T *argvars, typval_T *rettv);
210static void f_isdirectory(typval_T *argvars, typval_T *rettv);
211static void f_islocked(typval_T *argvars, typval_T *rettv);
212#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
213static void f_isnan(typval_T *argvars, typval_T *rettv);
214#endif
215static void f_items(typval_T *argvars, typval_T *rettv);
216#ifdef FEAT_JOB_CHANNEL
217static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
218static void f_job_info(typval_T *argvars, typval_T *rettv);
219static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
220static void f_job_start(typval_T *argvars, typval_T *rettv);
221static void f_job_stop(typval_T *argvars, typval_T *rettv);
222static void f_job_status(typval_T *argvars, typval_T *rettv);
223#endif
224static void f_join(typval_T *argvars, typval_T *rettv);
225static void f_js_decode(typval_T *argvars, typval_T *rettv);
226static void f_js_encode(typval_T *argvars, typval_T *rettv);
227static void f_json_decode(typval_T *argvars, typval_T *rettv);
228static void f_json_encode(typval_T *argvars, typval_T *rettv);
229static void f_keys(typval_T *argvars, typval_T *rettv);
230static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
231static void f_len(typval_T *argvars, typval_T *rettv);
232static void f_libcall(typval_T *argvars, typval_T *rettv);
233static void f_libcallnr(typval_T *argvars, typval_T *rettv);
234static void f_line(typval_T *argvars, typval_T *rettv);
235static void f_line2byte(typval_T *argvars, typval_T *rettv);
236static void f_lispindent(typval_T *argvars, typval_T *rettv);
237static void f_localtime(typval_T *argvars, typval_T *rettv);
238#ifdef FEAT_FLOAT
239static void f_log(typval_T *argvars, typval_T *rettv);
240static void f_log10(typval_T *argvars, typval_T *rettv);
241#endif
242#ifdef FEAT_LUA
243static void f_luaeval(typval_T *argvars, typval_T *rettv);
244#endif
245static void f_map(typval_T *argvars, typval_T *rettv);
246static void f_maparg(typval_T *argvars, typval_T *rettv);
247static void f_mapcheck(typval_T *argvars, typval_T *rettv);
248static void f_match(typval_T *argvars, typval_T *rettv);
249static void f_matchadd(typval_T *argvars, typval_T *rettv);
250static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
251static void f_matcharg(typval_T *argvars, typval_T *rettv);
252static void f_matchdelete(typval_T *argvars, typval_T *rettv);
253static void f_matchend(typval_T *argvars, typval_T *rettv);
254static void f_matchlist(typval_T *argvars, typval_T *rettv);
255static void f_matchstr(typval_T *argvars, typval_T *rettv);
256static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
257static void f_max(typval_T *argvars, typval_T *rettv);
258static void f_min(typval_T *argvars, typval_T *rettv);
259#ifdef vim_mkdir
260static void f_mkdir(typval_T *argvars, typval_T *rettv);
261#endif
262static void f_mode(typval_T *argvars, typval_T *rettv);
263#ifdef FEAT_MZSCHEME
264static void f_mzeval(typval_T *argvars, typval_T *rettv);
265#endif
266static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
267static void f_nr2char(typval_T *argvars, typval_T *rettv);
268static void f_or(typval_T *argvars, typval_T *rettv);
269static void f_pathshorten(typval_T *argvars, typval_T *rettv);
270#ifdef FEAT_PERL
271static void f_perleval(typval_T *argvars, typval_T *rettv);
272#endif
273#ifdef FEAT_FLOAT
274static void f_pow(typval_T *argvars, typval_T *rettv);
275#endif
276static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
277static void f_printf(typval_T *argvars, typval_T *rettv);
278static void f_pumvisible(typval_T *argvars, typval_T *rettv);
279#ifdef FEAT_PYTHON3
280static void f_py3eval(typval_T *argvars, typval_T *rettv);
281#endif
282#ifdef FEAT_PYTHON
283static void f_pyeval(typval_T *argvars, typval_T *rettv);
284#endif
285static void f_range(typval_T *argvars, typval_T *rettv);
286static void f_readfile(typval_T *argvars, typval_T *rettv);
287static void f_reltime(typval_T *argvars, typval_T *rettv);
288#ifdef FEAT_FLOAT
289static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
290#endif
291static void f_reltimestr(typval_T *argvars, typval_T *rettv);
292static void f_remote_expr(typval_T *argvars, typval_T *rettv);
293static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
294static void f_remote_peek(typval_T *argvars, typval_T *rettv);
295static void f_remote_read(typval_T *argvars, typval_T *rettv);
296static void f_remote_send(typval_T *argvars, typval_T *rettv);
297static void f_remove(typval_T *argvars, typval_T *rettv);
298static void f_rename(typval_T *argvars, typval_T *rettv);
299static void f_repeat(typval_T *argvars, typval_T *rettv);
300static void f_resolve(typval_T *argvars, typval_T *rettv);
301static void f_reverse(typval_T *argvars, typval_T *rettv);
302#ifdef FEAT_FLOAT
303static void f_round(typval_T *argvars, typval_T *rettv);
304#endif
305static void f_screenattr(typval_T *argvars, typval_T *rettv);
306static void f_screenchar(typval_T *argvars, typval_T *rettv);
307static void f_screencol(typval_T *argvars, typval_T *rettv);
308static void f_screenrow(typval_T *argvars, typval_T *rettv);
309static void f_search(typval_T *argvars, typval_T *rettv);
310static void f_searchdecl(typval_T *argvars, typval_T *rettv);
311static void f_searchpair(typval_T *argvars, typval_T *rettv);
312static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
313static void f_searchpos(typval_T *argvars, typval_T *rettv);
314static void f_server2client(typval_T *argvars, typval_T *rettv);
315static void f_serverlist(typval_T *argvars, typval_T *rettv);
316static void f_setbufvar(typval_T *argvars, typval_T *rettv);
317static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
318static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
319static void f_setfperm(typval_T *argvars, typval_T *rettv);
320static void f_setline(typval_T *argvars, typval_T *rettv);
321static void f_setloclist(typval_T *argvars, typval_T *rettv);
322static void f_setmatches(typval_T *argvars, typval_T *rettv);
323static void f_setpos(typval_T *argvars, typval_T *rettv);
324static void f_setqflist(typval_T *argvars, typval_T *rettv);
325static void f_setreg(typval_T *argvars, typval_T *rettv);
326static void f_settabvar(typval_T *argvars, typval_T *rettv);
327static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
328static void f_setwinvar(typval_T *argvars, typval_T *rettv);
329#ifdef FEAT_CRYPT
330static void f_sha256(typval_T *argvars, typval_T *rettv);
331#endif /* FEAT_CRYPT */
332static void f_shellescape(typval_T *argvars, typval_T *rettv);
333static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
334static void f_simplify(typval_T *argvars, typval_T *rettv);
335#ifdef FEAT_FLOAT
336static void f_sin(typval_T *argvars, typval_T *rettv);
337static void f_sinh(typval_T *argvars, typval_T *rettv);
338#endif
339static void f_sort(typval_T *argvars, typval_T *rettv);
340static void f_soundfold(typval_T *argvars, typval_T *rettv);
341static void f_spellbadword(typval_T *argvars, typval_T *rettv);
342static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
343static void f_split(typval_T *argvars, typval_T *rettv);
344#ifdef FEAT_FLOAT
345static void f_sqrt(typval_T *argvars, typval_T *rettv);
346static void f_str2float(typval_T *argvars, typval_T *rettv);
347#endif
348static void f_str2nr(typval_T *argvars, typval_T *rettv);
349static void f_strchars(typval_T *argvars, typval_T *rettv);
350#ifdef HAVE_STRFTIME
351static void f_strftime(typval_T *argvars, typval_T *rettv);
352#endif
353static void f_strgetchar(typval_T *argvars, typval_T *rettv);
354static void f_stridx(typval_T *argvars, typval_T *rettv);
355static void f_string(typval_T *argvars, typval_T *rettv);
356static void f_strlen(typval_T *argvars, typval_T *rettv);
357static void f_strcharpart(typval_T *argvars, typval_T *rettv);
358static void f_strpart(typval_T *argvars, typval_T *rettv);
359static void f_strridx(typval_T *argvars, typval_T *rettv);
360static void f_strtrans(typval_T *argvars, typval_T *rettv);
361static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
362static void f_strwidth(typval_T *argvars, typval_T *rettv);
363static void f_submatch(typval_T *argvars, typval_T *rettv);
364static void f_substitute(typval_T *argvars, typval_T *rettv);
365static void f_synID(typval_T *argvars, typval_T *rettv);
366static void f_synIDattr(typval_T *argvars, typval_T *rettv);
367static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
368static void f_synstack(typval_T *argvars, typval_T *rettv);
369static void f_synconcealed(typval_T *argvars, typval_T *rettv);
370static void f_system(typval_T *argvars, typval_T *rettv);
371static void f_systemlist(typval_T *argvars, typval_T *rettv);
372static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
373static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
374static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
375static void f_taglist(typval_T *argvars, typval_T *rettv);
376static void f_tagfiles(typval_T *argvars, typval_T *rettv);
377static void f_tempname(typval_T *argvars, typval_T *rettv);
378static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
379static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
380static void f_test_disable_char_avail(typval_T *argvars, typval_T *rettv);
381static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
382#ifdef FEAT_JOB_CHANNEL
383static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
384#endif
385static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
386#ifdef FEAT_JOB_CHANNEL
387static void f_test_null_job(typval_T *argvars, typval_T *rettv);
388#endif
389static void f_test_null_list(typval_T *argvars, typval_T *rettv);
390static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
391static void f_test_null_string(typval_T *argvars, typval_T *rettv);
392static void f_test_settime(typval_T *argvars, typval_T *rettv);
393#ifdef FEAT_FLOAT
394static void f_tan(typval_T *argvars, typval_T *rettv);
395static void f_tanh(typval_T *argvars, typval_T *rettv);
396#endif
397#ifdef FEAT_TIMERS
398static void f_timer_start(typval_T *argvars, typval_T *rettv);
399static void f_timer_stop(typval_T *argvars, typval_T *rettv);
400#endif
401static void f_tolower(typval_T *argvars, typval_T *rettv);
402static void f_toupper(typval_T *argvars, typval_T *rettv);
403static void f_tr(typval_T *argvars, typval_T *rettv);
404#ifdef FEAT_FLOAT
405static void f_trunc(typval_T *argvars, typval_T *rettv);
406#endif
407static void f_type(typval_T *argvars, typval_T *rettv);
408static void f_undofile(typval_T *argvars, typval_T *rettv);
409static void f_undotree(typval_T *argvars, typval_T *rettv);
410static void f_uniq(typval_T *argvars, typval_T *rettv);
411static void f_values(typval_T *argvars, typval_T *rettv);
412static void f_virtcol(typval_T *argvars, typval_T *rettv);
413static void f_visualmode(typval_T *argvars, typval_T *rettv);
414static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
415static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
416static void f_win_getid(typval_T *argvars, typval_T *rettv);
417static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
418static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
419static void f_win_id2win(typval_T *argvars, typval_T *rettv);
420static void f_winbufnr(typval_T *argvars, typval_T *rettv);
421static void f_wincol(typval_T *argvars, typval_T *rettv);
422static void f_winheight(typval_T *argvars, typval_T *rettv);
423static void f_winline(typval_T *argvars, typval_T *rettv);
424static void f_winnr(typval_T *argvars, typval_T *rettv);
425static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
426static void f_winrestview(typval_T *argvars, typval_T *rettv);
427static void f_winsaveview(typval_T *argvars, typval_T *rettv);
428static void f_winwidth(typval_T *argvars, typval_T *rettv);
429static void f_writefile(typval_T *argvars, typval_T *rettv);
430static void f_wordcount(typval_T *argvars, typval_T *rettv);
431static void f_xor(typval_T *argvars, typval_T *rettv);
432
433/*
434 * Array with names and number of arguments of all internal functions
435 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
436 */
437static struct fst
438{
439 char *f_name; /* function name */
440 char f_min_argc; /* minimal number of arguments */
441 char f_max_argc; /* maximal number of arguments */
442 void (*f_func)(typval_T *args, typval_T *rvar);
443 /* implementation of function */
444} functions[] =
445{
446#ifdef FEAT_FLOAT
447 {"abs", 1, 1, f_abs},
448 {"acos", 1, 1, f_acos}, /* WJMc */
449#endif
450 {"add", 2, 2, f_add},
451 {"and", 2, 2, f_and},
452 {"append", 2, 2, f_append},
453 {"argc", 0, 0, f_argc},
454 {"argidx", 0, 0, f_argidx},
455 {"arglistid", 0, 2, f_arglistid},
456 {"argv", 0, 1, f_argv},
457#ifdef FEAT_FLOAT
458 {"asin", 1, 1, f_asin}, /* WJMc */
459#endif
460 {"assert_equal", 2, 3, f_assert_equal},
461 {"assert_exception", 1, 2, f_assert_exception},
462 {"assert_fails", 1, 2, f_assert_fails},
463 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar61c04492016-07-23 15:35:35 +0200464 {"assert_inrange", 2, 3, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200465 {"assert_match", 2, 3, f_assert_match},
466 {"assert_notequal", 2, 3, f_assert_notequal},
467 {"assert_notmatch", 2, 3, f_assert_notmatch},
468 {"assert_true", 1, 2, f_assert_true},
469#ifdef FEAT_FLOAT
470 {"atan", 1, 1, f_atan},
471 {"atan2", 2, 2, f_atan2},
472#endif
473 {"browse", 4, 4, f_browse},
474 {"browsedir", 2, 2, f_browsedir},
475 {"bufexists", 1, 1, f_bufexists},
476 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
477 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
478 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
479 {"buflisted", 1, 1, f_buflisted},
480 {"bufloaded", 1, 1, f_bufloaded},
481 {"bufname", 1, 1, f_bufname},
482 {"bufnr", 1, 2, f_bufnr},
483 {"bufwinid", 1, 1, f_bufwinid},
484 {"bufwinnr", 1, 1, f_bufwinnr},
485 {"byte2line", 1, 1, f_byte2line},
486 {"byteidx", 2, 2, f_byteidx},
487 {"byteidxcomp", 2, 2, f_byteidxcomp},
488 {"call", 2, 3, f_call},
489#ifdef FEAT_FLOAT
490 {"ceil", 1, 1, f_ceil},
491#endif
492#ifdef FEAT_JOB_CHANNEL
493 {"ch_close", 1, 1, f_ch_close},
494 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
495 {"ch_evalraw", 2, 3, f_ch_evalraw},
496 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
497 {"ch_getjob", 1, 1, f_ch_getjob},
498 {"ch_info", 1, 1, f_ch_info},
499 {"ch_log", 1, 2, f_ch_log},
500 {"ch_logfile", 1, 2, f_ch_logfile},
501 {"ch_open", 1, 2, f_ch_open},
502 {"ch_read", 1, 2, f_ch_read},
503 {"ch_readraw", 1, 2, f_ch_readraw},
504 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
505 {"ch_sendraw", 2, 3, f_ch_sendraw},
506 {"ch_setoptions", 2, 2, f_ch_setoptions},
507 {"ch_status", 1, 1, f_ch_status},
508#endif
509 {"changenr", 0, 0, f_changenr},
510 {"char2nr", 1, 2, f_char2nr},
511 {"cindent", 1, 1, f_cindent},
512 {"clearmatches", 0, 0, f_clearmatches},
513 {"col", 1, 1, f_col},
514#if defined(FEAT_INS_EXPAND)
515 {"complete", 2, 2, f_complete},
516 {"complete_add", 1, 1, f_complete_add},
517 {"complete_check", 0, 0, f_complete_check},
518#endif
519 {"confirm", 1, 4, f_confirm},
520 {"copy", 1, 1, f_copy},
521#ifdef FEAT_FLOAT
522 {"cos", 1, 1, f_cos},
523 {"cosh", 1, 1, f_cosh},
524#endif
525 {"count", 2, 4, f_count},
526 {"cscope_connection",0,3, f_cscope_connection},
527 {"cursor", 1, 3, f_cursor},
528 {"deepcopy", 1, 2, f_deepcopy},
529 {"delete", 1, 2, f_delete},
530 {"did_filetype", 0, 0, f_did_filetype},
531 {"diff_filler", 1, 1, f_diff_filler},
532 {"diff_hlID", 2, 2, f_diff_hlID},
533 {"empty", 1, 1, f_empty},
534 {"escape", 2, 2, f_escape},
535 {"eval", 1, 1, f_eval},
536 {"eventhandler", 0, 0, f_eventhandler},
537 {"executable", 1, 1, f_executable},
538 {"execute", 1, 2, f_execute},
539 {"exepath", 1, 1, f_exepath},
540 {"exists", 1, 1, f_exists},
541#ifdef FEAT_FLOAT
542 {"exp", 1, 1, f_exp},
543#endif
544 {"expand", 1, 3, f_expand},
545 {"extend", 2, 3, f_extend},
546 {"feedkeys", 1, 2, f_feedkeys},
547 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
548 {"filereadable", 1, 1, f_filereadable},
549 {"filewritable", 1, 1, f_filewritable},
550 {"filter", 2, 2, f_filter},
551 {"finddir", 1, 3, f_finddir},
552 {"findfile", 1, 3, f_findfile},
553#ifdef FEAT_FLOAT
554 {"float2nr", 1, 1, f_float2nr},
555 {"floor", 1, 1, f_floor},
556 {"fmod", 2, 2, f_fmod},
557#endif
558 {"fnameescape", 1, 1, f_fnameescape},
559 {"fnamemodify", 2, 2, f_fnamemodify},
560 {"foldclosed", 1, 1, f_foldclosed},
561 {"foldclosedend", 1, 1, f_foldclosedend},
562 {"foldlevel", 1, 1, f_foldlevel},
563 {"foldtext", 0, 0, f_foldtext},
564 {"foldtextresult", 1, 1, f_foldtextresult},
565 {"foreground", 0, 0, f_foreground},
566 {"function", 1, 3, f_function},
567 {"garbagecollect", 0, 1, f_garbagecollect},
568 {"get", 2, 3, f_get},
569 {"getbufline", 2, 3, f_getbufline},
570 {"getbufvar", 2, 3, f_getbufvar},
571 {"getchar", 0, 1, f_getchar},
572 {"getcharmod", 0, 0, f_getcharmod},
573 {"getcharsearch", 0, 0, f_getcharsearch},
574 {"getcmdline", 0, 0, f_getcmdline},
575 {"getcmdpos", 0, 0, f_getcmdpos},
576 {"getcmdtype", 0, 0, f_getcmdtype},
577 {"getcmdwintype", 0, 0, f_getcmdwintype},
578#if defined(FEAT_CMDL_COMPL)
579 {"getcompletion", 2, 2, f_getcompletion},
580#endif
581 {"getcurpos", 0, 0, f_getcurpos},
582 {"getcwd", 0, 2, f_getcwd},
583 {"getfontname", 0, 1, f_getfontname},
584 {"getfperm", 1, 1, f_getfperm},
585 {"getfsize", 1, 1, f_getfsize},
586 {"getftime", 1, 1, f_getftime},
587 {"getftype", 1, 1, f_getftype},
588 {"getline", 1, 2, f_getline},
589 {"getloclist", 1, 1, f_getqflist},
590 {"getmatches", 0, 0, f_getmatches},
591 {"getpid", 0, 0, f_getpid},
592 {"getpos", 1, 1, f_getpos},
593 {"getqflist", 0, 0, f_getqflist},
594 {"getreg", 0, 3, f_getreg},
595 {"getregtype", 0, 1, f_getregtype},
596 {"gettabvar", 2, 3, f_gettabvar},
597 {"gettabwinvar", 3, 4, f_gettabwinvar},
598 {"getwinposx", 0, 0, f_getwinposx},
599 {"getwinposy", 0, 0, f_getwinposy},
600 {"getwinvar", 2, 3, f_getwinvar},
601 {"glob", 1, 4, f_glob},
602 {"glob2regpat", 1, 1, f_glob2regpat},
603 {"globpath", 2, 5, f_globpath},
604 {"has", 1, 1, f_has},
605 {"has_key", 2, 2, f_has_key},
606 {"haslocaldir", 0, 2, f_haslocaldir},
607 {"hasmapto", 1, 3, f_hasmapto},
608 {"highlightID", 1, 1, f_hlID}, /* obsolete */
609 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
610 {"histadd", 2, 2, f_histadd},
611 {"histdel", 1, 2, f_histdel},
612 {"histget", 1, 2, f_histget},
613 {"histnr", 1, 1, f_histnr},
614 {"hlID", 1, 1, f_hlID},
615 {"hlexists", 1, 1, f_hlexists},
616 {"hostname", 0, 0, f_hostname},
617 {"iconv", 3, 3, f_iconv},
618 {"indent", 1, 1, f_indent},
619 {"index", 2, 4, f_index},
620 {"input", 1, 3, f_input},
621 {"inputdialog", 1, 3, f_inputdialog},
622 {"inputlist", 1, 1, f_inputlist},
623 {"inputrestore", 0, 0, f_inputrestore},
624 {"inputsave", 0, 0, f_inputsave},
625 {"inputsecret", 1, 2, f_inputsecret},
626 {"insert", 2, 3, f_insert},
627 {"invert", 1, 1, f_invert},
628 {"isdirectory", 1, 1, f_isdirectory},
629 {"islocked", 1, 1, f_islocked},
630#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
631 {"isnan", 1, 1, f_isnan},
632#endif
633 {"items", 1, 1, f_items},
634#ifdef FEAT_JOB_CHANNEL
635 {"job_getchannel", 1, 1, f_job_getchannel},
636 {"job_info", 1, 1, f_job_info},
637 {"job_setoptions", 2, 2, f_job_setoptions},
638 {"job_start", 1, 2, f_job_start},
639 {"job_status", 1, 1, f_job_status},
640 {"job_stop", 1, 2, f_job_stop},
641#endif
642 {"join", 1, 2, f_join},
643 {"js_decode", 1, 1, f_js_decode},
644 {"js_encode", 1, 1, f_js_encode},
645 {"json_decode", 1, 1, f_json_decode},
646 {"json_encode", 1, 1, f_json_encode},
647 {"keys", 1, 1, f_keys},
648 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
649 {"len", 1, 1, f_len},
650 {"libcall", 3, 3, f_libcall},
651 {"libcallnr", 3, 3, f_libcallnr},
652 {"line", 1, 1, f_line},
653 {"line2byte", 1, 1, f_line2byte},
654 {"lispindent", 1, 1, f_lispindent},
655 {"localtime", 0, 0, f_localtime},
656#ifdef FEAT_FLOAT
657 {"log", 1, 1, f_log},
658 {"log10", 1, 1, f_log10},
659#endif
660#ifdef FEAT_LUA
661 {"luaeval", 1, 2, f_luaeval},
662#endif
663 {"map", 2, 2, f_map},
664 {"maparg", 1, 4, f_maparg},
665 {"mapcheck", 1, 3, f_mapcheck},
666 {"match", 2, 4, f_match},
667 {"matchadd", 2, 5, f_matchadd},
668 {"matchaddpos", 2, 5, f_matchaddpos},
669 {"matcharg", 1, 1, f_matcharg},
670 {"matchdelete", 1, 1, f_matchdelete},
671 {"matchend", 2, 4, f_matchend},
672 {"matchlist", 2, 4, f_matchlist},
673 {"matchstr", 2, 4, f_matchstr},
674 {"matchstrpos", 2, 4, f_matchstrpos},
675 {"max", 1, 1, f_max},
676 {"min", 1, 1, f_min},
677#ifdef vim_mkdir
678 {"mkdir", 1, 3, f_mkdir},
679#endif
680 {"mode", 0, 1, f_mode},
681#ifdef FEAT_MZSCHEME
682 {"mzeval", 1, 1, f_mzeval},
683#endif
684 {"nextnonblank", 1, 1, f_nextnonblank},
685 {"nr2char", 1, 2, f_nr2char},
686 {"or", 2, 2, f_or},
687 {"pathshorten", 1, 1, f_pathshorten},
688#ifdef FEAT_PERL
689 {"perleval", 1, 1, f_perleval},
690#endif
691#ifdef FEAT_FLOAT
692 {"pow", 2, 2, f_pow},
693#endif
694 {"prevnonblank", 1, 1, f_prevnonblank},
695 {"printf", 2, 19, f_printf},
696 {"pumvisible", 0, 0, f_pumvisible},
697#ifdef FEAT_PYTHON3
698 {"py3eval", 1, 1, f_py3eval},
699#endif
700#ifdef FEAT_PYTHON
701 {"pyeval", 1, 1, f_pyeval},
702#endif
703 {"range", 1, 3, f_range},
704 {"readfile", 1, 3, f_readfile},
705 {"reltime", 0, 2, f_reltime},
706#ifdef FEAT_FLOAT
707 {"reltimefloat", 1, 1, f_reltimefloat},
708#endif
709 {"reltimestr", 1, 1, f_reltimestr},
710 {"remote_expr", 2, 3, f_remote_expr},
711 {"remote_foreground", 1, 1, f_remote_foreground},
712 {"remote_peek", 1, 2, f_remote_peek},
713 {"remote_read", 1, 1, f_remote_read},
714 {"remote_send", 2, 3, f_remote_send},
715 {"remove", 2, 3, f_remove},
716 {"rename", 2, 2, f_rename},
717 {"repeat", 2, 2, f_repeat},
718 {"resolve", 1, 1, f_resolve},
719 {"reverse", 1, 1, f_reverse},
720#ifdef FEAT_FLOAT
721 {"round", 1, 1, f_round},
722#endif
723 {"screenattr", 2, 2, f_screenattr},
724 {"screenchar", 2, 2, f_screenchar},
725 {"screencol", 0, 0, f_screencol},
726 {"screenrow", 0, 0, f_screenrow},
727 {"search", 1, 4, f_search},
728 {"searchdecl", 1, 3, f_searchdecl},
729 {"searchpair", 3, 7, f_searchpair},
730 {"searchpairpos", 3, 7, f_searchpairpos},
731 {"searchpos", 1, 4, f_searchpos},
732 {"server2client", 2, 2, f_server2client},
733 {"serverlist", 0, 0, f_serverlist},
734 {"setbufvar", 3, 3, f_setbufvar},
735 {"setcharsearch", 1, 1, f_setcharsearch},
736 {"setcmdpos", 1, 1, f_setcmdpos},
737 {"setfperm", 2, 2, f_setfperm},
738 {"setline", 2, 2, f_setline},
739 {"setloclist", 2, 3, f_setloclist},
740 {"setmatches", 1, 1, f_setmatches},
741 {"setpos", 2, 2, f_setpos},
742 {"setqflist", 1, 2, f_setqflist},
743 {"setreg", 2, 3, f_setreg},
744 {"settabvar", 3, 3, f_settabvar},
745 {"settabwinvar", 4, 4, f_settabwinvar},
746 {"setwinvar", 3, 3, f_setwinvar},
747#ifdef FEAT_CRYPT
748 {"sha256", 1, 1, f_sha256},
749#endif
750 {"shellescape", 1, 2, f_shellescape},
751 {"shiftwidth", 0, 0, f_shiftwidth},
752 {"simplify", 1, 1, f_simplify},
753#ifdef FEAT_FLOAT
754 {"sin", 1, 1, f_sin},
755 {"sinh", 1, 1, f_sinh},
756#endif
757 {"sort", 1, 3, f_sort},
758 {"soundfold", 1, 1, f_soundfold},
759 {"spellbadword", 0, 1, f_spellbadword},
760 {"spellsuggest", 1, 3, f_spellsuggest},
761 {"split", 1, 3, f_split},
762#ifdef FEAT_FLOAT
763 {"sqrt", 1, 1, f_sqrt},
764 {"str2float", 1, 1, f_str2float},
765#endif
766 {"str2nr", 1, 2, f_str2nr},
767 {"strcharpart", 2, 3, f_strcharpart},
768 {"strchars", 1, 2, f_strchars},
769 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
770#ifdef HAVE_STRFTIME
771 {"strftime", 1, 2, f_strftime},
772#endif
773 {"strgetchar", 2, 2, f_strgetchar},
774 {"stridx", 2, 3, f_stridx},
775 {"string", 1, 1, f_string},
776 {"strlen", 1, 1, f_strlen},
777 {"strpart", 2, 3, f_strpart},
778 {"strridx", 2, 3, f_strridx},
779 {"strtrans", 1, 1, f_strtrans},
780 {"strwidth", 1, 1, f_strwidth},
781 {"submatch", 1, 2, f_submatch},
782 {"substitute", 4, 4, f_substitute},
783 {"synID", 3, 3, f_synID},
784 {"synIDattr", 2, 3, f_synIDattr},
785 {"synIDtrans", 1, 1, f_synIDtrans},
786 {"synconcealed", 2, 2, f_synconcealed},
787 {"synstack", 2, 2, f_synstack},
788 {"system", 1, 2, f_system},
789 {"systemlist", 1, 2, f_systemlist},
790 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
791 {"tabpagenr", 0, 1, f_tabpagenr},
792 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
793 {"tagfiles", 0, 0, f_tagfiles},
794 {"taglist", 1, 1, f_taglist},
795#ifdef FEAT_FLOAT
796 {"tan", 1, 1, f_tan},
797 {"tanh", 1, 1, f_tanh},
798#endif
799 {"tempname", 0, 0, f_tempname},
800 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
801 {"test_autochdir", 0, 0, f_test_autochdir},
802 {"test_disable_char_avail", 1, 1, f_test_disable_char_avail},
803 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
804#ifdef FEAT_JOB_CHANNEL
805 {"test_null_channel", 0, 0, f_test_null_channel},
806#endif
807 {"test_null_dict", 0, 0, f_test_null_dict},
808#ifdef FEAT_JOB_CHANNEL
809 {"test_null_job", 0, 0, f_test_null_job},
810#endif
811 {"test_null_list", 0, 0, f_test_null_list},
812 {"test_null_partial", 0, 0, f_test_null_partial},
813 {"test_null_string", 0, 0, f_test_null_string},
814 {"test_settime", 1, 1, f_test_settime},
815#ifdef FEAT_TIMERS
816 {"timer_start", 2, 3, f_timer_start},
817 {"timer_stop", 1, 1, f_timer_stop},
818#endif
819 {"tolower", 1, 1, f_tolower},
820 {"toupper", 1, 1, f_toupper},
821 {"tr", 3, 3, f_tr},
822#ifdef FEAT_FLOAT
823 {"trunc", 1, 1, f_trunc},
824#endif
825 {"type", 1, 1, f_type},
826 {"undofile", 1, 1, f_undofile},
827 {"undotree", 0, 0, f_undotree},
828 {"uniq", 1, 3, f_uniq},
829 {"values", 1, 1, f_values},
830 {"virtcol", 1, 1, f_virtcol},
831 {"visualmode", 0, 1, f_visualmode},
832 {"wildmenumode", 0, 0, f_wildmenumode},
833 {"win_findbuf", 1, 1, f_win_findbuf},
834 {"win_getid", 0, 2, f_win_getid},
835 {"win_gotoid", 1, 1, f_win_gotoid},
836 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
837 {"win_id2win", 1, 1, f_win_id2win},
838 {"winbufnr", 1, 1, f_winbufnr},
839 {"wincol", 0, 0, f_wincol},
840 {"winheight", 1, 1, f_winheight},
841 {"winline", 0, 0, f_winline},
842 {"winnr", 0, 1, f_winnr},
843 {"winrestcmd", 0, 0, f_winrestcmd},
844 {"winrestview", 1, 1, f_winrestview},
845 {"winsaveview", 0, 0, f_winsaveview},
846 {"winwidth", 1, 1, f_winwidth},
847 {"wordcount", 0, 0, f_wordcount},
848 {"writefile", 2, 3, f_writefile},
849 {"xor", 2, 2, f_xor},
850};
851
852#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
853
854/*
855 * Function given to ExpandGeneric() to obtain the list of internal
856 * or user defined function names.
857 */
858 char_u *
859get_function_name(expand_T *xp, int idx)
860{
861 static int intidx = -1;
862 char_u *name;
863
864 if (idx == 0)
865 intidx = -1;
866 if (intidx < 0)
867 {
868 name = get_user_func_name(xp, idx);
869 if (name != NULL)
870 return name;
871 }
872 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
873 {
874 STRCPY(IObuff, functions[intidx].f_name);
875 STRCAT(IObuff, "(");
876 if (functions[intidx].f_max_argc == 0)
877 STRCAT(IObuff, ")");
878 return IObuff;
879 }
880
881 return NULL;
882}
883
884/*
885 * Function given to ExpandGeneric() to obtain the list of internal or
886 * user defined variable or function names.
887 */
888 char_u *
889get_expr_name(expand_T *xp, int idx)
890{
891 static int intidx = -1;
892 char_u *name;
893
894 if (idx == 0)
895 intidx = -1;
896 if (intidx < 0)
897 {
898 name = get_function_name(xp, idx);
899 if (name != NULL)
900 return name;
901 }
902 return get_user_var_name(xp, ++intidx);
903}
904
905#endif /* FEAT_CMDL_COMPL */
906
907#if defined(EBCDIC) || defined(PROTO)
908/*
909 * Compare struct fst by function name.
910 */
911 static int
912compare_func_name(const void *s1, const void *s2)
913{
914 struct fst *p1 = (struct fst *)s1;
915 struct fst *p2 = (struct fst *)s2;
916
917 return STRCMP(p1->f_name, p2->f_name);
918}
919
920/*
921 * Sort the function table by function name.
922 * The sorting of the table above is ASCII dependant.
923 * On machines using EBCDIC we have to sort it.
924 */
925 static void
926sortFunctions(void)
927{
928 int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
929
930 qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name);
931}
932#endif
933
934
935/*
936 * Find internal function in table above.
937 * Return index, or -1 if not found
938 */
939 int
940find_internal_func(
941 char_u *name) /* name of the function */
942{
943 int first = 0;
944 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
945 int cmp;
946 int x;
947
948 /*
949 * Find the function name in the table. Binary search.
950 */
951 while (first <= last)
952 {
953 x = first + ((unsigned)(last - first) >> 1);
954 cmp = STRCMP(name, functions[x].f_name);
955 if (cmp < 0)
956 last = x - 1;
957 else if (cmp > 0)
958 first = x + 1;
959 else
960 return x;
961 }
962 return -1;
963}
964
965 int
966call_internal_func(
967 char_u *name,
968 int argcount,
969 typval_T *argvars,
970 typval_T *rettv)
971{
972 int i;
973
974 i = find_internal_func(name);
975 if (i < 0)
976 return ERROR_UNKNOWN;
977 if (argcount < functions[i].f_min_argc)
978 return ERROR_TOOFEW;
979 if (argcount > functions[i].f_max_argc)
980 return ERROR_TOOMANY;
981 argvars[argcount].v_type = VAR_UNKNOWN;
982 functions[i].f_func(argvars, rettv);
983 return ERROR_NONE;
984}
985
986/*
987 * Return TRUE for a non-zero Number and a non-empty String.
988 */
989 static int
990non_zero_arg(typval_T *argvars)
991{
992 return ((argvars[0].v_type == VAR_NUMBER
993 && argvars[0].vval.v_number != 0)
994 || (argvars[0].v_type == VAR_SPECIAL
995 && argvars[0].vval.v_number == VVAL_TRUE)
996 || (argvars[0].v_type == VAR_STRING
997 && argvars[0].vval.v_string != NULL
998 && *argvars[0].vval.v_string != NUL));
999}
1000
1001/*
1002 * Get the lnum from the first argument.
1003 * Also accepts ".", "$", etc., but that only works for the current buffer.
1004 * Returns -1 on error.
1005 */
1006 static linenr_T
1007get_tv_lnum(typval_T *argvars)
1008{
1009 typval_T rettv;
1010 linenr_T lnum;
1011
1012 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL);
1013 if (lnum == 0) /* no valid number, try using line() */
1014 {
1015 rettv.v_type = VAR_NUMBER;
1016 f_line(argvars, &rettv);
1017 lnum = (linenr_T)rettv.vval.v_number;
1018 clear_tv(&rettv);
1019 }
1020 return lnum;
1021}
1022
1023#ifdef FEAT_FLOAT
1024static int get_float_arg(typval_T *argvars, float_T *f);
1025
1026/*
1027 * Get the float value of "argvars[0]" into "f".
1028 * Returns FAIL when the argument is not a Number or Float.
1029 */
1030 static int
1031get_float_arg(typval_T *argvars, float_T *f)
1032{
1033 if (argvars[0].v_type == VAR_FLOAT)
1034 {
1035 *f = argvars[0].vval.v_float;
1036 return OK;
1037 }
1038 if (argvars[0].v_type == VAR_NUMBER)
1039 {
1040 *f = (float_T)argvars[0].vval.v_number;
1041 return OK;
1042 }
1043 EMSG(_("E808: Number or Float required"));
1044 return FAIL;
1045}
1046
1047/*
1048 * "abs(expr)" function
1049 */
1050 static void
1051f_abs(typval_T *argvars, typval_T *rettv)
1052{
1053 if (argvars[0].v_type == VAR_FLOAT)
1054 {
1055 rettv->v_type = VAR_FLOAT;
1056 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1057 }
1058 else
1059 {
1060 varnumber_T n;
1061 int error = FALSE;
1062
1063 n = get_tv_number_chk(&argvars[0], &error);
1064 if (error)
1065 rettv->vval.v_number = -1;
1066 else if (n > 0)
1067 rettv->vval.v_number = n;
1068 else
1069 rettv->vval.v_number = -n;
1070 }
1071}
1072
1073/*
1074 * "acos()" function
1075 */
1076 static void
1077f_acos(typval_T *argvars, typval_T *rettv)
1078{
1079 float_T f = 0.0;
1080
1081 rettv->v_type = VAR_FLOAT;
1082 if (get_float_arg(argvars, &f) == OK)
1083 rettv->vval.v_float = acos(f);
1084 else
1085 rettv->vval.v_float = 0.0;
1086}
1087#endif
1088
1089/*
1090 * "add(list, item)" function
1091 */
1092 static void
1093f_add(typval_T *argvars, typval_T *rettv)
1094{
1095 list_T *l;
1096
1097 rettv->vval.v_number = 1; /* Default: Failed */
1098 if (argvars[0].v_type == VAR_LIST)
1099 {
1100 if ((l = argvars[0].vval.v_list) != NULL
1101 && !tv_check_lock(l->lv_lock,
1102 (char_u *)N_("add() argument"), TRUE)
1103 && list_append_tv(l, &argvars[1]) == OK)
1104 copy_tv(&argvars[0], rettv);
1105 }
1106 else
1107 EMSG(_(e_listreq));
1108}
1109
1110/*
1111 * "and(expr, expr)" function
1112 */
1113 static void
1114f_and(typval_T *argvars, typval_T *rettv)
1115{
1116 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
1117 & get_tv_number_chk(&argvars[1], NULL);
1118}
1119
1120/*
1121 * "append(lnum, string/list)" function
1122 */
1123 static void
1124f_append(typval_T *argvars, typval_T *rettv)
1125{
1126 long lnum;
1127 char_u *line;
1128 list_T *l = NULL;
1129 listitem_T *li = NULL;
1130 typval_T *tv;
1131 long added = 0;
1132
1133 /* When coming here from Insert mode, sync undo, so that this can be
1134 * undone separately from what was previously inserted. */
1135 if (u_sync_once == 2)
1136 {
1137 u_sync_once = 1; /* notify that u_sync() was called */
1138 u_sync(TRUE);
1139 }
1140
1141 lnum = get_tv_lnum(argvars);
1142 if (lnum >= 0
1143 && lnum <= curbuf->b_ml.ml_line_count
1144 && u_save(lnum, lnum + 1) == OK)
1145 {
1146 if (argvars[1].v_type == VAR_LIST)
1147 {
1148 l = argvars[1].vval.v_list;
1149 if (l == NULL)
1150 return;
1151 li = l->lv_first;
1152 }
1153 for (;;)
1154 {
1155 if (l == NULL)
1156 tv = &argvars[1]; /* append a string */
1157 else if (li == NULL)
1158 break; /* end of list */
1159 else
1160 tv = &li->li_tv; /* append item from list */
1161 line = get_tv_string_chk(tv);
1162 if (line == NULL) /* type error */
1163 {
1164 rettv->vval.v_number = 1; /* Failed */
1165 break;
1166 }
1167 ml_append(lnum + added, line, (colnr_T)0, FALSE);
1168 ++added;
1169 if (l == NULL)
1170 break;
1171 li = li->li_next;
1172 }
1173
1174 appended_lines_mark(lnum, added);
1175 if (curwin->w_cursor.lnum > lnum)
1176 curwin->w_cursor.lnum += added;
1177 }
1178 else
1179 rettv->vval.v_number = 1; /* Failed */
1180}
1181
1182/*
1183 * "argc()" function
1184 */
1185 static void
1186f_argc(typval_T *argvars UNUSED, typval_T *rettv)
1187{
1188 rettv->vval.v_number = ARGCOUNT;
1189}
1190
1191/*
1192 * "argidx()" function
1193 */
1194 static void
1195f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1196{
1197 rettv->vval.v_number = curwin->w_arg_idx;
1198}
1199
1200/*
1201 * "arglistid()" function
1202 */
1203 static void
1204f_arglistid(typval_T *argvars, typval_T *rettv)
1205{
1206 win_T *wp;
1207
1208 rettv->vval.v_number = -1;
1209 wp = find_tabwin(&argvars[0], &argvars[1]);
1210 if (wp != NULL)
1211 rettv->vval.v_number = wp->w_alist->id;
1212}
1213
1214/*
1215 * "argv(nr)" function
1216 */
1217 static void
1218f_argv(typval_T *argvars, typval_T *rettv)
1219{
1220 int idx;
1221
1222 if (argvars[0].v_type != VAR_UNKNOWN)
1223 {
1224 idx = (int)get_tv_number_chk(&argvars[0], NULL);
1225 if (idx >= 0 && idx < ARGCOUNT)
1226 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx]));
1227 else
1228 rettv->vval.v_string = NULL;
1229 rettv->v_type = VAR_STRING;
1230 }
1231 else if (rettv_list_alloc(rettv) == OK)
1232 for (idx = 0; idx < ARGCOUNT; ++idx)
1233 list_append_string(rettv->vval.v_list,
1234 alist_name(&ARGLIST[idx]), -1);
1235}
1236
1237/*
1238 * "assert_equal(expected, actual[, msg])" function
1239 */
1240 static void
1241f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED)
1242{
1243 assert_equal_common(argvars, ASSERT_EQUAL);
1244}
1245
1246/*
1247 * "assert_notequal(expected, actual[, msg])" function
1248 */
1249 static void
1250f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED)
1251{
1252 assert_equal_common(argvars, ASSERT_NOTEQUAL);
1253}
1254
1255/*
1256 * "assert_exception(string[, msg])" function
1257 */
1258 static void
1259f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED)
1260{
1261 assert_exception(argvars);
1262}
1263
1264/*
1265 * "assert_fails(cmd [, error])" function
1266 */
1267 static void
1268f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED)
1269{
1270 assert_fails(argvars);
1271}
1272
1273/*
1274 * "assert_false(actual[, msg])" function
1275 */
1276 static void
1277f_assert_false(typval_T *argvars, typval_T *rettv UNUSED)
1278{
1279 assert_bool(argvars, FALSE);
1280}
1281
1282/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001283 * "assert_inrange(lower, upper[, msg])" function
1284 */
1285 static void
1286f_assert_inrange(typval_T *argvars, typval_T *rettv UNUSED)
1287{
1288 assert_inrange(argvars);
1289}
1290
1291/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001292 * "assert_match(pattern, actual[, msg])" function
1293 */
1294 static void
1295f_assert_match(typval_T *argvars, typval_T *rettv UNUSED)
1296{
1297 assert_match_common(argvars, ASSERT_MATCH);
1298}
1299
1300/*
1301 * "assert_notmatch(pattern, actual[, msg])" function
1302 */
1303 static void
1304f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED)
1305{
1306 assert_match_common(argvars, ASSERT_NOTMATCH);
1307}
1308
1309/*
1310 * "assert_true(actual[, msg])" function
1311 */
1312 static void
1313f_assert_true(typval_T *argvars, typval_T *rettv UNUSED)
1314{
1315 assert_bool(argvars, TRUE);
1316}
1317
1318#ifdef FEAT_FLOAT
1319/*
1320 * "asin()" function
1321 */
1322 static void
1323f_asin(typval_T *argvars, typval_T *rettv)
1324{
1325 float_T f = 0.0;
1326
1327 rettv->v_type = VAR_FLOAT;
1328 if (get_float_arg(argvars, &f) == OK)
1329 rettv->vval.v_float = asin(f);
1330 else
1331 rettv->vval.v_float = 0.0;
1332}
1333
1334/*
1335 * "atan()" function
1336 */
1337 static void
1338f_atan(typval_T *argvars, typval_T *rettv)
1339{
1340 float_T f = 0.0;
1341
1342 rettv->v_type = VAR_FLOAT;
1343 if (get_float_arg(argvars, &f) == OK)
1344 rettv->vval.v_float = atan(f);
1345 else
1346 rettv->vval.v_float = 0.0;
1347}
1348
1349/*
1350 * "atan2()" function
1351 */
1352 static void
1353f_atan2(typval_T *argvars, typval_T *rettv)
1354{
1355 float_T fx = 0.0, fy = 0.0;
1356
1357 rettv->v_type = VAR_FLOAT;
1358 if (get_float_arg(argvars, &fx) == OK
1359 && get_float_arg(&argvars[1], &fy) == OK)
1360 rettv->vval.v_float = atan2(fx, fy);
1361 else
1362 rettv->vval.v_float = 0.0;
1363}
1364#endif
1365
1366/*
1367 * "browse(save, title, initdir, default)" function
1368 */
1369 static void
1370f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1371{
1372#ifdef FEAT_BROWSE
1373 int save;
1374 char_u *title;
1375 char_u *initdir;
1376 char_u *defname;
1377 char_u buf[NUMBUFLEN];
1378 char_u buf2[NUMBUFLEN];
1379 int error = FALSE;
1380
1381 save = (int)get_tv_number_chk(&argvars[0], &error);
1382 title = get_tv_string_chk(&argvars[1]);
1383 initdir = get_tv_string_buf_chk(&argvars[2], buf);
1384 defname = get_tv_string_buf_chk(&argvars[3], buf2);
1385
1386 if (error || title == NULL || initdir == NULL || defname == NULL)
1387 rettv->vval.v_string = NULL;
1388 else
1389 rettv->vval.v_string =
1390 do_browse(save ? BROWSE_SAVE : 0,
1391 title, defname, NULL, initdir, NULL, curbuf);
1392#else
1393 rettv->vval.v_string = NULL;
1394#endif
1395 rettv->v_type = VAR_STRING;
1396}
1397
1398/*
1399 * "browsedir(title, initdir)" function
1400 */
1401 static void
1402f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1403{
1404#ifdef FEAT_BROWSE
1405 char_u *title;
1406 char_u *initdir;
1407 char_u buf[NUMBUFLEN];
1408
1409 title = get_tv_string_chk(&argvars[0]);
1410 initdir = get_tv_string_buf_chk(&argvars[1], buf);
1411
1412 if (title == NULL || initdir == NULL)
1413 rettv->vval.v_string = NULL;
1414 else
1415 rettv->vval.v_string = do_browse(BROWSE_DIR,
1416 title, NULL, NULL, initdir, NULL, curbuf);
1417#else
1418 rettv->vval.v_string = NULL;
1419#endif
1420 rettv->v_type = VAR_STRING;
1421}
1422
1423static buf_T *find_buffer(typval_T *avar);
1424
1425/*
1426 * Find a buffer by number or exact name.
1427 */
1428 static buf_T *
1429find_buffer(typval_T *avar)
1430{
1431 buf_T *buf = NULL;
1432
1433 if (avar->v_type == VAR_NUMBER)
1434 buf = buflist_findnr((int)avar->vval.v_number);
1435 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1436 {
1437 buf = buflist_findname_exp(avar->vval.v_string);
1438 if (buf == NULL)
1439 {
1440 /* No full path name match, try a match with a URL or a "nofile"
1441 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001442 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443 if (buf->b_fname != NULL
1444 && (path_with_url(buf->b_fname)
1445#ifdef FEAT_QUICKFIX
1446 || bt_nofile(buf)
1447#endif
1448 )
1449 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1450 break;
1451 }
1452 }
1453 return buf;
1454}
1455
1456/*
1457 * "bufexists(expr)" function
1458 */
1459 static void
1460f_bufexists(typval_T *argvars, typval_T *rettv)
1461{
1462 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1463}
1464
1465/*
1466 * "buflisted(expr)" function
1467 */
1468 static void
1469f_buflisted(typval_T *argvars, typval_T *rettv)
1470{
1471 buf_T *buf;
1472
1473 buf = find_buffer(&argvars[0]);
1474 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1475}
1476
1477/*
1478 * "bufloaded(expr)" function
1479 */
1480 static void
1481f_bufloaded(typval_T *argvars, typval_T *rettv)
1482{
1483 buf_T *buf;
1484
1485 buf = find_buffer(&argvars[0]);
1486 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1487}
1488
1489 buf_T *
1490buflist_find_by_name(char_u *name, int curtab_only)
1491{
1492 int save_magic;
1493 char_u *save_cpo;
1494 buf_T *buf;
1495
1496 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1497 save_magic = p_magic;
1498 p_magic = TRUE;
1499 save_cpo = p_cpo;
1500 p_cpo = (char_u *)"";
1501
1502 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1503 TRUE, FALSE, curtab_only));
1504
1505 p_magic = save_magic;
1506 p_cpo = save_cpo;
1507 return buf;
1508}
1509
1510/*
1511 * Get buffer by number or pattern.
1512 */
1513 static buf_T *
1514get_buf_tv(typval_T *tv, int curtab_only)
1515{
1516 char_u *name = tv->vval.v_string;
1517 buf_T *buf;
1518
1519 if (tv->v_type == VAR_NUMBER)
1520 return buflist_findnr((int)tv->vval.v_number);
1521 if (tv->v_type != VAR_STRING)
1522 return NULL;
1523 if (name == NULL || *name == NUL)
1524 return curbuf;
1525 if (name[0] == '$' && name[1] == NUL)
1526 return lastbuf;
1527
1528 buf = buflist_find_by_name(name, curtab_only);
1529
1530 /* If not found, try expanding the name, like done for bufexists(). */
1531 if (buf == NULL)
1532 buf = find_buffer(tv);
1533
1534 return buf;
1535}
1536
1537/*
1538 * "bufname(expr)" function
1539 */
1540 static void
1541f_bufname(typval_T *argvars, typval_T *rettv)
1542{
1543 buf_T *buf;
1544
1545 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1546 ++emsg_off;
1547 buf = get_buf_tv(&argvars[0], FALSE);
1548 rettv->v_type = VAR_STRING;
1549 if (buf != NULL && buf->b_fname != NULL)
1550 rettv->vval.v_string = vim_strsave(buf->b_fname);
1551 else
1552 rettv->vval.v_string = NULL;
1553 --emsg_off;
1554}
1555
1556/*
1557 * "bufnr(expr)" function
1558 */
1559 static void
1560f_bufnr(typval_T *argvars, typval_T *rettv)
1561{
1562 buf_T *buf;
1563 int error = FALSE;
1564 char_u *name;
1565
1566 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1567 ++emsg_off;
1568 buf = get_buf_tv(&argvars[0], FALSE);
1569 --emsg_off;
1570
1571 /* If the buffer isn't found and the second argument is not zero create a
1572 * new buffer. */
1573 if (buf == NULL
1574 && argvars[1].v_type != VAR_UNKNOWN
1575 && get_tv_number_chk(&argvars[1], &error) != 0
1576 && !error
1577 && (name = get_tv_string_chk(&argvars[0])) != NULL
1578 && !error)
1579 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1580
1581 if (buf != NULL)
1582 rettv->vval.v_number = buf->b_fnum;
1583 else
1584 rettv->vval.v_number = -1;
1585}
1586
1587 static void
1588buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1589{
1590#ifdef FEAT_WINDOWS
1591 win_T *wp;
1592 int winnr = 0;
1593#endif
1594 buf_T *buf;
1595
1596 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
1597 ++emsg_off;
1598 buf = get_buf_tv(&argvars[0], TRUE);
1599#ifdef FEAT_WINDOWS
Bram Moolenaar29323592016-07-24 22:04:11 +02001600 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601 {
1602 ++winnr;
1603 if (wp->w_buffer == buf)
1604 break;
1605 }
1606 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
1607#else
1608 rettv->vval.v_number = (curwin->w_buffer == buf
1609 ? (get_nr ? 1 : curwin->w_id) : -1);
1610#endif
1611 --emsg_off;
1612}
1613
1614/*
1615 * "bufwinid(nr)" function
1616 */
1617 static void
1618f_bufwinid(typval_T *argvars, typval_T *rettv)
1619{
1620 buf_win_common(argvars, rettv, FALSE);
1621}
1622
1623/*
1624 * "bufwinnr(nr)" function
1625 */
1626 static void
1627f_bufwinnr(typval_T *argvars, typval_T *rettv)
1628{
1629 buf_win_common(argvars, rettv, TRUE);
1630}
1631
1632/*
1633 * "byte2line(byte)" function
1634 */
1635 static void
1636f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1637{
1638#ifndef FEAT_BYTEOFF
1639 rettv->vval.v_number = -1;
1640#else
1641 long boff = 0;
1642
1643 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */
1644 if (boff < 0)
1645 rettv->vval.v_number = -1;
1646 else
1647 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1648 (linenr_T)0, &boff);
1649#endif
1650}
1651
1652 static void
1653byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1654{
1655#ifdef FEAT_MBYTE
1656 char_u *t;
1657#endif
1658 char_u *str;
1659 varnumber_T idx;
1660
1661 str = get_tv_string_chk(&argvars[0]);
1662 idx = get_tv_number_chk(&argvars[1], NULL);
1663 rettv->vval.v_number = -1;
1664 if (str == NULL || idx < 0)
1665 return;
1666
1667#ifdef FEAT_MBYTE
1668 t = str;
1669 for ( ; idx > 0; idx--)
1670 {
1671 if (*t == NUL) /* EOL reached */
1672 return;
1673 if (enc_utf8 && comp)
1674 t += utf_ptr2len(t);
1675 else
1676 t += (*mb_ptr2len)(t);
1677 }
1678 rettv->vval.v_number = (varnumber_T)(t - str);
1679#else
1680 if ((size_t)idx <= STRLEN(str))
1681 rettv->vval.v_number = idx;
1682#endif
1683}
1684
1685/*
1686 * "byteidx()" function
1687 */
1688 static void
1689f_byteidx(typval_T *argvars, typval_T *rettv)
1690{
1691 byteidx(argvars, rettv, FALSE);
1692}
1693
1694/*
1695 * "byteidxcomp()" function
1696 */
1697 static void
1698f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1699{
1700 byteidx(argvars, rettv, TRUE);
1701}
1702
1703/*
1704 * "call(func, arglist [, dict])" function
1705 */
1706 static void
1707f_call(typval_T *argvars, typval_T *rettv)
1708{
1709 char_u *func;
1710 partial_T *partial = NULL;
1711 dict_T *selfdict = NULL;
1712
1713 if (argvars[1].v_type != VAR_LIST)
1714 {
1715 EMSG(_(e_listreq));
1716 return;
1717 }
1718 if (argvars[1].vval.v_list == NULL)
1719 return;
1720
1721 if (argvars[0].v_type == VAR_FUNC)
1722 func = argvars[0].vval.v_string;
1723 else if (argvars[0].v_type == VAR_PARTIAL)
1724 {
1725 partial = argvars[0].vval.v_partial;
1726 func = partial->pt_name;
1727 }
1728 else
1729 func = get_tv_string(&argvars[0]);
1730 if (*func == NUL)
1731 return; /* type error or empty name */
1732
1733 if (argvars[2].v_type != VAR_UNKNOWN)
1734 {
1735 if (argvars[2].v_type != VAR_DICT)
1736 {
1737 EMSG(_(e_dictreq));
1738 return;
1739 }
1740 selfdict = argvars[2].vval.v_dict;
1741 }
1742
1743 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1744}
1745
1746#ifdef FEAT_FLOAT
1747/*
1748 * "ceil({float})" function
1749 */
1750 static void
1751f_ceil(typval_T *argvars, typval_T *rettv)
1752{
1753 float_T f = 0.0;
1754
1755 rettv->v_type = VAR_FLOAT;
1756 if (get_float_arg(argvars, &f) == OK)
1757 rettv->vval.v_float = ceil(f);
1758 else
1759 rettv->vval.v_float = 0.0;
1760}
1761#endif
1762
1763#ifdef FEAT_JOB_CHANNEL
1764/*
1765 * "ch_close()" function
1766 */
1767 static void
1768f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
1769{
1770 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
1771
1772 if (channel != NULL)
1773 {
1774 channel_close(channel, FALSE);
1775 channel_clear(channel);
1776 }
1777}
1778
1779/*
1780 * "ch_getbufnr()" function
1781 */
1782 static void
1783f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
1784{
1785 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1786
1787 rettv->vval.v_number = -1;
1788 if (channel != NULL)
1789 {
1790 char_u *what = get_tv_string(&argvars[1]);
1791 int part;
1792
1793 if (STRCMP(what, "err") == 0)
1794 part = PART_ERR;
1795 else if (STRCMP(what, "out") == 0)
1796 part = PART_OUT;
1797 else if (STRCMP(what, "in") == 0)
1798 part = PART_IN;
1799 else
1800 part = PART_SOCK;
1801 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
1802 rettv->vval.v_number =
1803 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
1804 }
1805}
1806
1807/*
1808 * "ch_getjob()" function
1809 */
1810 static void
1811f_ch_getjob(typval_T *argvars, typval_T *rettv)
1812{
1813 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1814
1815 if (channel != NULL)
1816 {
1817 rettv->v_type = VAR_JOB;
1818 rettv->vval.v_job = channel->ch_job;
1819 if (channel->ch_job != NULL)
1820 ++channel->ch_job->jv_refcount;
1821 }
1822}
1823
1824/*
1825 * "ch_info()" function
1826 */
1827 static void
1828f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
1829{
1830 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1831
1832 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
1833 channel_info(channel, rettv->vval.v_dict);
1834}
1835
1836/*
1837 * "ch_log()" function
1838 */
1839 static void
1840f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
1841{
1842 char_u *msg = get_tv_string(&argvars[0]);
1843 channel_T *channel = NULL;
1844
1845 if (argvars[1].v_type != VAR_UNKNOWN)
1846 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
1847
1848 ch_log(channel, (char *)msg);
1849}
1850
1851/*
1852 * "ch_logfile()" function
1853 */
1854 static void
1855f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
1856{
1857 char_u *fname;
1858 char_u *opt = (char_u *)"";
1859 char_u buf[NUMBUFLEN];
1860
1861 fname = get_tv_string(&argvars[0]);
1862 if (argvars[1].v_type == VAR_STRING)
1863 opt = get_tv_string_buf(&argvars[1], buf);
1864 ch_logfile(fname, opt);
1865}
1866
1867/*
1868 * "ch_open()" function
1869 */
1870 static void
1871f_ch_open(typval_T *argvars, typval_T *rettv)
1872{
1873 rettv->v_type = VAR_CHANNEL;
1874 if (check_restricted() || check_secure())
1875 return;
1876 rettv->vval.v_channel = channel_open_func(argvars);
1877}
1878
1879/*
1880 * "ch_read()" function
1881 */
1882 static void
1883f_ch_read(typval_T *argvars, typval_T *rettv)
1884{
1885 common_channel_read(argvars, rettv, FALSE);
1886}
1887
1888/*
1889 * "ch_readraw()" function
1890 */
1891 static void
1892f_ch_readraw(typval_T *argvars, typval_T *rettv)
1893{
1894 common_channel_read(argvars, rettv, TRUE);
1895}
1896
1897/*
1898 * "ch_evalexpr()" function
1899 */
1900 static void
1901f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
1902{
1903 ch_expr_common(argvars, rettv, TRUE);
1904}
1905
1906/*
1907 * "ch_sendexpr()" function
1908 */
1909 static void
1910f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
1911{
1912 ch_expr_common(argvars, rettv, FALSE);
1913}
1914
1915/*
1916 * "ch_evalraw()" function
1917 */
1918 static void
1919f_ch_evalraw(typval_T *argvars, typval_T *rettv)
1920{
1921 ch_raw_common(argvars, rettv, TRUE);
1922}
1923
1924/*
1925 * "ch_sendraw()" function
1926 */
1927 static void
1928f_ch_sendraw(typval_T *argvars, typval_T *rettv)
1929{
1930 ch_raw_common(argvars, rettv, FALSE);
1931}
1932
1933/*
1934 * "ch_setoptions()" function
1935 */
1936 static void
1937f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
1938{
1939 channel_T *channel;
1940 jobopt_T opt;
1941
1942 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1943 if (channel == NULL)
1944 return;
1945 clear_job_options(&opt);
1946 if (get_job_options(&argvars[1], &opt,
1947 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK)
1948 channel_set_options(channel, &opt);
1949 free_job_options(&opt);
1950}
1951
1952/*
1953 * "ch_status()" function
1954 */
1955 static void
1956f_ch_status(typval_T *argvars, typval_T *rettv)
1957{
1958 channel_T *channel;
1959
1960 /* return an empty string by default */
1961 rettv->v_type = VAR_STRING;
1962 rettv->vval.v_string = NULL;
1963
1964 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
1965 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel));
1966}
1967#endif
1968
1969/*
1970 * "changenr()" function
1971 */
1972 static void
1973f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1974{
1975 rettv->vval.v_number = curbuf->b_u_seq_cur;
1976}
1977
1978/*
1979 * "char2nr(string)" function
1980 */
1981 static void
1982f_char2nr(typval_T *argvars, typval_T *rettv)
1983{
1984#ifdef FEAT_MBYTE
1985 if (has_mbyte)
1986 {
1987 int utf8 = 0;
1988
1989 if (argvars[1].v_type != VAR_UNKNOWN)
1990 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
1991
1992 if (utf8)
1993 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0]));
1994 else
1995 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0]));
1996 }
1997 else
1998#endif
1999 rettv->vval.v_number = get_tv_string(&argvars[0])[0];
2000}
2001
2002/*
2003 * "cindent(lnum)" function
2004 */
2005 static void
2006f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2007{
2008#ifdef FEAT_CINDENT
2009 pos_T pos;
2010 linenr_T lnum;
2011
2012 pos = curwin->w_cursor;
2013 lnum = get_tv_lnum(argvars);
2014 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2015 {
2016 curwin->w_cursor.lnum = lnum;
2017 rettv->vval.v_number = get_c_indent();
2018 curwin->w_cursor = pos;
2019 }
2020 else
2021#endif
2022 rettv->vval.v_number = -1;
2023}
2024
2025/*
2026 * "clearmatches()" function
2027 */
2028 static void
2029f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2030{
2031#ifdef FEAT_SEARCH_EXTRA
2032 clear_matches(curwin);
2033#endif
2034}
2035
2036/*
2037 * "col(string)" function
2038 */
2039 static void
2040f_col(typval_T *argvars, typval_T *rettv)
2041{
2042 colnr_T col = 0;
2043 pos_T *fp;
2044 int fnum = curbuf->b_fnum;
2045
2046 fp = var2fpos(&argvars[0], FALSE, &fnum);
2047 if (fp != NULL && fnum == curbuf->b_fnum)
2048 {
2049 if (fp->col == MAXCOL)
2050 {
2051 /* '> can be MAXCOL, get the length of the line then */
2052 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2053 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2054 else
2055 col = MAXCOL;
2056 }
2057 else
2058 {
2059 col = fp->col + 1;
2060#ifdef FEAT_VIRTUALEDIT
2061 /* col(".") when the cursor is on the NUL at the end of the line
2062 * because of "coladd" can be seen as an extra column. */
2063 if (virtual_active() && fp == &curwin->w_cursor)
2064 {
2065 char_u *p = ml_get_cursor();
2066
2067 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2068 curwin->w_virtcol - curwin->w_cursor.coladd))
2069 {
2070# ifdef FEAT_MBYTE
2071 int l;
2072
2073 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2074 col += l;
2075# else
2076 if (*p != NUL && p[1] == NUL)
2077 ++col;
2078# endif
2079 }
2080 }
2081#endif
2082 }
2083 }
2084 rettv->vval.v_number = col;
2085}
2086
2087#if defined(FEAT_INS_EXPAND)
2088/*
2089 * "complete()" function
2090 */
2091 static void
2092f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2093{
2094 int startcol;
2095
2096 if ((State & INSERT) == 0)
2097 {
2098 EMSG(_("E785: complete() can only be used in Insert mode"));
2099 return;
2100 }
2101
2102 /* Check for undo allowed here, because if something was already inserted
2103 * the line was already saved for undo and this check isn't done. */
2104 if (!undo_allowed())
2105 return;
2106
2107 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2108 {
2109 EMSG(_(e_invarg));
2110 return;
2111 }
2112
2113 startcol = (int)get_tv_number_chk(&argvars[0], NULL);
2114 if (startcol <= 0)
2115 return;
2116
2117 set_completion(startcol - 1, argvars[1].vval.v_list);
2118}
2119
2120/*
2121 * "complete_add()" function
2122 */
2123 static void
2124f_complete_add(typval_T *argvars, typval_T *rettv)
2125{
2126 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2127}
2128
2129/*
2130 * "complete_check()" function
2131 */
2132 static void
2133f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2134{
2135 int saved = RedrawingDisabled;
2136
2137 RedrawingDisabled = 0;
2138 ins_compl_check_keys(0);
2139 rettv->vval.v_number = compl_interrupted;
2140 RedrawingDisabled = saved;
2141}
2142#endif
2143
2144/*
2145 * "confirm(message, buttons[, default [, type]])" function
2146 */
2147 static void
2148f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2149{
2150#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2151 char_u *message;
2152 char_u *buttons = NULL;
2153 char_u buf[NUMBUFLEN];
2154 char_u buf2[NUMBUFLEN];
2155 int def = 1;
2156 int type = VIM_GENERIC;
2157 char_u *typestr;
2158 int error = FALSE;
2159
2160 message = get_tv_string_chk(&argvars[0]);
2161 if (message == NULL)
2162 error = TRUE;
2163 if (argvars[1].v_type != VAR_UNKNOWN)
2164 {
2165 buttons = get_tv_string_buf_chk(&argvars[1], buf);
2166 if (buttons == NULL)
2167 error = TRUE;
2168 if (argvars[2].v_type != VAR_UNKNOWN)
2169 {
2170 def = (int)get_tv_number_chk(&argvars[2], &error);
2171 if (argvars[3].v_type != VAR_UNKNOWN)
2172 {
2173 typestr = get_tv_string_buf_chk(&argvars[3], buf2);
2174 if (typestr == NULL)
2175 error = TRUE;
2176 else
2177 {
2178 switch (TOUPPER_ASC(*typestr))
2179 {
2180 case 'E': type = VIM_ERROR; break;
2181 case 'Q': type = VIM_QUESTION; break;
2182 case 'I': type = VIM_INFO; break;
2183 case 'W': type = VIM_WARNING; break;
2184 case 'G': type = VIM_GENERIC; break;
2185 }
2186 }
2187 }
2188 }
2189 }
2190
2191 if (buttons == NULL || *buttons == NUL)
2192 buttons = (char_u *)_("&Ok");
2193
2194 if (!error)
2195 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2196 def, NULL, FALSE);
2197#endif
2198}
2199
2200/*
2201 * "copy()" function
2202 */
2203 static void
2204f_copy(typval_T *argvars, typval_T *rettv)
2205{
2206 item_copy(&argvars[0], rettv, FALSE, 0);
2207}
2208
2209#ifdef FEAT_FLOAT
2210/*
2211 * "cos()" function
2212 */
2213 static void
2214f_cos(typval_T *argvars, typval_T *rettv)
2215{
2216 float_T f = 0.0;
2217
2218 rettv->v_type = VAR_FLOAT;
2219 if (get_float_arg(argvars, &f) == OK)
2220 rettv->vval.v_float = cos(f);
2221 else
2222 rettv->vval.v_float = 0.0;
2223}
2224
2225/*
2226 * "cosh()" function
2227 */
2228 static void
2229f_cosh(typval_T *argvars, typval_T *rettv)
2230{
2231 float_T f = 0.0;
2232
2233 rettv->v_type = VAR_FLOAT;
2234 if (get_float_arg(argvars, &f) == OK)
2235 rettv->vval.v_float = cosh(f);
2236 else
2237 rettv->vval.v_float = 0.0;
2238}
2239#endif
2240
2241/*
2242 * "count()" function
2243 */
2244 static void
2245f_count(typval_T *argvars, typval_T *rettv)
2246{
2247 long n = 0;
2248 int ic = FALSE;
2249
2250 if (argvars[0].v_type == VAR_LIST)
2251 {
2252 listitem_T *li;
2253 list_T *l;
2254 long idx;
2255
2256 if ((l = argvars[0].vval.v_list) != NULL)
2257 {
2258 li = l->lv_first;
2259 if (argvars[2].v_type != VAR_UNKNOWN)
2260 {
2261 int error = FALSE;
2262
2263 ic = (int)get_tv_number_chk(&argvars[2], &error);
2264 if (argvars[3].v_type != VAR_UNKNOWN)
2265 {
2266 idx = (long)get_tv_number_chk(&argvars[3], &error);
2267 if (!error)
2268 {
2269 li = list_find(l, idx);
2270 if (li == NULL)
2271 EMSGN(_(e_listidx), idx);
2272 }
2273 }
2274 if (error)
2275 li = NULL;
2276 }
2277
2278 for ( ; li != NULL; li = li->li_next)
2279 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2280 ++n;
2281 }
2282 }
2283 else if (argvars[0].v_type == VAR_DICT)
2284 {
2285 int todo;
2286 dict_T *d;
2287 hashitem_T *hi;
2288
2289 if ((d = argvars[0].vval.v_dict) != NULL)
2290 {
2291 int error = FALSE;
2292
2293 if (argvars[2].v_type != VAR_UNKNOWN)
2294 {
2295 ic = (int)get_tv_number_chk(&argvars[2], &error);
2296 if (argvars[3].v_type != VAR_UNKNOWN)
2297 EMSG(_(e_invarg));
2298 }
2299
2300 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2301 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2302 {
2303 if (!HASHITEM_EMPTY(hi))
2304 {
2305 --todo;
2306 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2307 ++n;
2308 }
2309 }
2310 }
2311 }
2312 else
2313 EMSG2(_(e_listdictarg), "count()");
2314 rettv->vval.v_number = n;
2315}
2316
2317/*
2318 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2319 *
2320 * Checks the existence of a cscope connection.
2321 */
2322 static void
2323f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2324{
2325#ifdef FEAT_CSCOPE
2326 int num = 0;
2327 char_u *dbpath = NULL;
2328 char_u *prepend = NULL;
2329 char_u buf[NUMBUFLEN];
2330
2331 if (argvars[0].v_type != VAR_UNKNOWN
2332 && argvars[1].v_type != VAR_UNKNOWN)
2333 {
2334 num = (int)get_tv_number(&argvars[0]);
2335 dbpath = get_tv_string(&argvars[1]);
2336 if (argvars[2].v_type != VAR_UNKNOWN)
2337 prepend = get_tv_string_buf(&argvars[2], buf);
2338 }
2339
2340 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2341#endif
2342}
2343
2344/*
2345 * "cursor(lnum, col)" function, or
2346 * "cursor(list)"
2347 *
2348 * Moves the cursor to the specified line and column.
2349 * Returns 0 when the position could be set, -1 otherwise.
2350 */
2351 static void
2352f_cursor(typval_T *argvars, typval_T *rettv)
2353{
2354 long line, col;
2355#ifdef FEAT_VIRTUALEDIT
2356 long coladd = 0;
2357#endif
2358 int set_curswant = TRUE;
2359
2360 rettv->vval.v_number = -1;
2361 if (argvars[1].v_type == VAR_UNKNOWN)
2362 {
2363 pos_T pos;
2364 colnr_T curswant = -1;
2365
2366 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2367 {
2368 EMSG(_(e_invarg));
2369 return;
2370 }
2371 line = pos.lnum;
2372 col = pos.col;
2373#ifdef FEAT_VIRTUALEDIT
2374 coladd = pos.coladd;
2375#endif
2376 if (curswant >= 0)
2377 {
2378 curwin->w_curswant = curswant - 1;
2379 set_curswant = FALSE;
2380 }
2381 }
2382 else
2383 {
2384 line = get_tv_lnum(argvars);
2385 col = (long)get_tv_number_chk(&argvars[1], NULL);
2386#ifdef FEAT_VIRTUALEDIT
2387 if (argvars[2].v_type != VAR_UNKNOWN)
2388 coladd = (long)get_tv_number_chk(&argvars[2], NULL);
2389#endif
2390 }
2391 if (line < 0 || col < 0
2392#ifdef FEAT_VIRTUALEDIT
2393 || coladd < 0
2394#endif
2395 )
2396 return; /* type error; errmsg already given */
2397 if (line > 0)
2398 curwin->w_cursor.lnum = line;
2399 if (col > 0)
2400 curwin->w_cursor.col = col - 1;
2401#ifdef FEAT_VIRTUALEDIT
2402 curwin->w_cursor.coladd = coladd;
2403#endif
2404
2405 /* Make sure the cursor is in a valid position. */
2406 check_cursor();
2407#ifdef FEAT_MBYTE
2408 /* Correct cursor for multi-byte character. */
2409 if (has_mbyte)
2410 mb_adjust_cursor();
2411#endif
2412
2413 curwin->w_set_curswant = set_curswant;
2414 rettv->vval.v_number = 0;
2415}
2416
2417/*
2418 * "deepcopy()" function
2419 */
2420 static void
2421f_deepcopy(typval_T *argvars, typval_T *rettv)
2422{
2423 int noref = 0;
2424 int copyID;
2425
2426 if (argvars[1].v_type != VAR_UNKNOWN)
2427 noref = (int)get_tv_number_chk(&argvars[1], NULL);
2428 if (noref < 0 || noref > 1)
2429 EMSG(_(e_invarg));
2430 else
2431 {
2432 copyID = get_copyID();
2433 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2434 }
2435}
2436
2437/*
2438 * "delete()" function
2439 */
2440 static void
2441f_delete(typval_T *argvars, typval_T *rettv)
2442{
2443 char_u nbuf[NUMBUFLEN];
2444 char_u *name;
2445 char_u *flags;
2446
2447 rettv->vval.v_number = -1;
2448 if (check_restricted() || check_secure())
2449 return;
2450
2451 name = get_tv_string(&argvars[0]);
2452 if (name == NULL || *name == NUL)
2453 {
2454 EMSG(_(e_invarg));
2455 return;
2456 }
2457
2458 if (argvars[1].v_type != VAR_UNKNOWN)
2459 flags = get_tv_string_buf(&argvars[1], nbuf);
2460 else
2461 flags = (char_u *)"";
2462
2463 if (*flags == NUL)
2464 /* delete a file */
2465 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2466 else if (STRCMP(flags, "d") == 0)
2467 /* delete an empty directory */
2468 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2469 else if (STRCMP(flags, "rf") == 0)
2470 /* delete a directory recursively */
2471 rettv->vval.v_number = delete_recursive(name);
2472 else
2473 EMSG2(_(e_invexpr2), flags);
2474}
2475
2476/*
2477 * "did_filetype()" function
2478 */
2479 static void
2480f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2481{
2482#ifdef FEAT_AUTOCMD
2483 rettv->vval.v_number = did_filetype;
2484#endif
2485}
2486
2487/*
2488 * "diff_filler()" function
2489 */
2490 static void
2491f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2492{
2493#ifdef FEAT_DIFF
2494 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars));
2495#endif
2496}
2497
2498/*
2499 * "diff_hlID()" function
2500 */
2501 static void
2502f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2503{
2504#ifdef FEAT_DIFF
2505 linenr_T lnum = get_tv_lnum(argvars);
2506 static linenr_T prev_lnum = 0;
2507 static int changedtick = 0;
2508 static int fnum = 0;
2509 static int change_start = 0;
2510 static int change_end = 0;
2511 static hlf_T hlID = (hlf_T)0;
2512 int filler_lines;
2513 int col;
2514
2515 if (lnum < 0) /* ignore type error in {lnum} arg */
2516 lnum = 0;
2517 if (lnum != prev_lnum
2518 || changedtick != curbuf->b_changedtick
2519 || fnum != curbuf->b_fnum)
2520 {
2521 /* New line, buffer, change: need to get the values. */
2522 filler_lines = diff_check(curwin, lnum);
2523 if (filler_lines < 0)
2524 {
2525 if (filler_lines == -1)
2526 {
2527 change_start = MAXCOL;
2528 change_end = -1;
2529 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2530 hlID = HLF_ADD; /* added line */
2531 else
2532 hlID = HLF_CHD; /* changed line */
2533 }
2534 else
2535 hlID = HLF_ADD; /* added line */
2536 }
2537 else
2538 hlID = (hlf_T)0;
2539 prev_lnum = lnum;
2540 changedtick = curbuf->b_changedtick;
2541 fnum = curbuf->b_fnum;
2542 }
2543
2544 if (hlID == HLF_CHD || hlID == HLF_TXD)
2545 {
2546 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */
2547 if (col >= change_start && col <= change_end)
2548 hlID = HLF_TXD; /* changed text */
2549 else
2550 hlID = HLF_CHD; /* changed line */
2551 }
2552 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2553#endif
2554}
2555
2556/*
2557 * "empty({expr})" function
2558 */
2559 static void
2560f_empty(typval_T *argvars, typval_T *rettv)
2561{
2562 int n = FALSE;
2563
2564 switch (argvars[0].v_type)
2565 {
2566 case VAR_STRING:
2567 case VAR_FUNC:
2568 n = argvars[0].vval.v_string == NULL
2569 || *argvars[0].vval.v_string == NUL;
2570 break;
2571 case VAR_PARTIAL:
2572 n = FALSE;
2573 break;
2574 case VAR_NUMBER:
2575 n = argvars[0].vval.v_number == 0;
2576 break;
2577 case VAR_FLOAT:
2578#ifdef FEAT_FLOAT
2579 n = argvars[0].vval.v_float == 0.0;
2580 break;
2581#endif
2582 case VAR_LIST:
2583 n = argvars[0].vval.v_list == NULL
2584 || argvars[0].vval.v_list->lv_first == NULL;
2585 break;
2586 case VAR_DICT:
2587 n = argvars[0].vval.v_dict == NULL
2588 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2589 break;
2590 case VAR_SPECIAL:
2591 n = argvars[0].vval.v_number != VVAL_TRUE;
2592 break;
2593
2594 case VAR_JOB:
2595#ifdef FEAT_JOB_CHANNEL
2596 n = argvars[0].vval.v_job == NULL
2597 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2598 break;
2599#endif
2600 case VAR_CHANNEL:
2601#ifdef FEAT_JOB_CHANNEL
2602 n = argvars[0].vval.v_channel == NULL
2603 || !channel_is_open(argvars[0].vval.v_channel);
2604 break;
2605#endif
2606 case VAR_UNKNOWN:
2607 EMSG2(_(e_intern2), "f_empty(UNKNOWN)");
2608 n = TRUE;
2609 break;
2610 }
2611
2612 rettv->vval.v_number = n;
2613}
2614
2615/*
2616 * "escape({string}, {chars})" function
2617 */
2618 static void
2619f_escape(typval_T *argvars, typval_T *rettv)
2620{
2621 char_u buf[NUMBUFLEN];
2622
2623 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]),
2624 get_tv_string_buf(&argvars[1], buf));
2625 rettv->v_type = VAR_STRING;
2626}
2627
2628/*
2629 * "eval()" function
2630 */
2631 static void
2632f_eval(typval_T *argvars, typval_T *rettv)
2633{
2634 char_u *s, *p;
2635
2636 s = get_tv_string_chk(&argvars[0]);
2637 if (s != NULL)
2638 s = skipwhite(s);
2639
2640 p = s;
2641 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2642 {
2643 if (p != NULL && !aborting())
2644 EMSG2(_(e_invexpr2), p);
2645 need_clr_eos = FALSE;
2646 rettv->v_type = VAR_NUMBER;
2647 rettv->vval.v_number = 0;
2648 }
2649 else if (*s != NUL)
2650 EMSG(_(e_trailing));
2651}
2652
2653/*
2654 * "eventhandler()" function
2655 */
2656 static void
2657f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2658{
2659 rettv->vval.v_number = vgetc_busy;
2660}
2661
2662/*
2663 * "executable()" function
2664 */
2665 static void
2666f_executable(typval_T *argvars, typval_T *rettv)
2667{
2668 char_u *name = get_tv_string(&argvars[0]);
2669
2670 /* Check in $PATH and also check directly if there is a directory name. */
2671 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
2672 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
2673}
2674
2675static garray_T redir_execute_ga;
2676
2677/*
2678 * Append "value[value_len]" to the execute() output.
2679 */
2680 void
2681execute_redir_str(char_u *value, int value_len)
2682{
2683 int len;
2684
2685 if (value_len == -1)
2686 len = (int)STRLEN(value); /* Append the entire string */
2687 else
2688 len = value_len; /* Append only "value_len" characters */
2689 if (ga_grow(&redir_execute_ga, len) == OK)
2690 {
2691 mch_memmove((char *)redir_execute_ga.ga_data
2692 + redir_execute_ga.ga_len, value, len);
2693 redir_execute_ga.ga_len += len;
2694 }
2695}
2696
2697/*
2698 * Get next line from a list.
2699 * Called by do_cmdline() to get the next line.
2700 * Returns allocated string, or NULL for end of function.
2701 */
2702
2703 static char_u *
2704get_list_line(
2705 int c UNUSED,
2706 void *cookie,
2707 int indent UNUSED)
2708{
2709 listitem_T **p = (listitem_T **)cookie;
2710 listitem_T *item = *p;
2711 char_u buf[NUMBUFLEN];
2712 char_u *s;
2713
2714 if (item == NULL)
2715 return NULL;
2716 s = get_tv_string_buf_chk(&item->li_tv, buf);
2717 *p = item->li_next;
2718 return s == NULL ? NULL : vim_strsave(s);
2719}
2720
2721/*
2722 * "execute()" function
2723 */
2724 static void
2725f_execute(typval_T *argvars, typval_T *rettv)
2726{
2727 char_u *cmd = NULL;
2728 list_T *list = NULL;
2729 int save_msg_silent = msg_silent;
2730 int save_emsg_silent = emsg_silent;
2731 int save_emsg_noredir = emsg_noredir;
2732 int save_redir_execute = redir_execute;
2733 garray_T save_ga;
2734
2735 rettv->vval.v_string = NULL;
2736 rettv->v_type = VAR_STRING;
2737
2738 if (argvars[0].v_type == VAR_LIST)
2739 {
2740 list = argvars[0].vval.v_list;
2741 if (list == NULL || list->lv_first == NULL)
2742 /* empty list, no commands, empty output */
2743 return;
2744 ++list->lv_refcount;
2745 }
2746 else
2747 {
2748 cmd = get_tv_string_chk(&argvars[0]);
2749 if (cmd == NULL)
2750 return;
2751 }
2752
2753 if (argvars[1].v_type != VAR_UNKNOWN)
2754 {
2755 char_u buf[NUMBUFLEN];
2756 char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
2757
2758 if (s == NULL)
2759 return;
2760 if (STRNCMP(s, "silent", 6) == 0)
2761 ++msg_silent;
2762 if (STRCMP(s, "silent!") == 0)
2763 {
2764 emsg_silent = TRUE;
2765 emsg_noredir = TRUE;
2766 }
2767 }
2768 else
2769 ++msg_silent;
2770
2771 if (redir_execute)
2772 save_ga = redir_execute_ga;
2773 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2774 redir_execute = TRUE;
2775
2776 if (cmd != NULL)
2777 do_cmdline_cmd(cmd);
2778 else
2779 {
2780 listitem_T *item = list->lv_first;
2781
2782 do_cmdline(NULL, get_list_line, (void *)&item,
2783 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2784 --list->lv_refcount;
2785 }
2786
2787 rettv->vval.v_string = redir_execute_ga.ga_data;
2788 msg_silent = save_msg_silent;
2789 emsg_silent = save_emsg_silent;
2790 emsg_noredir = save_emsg_noredir;
2791
2792 redir_execute = save_redir_execute;
2793 if (redir_execute)
2794 redir_execute_ga = save_ga;
2795
2796 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the
2797 * line. Put it back in the first column. */
2798 msg_col = 0;
2799}
2800
2801/*
2802 * "exepath()" function
2803 */
2804 static void
2805f_exepath(typval_T *argvars, typval_T *rettv)
2806{
2807 char_u *p = NULL;
2808
2809 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE);
2810 rettv->v_type = VAR_STRING;
2811 rettv->vval.v_string = p;
2812}
2813
2814/*
2815 * "exists()" function
2816 */
2817 static void
2818f_exists(typval_T *argvars, typval_T *rettv)
2819{
2820 char_u *p;
2821 char_u *name;
2822 int n = FALSE;
2823 int len = 0;
2824
2825 p = get_tv_string(&argvars[0]);
2826 if (*p == '$') /* environment variable */
2827 {
2828 /* first try "normal" environment variables (fast) */
2829 if (mch_getenv(p + 1) != NULL)
2830 n = TRUE;
2831 else
2832 {
2833 /* try expanding things like $VIM and ${HOME} */
2834 p = expand_env_save(p);
2835 if (p != NULL && *p != '$')
2836 n = TRUE;
2837 vim_free(p);
2838 }
2839 }
2840 else if (*p == '&' || *p == '+') /* option */
2841 {
2842 n = (get_option_tv(&p, NULL, TRUE) == OK);
2843 if (*skipwhite(p) != NUL)
2844 n = FALSE; /* trailing garbage */
2845 }
2846 else if (*p == '*') /* internal or user defined function */
2847 {
2848 n = function_exists(p + 1);
2849 }
2850 else if (*p == ':')
2851 {
2852 n = cmd_exists(p + 1);
2853 }
2854 else if (*p == '#')
2855 {
2856#ifdef FEAT_AUTOCMD
2857 if (p[1] == '#')
2858 n = autocmd_supported(p + 2);
2859 else
2860 n = au_exists(p + 1);
2861#endif
2862 }
2863 else /* internal variable */
2864 {
2865 char_u *tofree;
2866 typval_T tv;
2867
2868 /* get_name_len() takes care of expanding curly braces */
2869 name = p;
2870 len = get_name_len(&p, &tofree, TRUE, FALSE);
2871 if (len > 0)
2872 {
2873 if (tofree != NULL)
2874 name = tofree;
2875 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
2876 if (n)
2877 {
2878 /* handle d.key, l[idx], f(expr) */
2879 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
2880 if (n)
2881 clear_tv(&tv);
2882 }
2883 }
2884 if (*p != NUL)
2885 n = FALSE;
2886
2887 vim_free(tofree);
2888 }
2889
2890 rettv->vval.v_number = n;
2891}
2892
2893#ifdef FEAT_FLOAT
2894/*
2895 * "exp()" function
2896 */
2897 static void
2898f_exp(typval_T *argvars, typval_T *rettv)
2899{
2900 float_T f = 0.0;
2901
2902 rettv->v_type = VAR_FLOAT;
2903 if (get_float_arg(argvars, &f) == OK)
2904 rettv->vval.v_float = exp(f);
2905 else
2906 rettv->vval.v_float = 0.0;
2907}
2908#endif
2909
2910/*
2911 * "expand()" function
2912 */
2913 static void
2914f_expand(typval_T *argvars, typval_T *rettv)
2915{
2916 char_u *s;
2917 int len;
2918 char_u *errormsg;
2919 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2920 expand_T xpc;
2921 int error = FALSE;
2922 char_u *result;
2923
2924 rettv->v_type = VAR_STRING;
2925 if (argvars[1].v_type != VAR_UNKNOWN
2926 && argvars[2].v_type != VAR_UNKNOWN
2927 && get_tv_number_chk(&argvars[2], &error)
2928 && !error)
2929 {
2930 rettv->v_type = VAR_LIST;
2931 rettv->vval.v_list = NULL;
2932 }
2933
2934 s = get_tv_string(&argvars[0]);
2935 if (*s == '%' || *s == '#' || *s == '<')
2936 {
2937 ++emsg_off;
2938 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2939 --emsg_off;
2940 if (rettv->v_type == VAR_LIST)
2941 {
2942 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2943 list_append_string(rettv->vval.v_list, result, -1);
2944 else
2945 vim_free(result);
2946 }
2947 else
2948 rettv->vval.v_string = result;
2949 }
2950 else
2951 {
2952 /* When the optional second argument is non-zero, don't remove matches
2953 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2954 if (argvars[1].v_type != VAR_UNKNOWN
2955 && get_tv_number_chk(&argvars[1], &error))
2956 options |= WILD_KEEP_ALL;
2957 if (!error)
2958 {
2959 ExpandInit(&xpc);
2960 xpc.xp_context = EXPAND_FILES;
2961 if (p_wic)
2962 options += WILD_ICASE;
2963 if (rettv->v_type == VAR_STRING)
2964 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2965 options, WILD_ALL);
2966 else if (rettv_list_alloc(rettv) != FAIL)
2967 {
2968 int i;
2969
2970 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2971 for (i = 0; i < xpc.xp_numfiles; i++)
2972 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2973 ExpandCleanup(&xpc);
2974 }
2975 }
2976 else
2977 rettv->vval.v_string = NULL;
2978 }
2979}
2980
2981/*
2982 * "extend(list, list [, idx])" function
2983 * "extend(dict, dict [, action])" function
2984 */
2985 static void
2986f_extend(typval_T *argvars, typval_T *rettv)
2987{
2988 char_u *arg_errmsg = (char_u *)N_("extend() argument");
2989
2990 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
2991 {
2992 list_T *l1, *l2;
2993 listitem_T *item;
2994 long before;
2995 int error = FALSE;
2996
2997 l1 = argvars[0].vval.v_list;
2998 l2 = argvars[1].vval.v_list;
2999 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE)
3000 && l2 != NULL)
3001 {
3002 if (argvars[2].v_type != VAR_UNKNOWN)
3003 {
3004 before = (long)get_tv_number_chk(&argvars[2], &error);
3005 if (error)
3006 return; /* type error; errmsg already given */
3007
3008 if (before == l1->lv_len)
3009 item = NULL;
3010 else
3011 {
3012 item = list_find(l1, before);
3013 if (item == NULL)
3014 {
3015 EMSGN(_(e_listidx), before);
3016 return;
3017 }
3018 }
3019 }
3020 else
3021 item = NULL;
3022 list_extend(l1, l2, item);
3023
3024 copy_tv(&argvars[0], rettv);
3025 }
3026 }
3027 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3028 {
3029 dict_T *d1, *d2;
3030 char_u *action;
3031 int i;
3032
3033 d1 = argvars[0].vval.v_dict;
3034 d2 = argvars[1].vval.v_dict;
3035 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
3036 && d2 != NULL)
3037 {
3038 /* Check the third argument. */
3039 if (argvars[2].v_type != VAR_UNKNOWN)
3040 {
3041 static char *(av[]) = {"keep", "force", "error"};
3042
3043 action = get_tv_string_chk(&argvars[2]);
3044 if (action == NULL)
3045 return; /* type error; errmsg already given */
3046 for (i = 0; i < 3; ++i)
3047 if (STRCMP(action, av[i]) == 0)
3048 break;
3049 if (i == 3)
3050 {
3051 EMSG2(_(e_invarg2), action);
3052 return;
3053 }
3054 }
3055 else
3056 action = (char_u *)"force";
3057
3058 dict_extend(d1, d2, action);
3059
3060 copy_tv(&argvars[0], rettv);
3061 }
3062 }
3063 else
3064 EMSG2(_(e_listdictarg), "extend()");
3065}
3066
3067/*
3068 * "feedkeys()" function
3069 */
3070 static void
3071f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3072{
3073 int remap = TRUE;
3074 int insert = FALSE;
3075 char_u *keys, *flags;
3076 char_u nbuf[NUMBUFLEN];
3077 int typed = FALSE;
3078 int execute = FALSE;
3079 int dangerous = FALSE;
3080 char_u *keys_esc;
3081
3082 /* This is not allowed in the sandbox. If the commands would still be
3083 * executed in the sandbox it would be OK, but it probably happens later,
3084 * when "sandbox" is no longer set. */
3085 if (check_secure())
3086 return;
3087
3088 keys = get_tv_string(&argvars[0]);
3089
3090 if (argvars[1].v_type != VAR_UNKNOWN)
3091 {
3092 flags = get_tv_string_buf(&argvars[1], nbuf);
3093 for ( ; *flags != NUL; ++flags)
3094 {
3095 switch (*flags)
3096 {
3097 case 'n': remap = FALSE; break;
3098 case 'm': remap = TRUE; break;
3099 case 't': typed = TRUE; break;
3100 case 'i': insert = TRUE; break;
3101 case 'x': execute = TRUE; break;
3102 case '!': dangerous = TRUE; break;
3103 }
3104 }
3105 }
3106
3107 if (*keys != NUL || execute)
3108 {
3109 /* Need to escape K_SPECIAL and CSI before putting the string in the
3110 * typeahead buffer. */
3111 keys_esc = vim_strsave_escape_csi(keys);
3112 if (keys_esc != NULL)
3113 {
3114 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
3115 insert ? 0 : typebuf.tb_len, !typed, FALSE);
3116 vim_free(keys_esc);
3117 if (vgetc_busy)
3118 typebuf_was_filled = TRUE;
3119 if (execute)
3120 {
3121 int save_msg_scroll = msg_scroll;
3122
3123 /* Avoid a 1 second delay when the keys start Insert mode. */
3124 msg_scroll = FALSE;
3125
3126 if (!dangerous)
3127 ++ex_normal_busy;
3128 exec_normal(TRUE);
3129 if (!dangerous)
3130 --ex_normal_busy;
3131 msg_scroll |= save_msg_scroll;
3132 }
3133 }
3134 }
3135}
3136
3137/*
3138 * "filereadable()" function
3139 */
3140 static void
3141f_filereadable(typval_T *argvars, typval_T *rettv)
3142{
3143 int fd;
3144 char_u *p;
3145 int n;
3146
3147#ifndef O_NONBLOCK
3148# define O_NONBLOCK 0
3149#endif
3150 p = get_tv_string(&argvars[0]);
3151 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3152 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3153 {
3154 n = TRUE;
3155 close(fd);
3156 }
3157 else
3158 n = FALSE;
3159
3160 rettv->vval.v_number = n;
3161}
3162
3163/*
3164 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3165 * rights to write into.
3166 */
3167 static void
3168f_filewritable(typval_T *argvars, typval_T *rettv)
3169{
3170 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0]));
3171}
3172
3173 static void
3174findfilendir(
3175 typval_T *argvars UNUSED,
3176 typval_T *rettv,
3177 int find_what UNUSED)
3178{
3179#ifdef FEAT_SEARCHPATH
3180 char_u *fname;
3181 char_u *fresult = NULL;
3182 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3183 char_u *p;
3184 char_u pathbuf[NUMBUFLEN];
3185 int count = 1;
3186 int first = TRUE;
3187 int error = FALSE;
3188#endif
3189
3190 rettv->vval.v_string = NULL;
3191 rettv->v_type = VAR_STRING;
3192
3193#ifdef FEAT_SEARCHPATH
3194 fname = get_tv_string(&argvars[0]);
3195
3196 if (argvars[1].v_type != VAR_UNKNOWN)
3197 {
3198 p = get_tv_string_buf_chk(&argvars[1], pathbuf);
3199 if (p == NULL)
3200 error = TRUE;
3201 else
3202 {
3203 if (*p != NUL)
3204 path = p;
3205
3206 if (argvars[2].v_type != VAR_UNKNOWN)
3207 count = (int)get_tv_number_chk(&argvars[2], &error);
3208 }
3209 }
3210
3211 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3212 error = TRUE;
3213
3214 if (*fname != NUL && !error)
3215 {
3216 do
3217 {
3218 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3219 vim_free(fresult);
3220 fresult = find_file_in_path_option(first ? fname : NULL,
3221 first ? (int)STRLEN(fname) : 0,
3222 0, first, path,
3223 find_what,
3224 curbuf->b_ffname,
3225 find_what == FINDFILE_DIR
3226 ? (char_u *)"" : curbuf->b_p_sua);
3227 first = FALSE;
3228
3229 if (fresult != NULL && rettv->v_type == VAR_LIST)
3230 list_append_string(rettv->vval.v_list, fresult, -1);
3231
3232 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3233 }
3234
3235 if (rettv->v_type == VAR_STRING)
3236 rettv->vval.v_string = fresult;
3237#endif
3238}
3239
3240/*
3241 * "filter()" function
3242 */
3243 static void
3244f_filter(typval_T *argvars, typval_T *rettv)
3245{
3246 filter_map(argvars, rettv, FALSE);
3247}
3248
3249/*
3250 * "finddir({fname}[, {path}[, {count}]])" function
3251 */
3252 static void
3253f_finddir(typval_T *argvars, typval_T *rettv)
3254{
3255 findfilendir(argvars, rettv, FINDFILE_DIR);
3256}
3257
3258/*
3259 * "findfile({fname}[, {path}[, {count}]])" function
3260 */
3261 static void
3262f_findfile(typval_T *argvars, typval_T *rettv)
3263{
3264 findfilendir(argvars, rettv, FINDFILE_FILE);
3265}
3266
3267#ifdef FEAT_FLOAT
3268/*
3269 * "float2nr({float})" function
3270 */
3271 static void
3272f_float2nr(typval_T *argvars, typval_T *rettv)
3273{
3274 float_T f = 0.0;
3275
3276 if (get_float_arg(argvars, &f) == OK)
3277 {
3278# ifdef FEAT_NUM64
3279 if (f < -0x7fffffffffffffff)
3280 rettv->vval.v_number = -0x7fffffffffffffff;
3281 else if (f > 0x7fffffffffffffff)
3282 rettv->vval.v_number = 0x7fffffffffffffff;
3283 else
3284 rettv->vval.v_number = (varnumber_T)f;
3285# else
3286 if (f < -0x7fffffff)
3287 rettv->vval.v_number = -0x7fffffff;
3288 else if (f > 0x7fffffff)
3289 rettv->vval.v_number = 0x7fffffff;
3290 else
3291 rettv->vval.v_number = (varnumber_T)f;
3292# endif
3293 }
3294}
3295
3296/*
3297 * "floor({float})" function
3298 */
3299 static void
3300f_floor(typval_T *argvars, typval_T *rettv)
3301{
3302 float_T f = 0.0;
3303
3304 rettv->v_type = VAR_FLOAT;
3305 if (get_float_arg(argvars, &f) == OK)
3306 rettv->vval.v_float = floor(f);
3307 else
3308 rettv->vval.v_float = 0.0;
3309}
3310
3311/*
3312 * "fmod()" function
3313 */
3314 static void
3315f_fmod(typval_T *argvars, typval_T *rettv)
3316{
3317 float_T fx = 0.0, fy = 0.0;
3318
3319 rettv->v_type = VAR_FLOAT;
3320 if (get_float_arg(argvars, &fx) == OK
3321 && get_float_arg(&argvars[1], &fy) == OK)
3322 rettv->vval.v_float = fmod(fx, fy);
3323 else
3324 rettv->vval.v_float = 0.0;
3325}
3326#endif
3327
3328/*
3329 * "fnameescape({string})" function
3330 */
3331 static void
3332f_fnameescape(typval_T *argvars, typval_T *rettv)
3333{
3334 rettv->vval.v_string = vim_strsave_fnameescape(
3335 get_tv_string(&argvars[0]), FALSE);
3336 rettv->v_type = VAR_STRING;
3337}
3338
3339/*
3340 * "fnamemodify({fname}, {mods})" function
3341 */
3342 static void
3343f_fnamemodify(typval_T *argvars, typval_T *rettv)
3344{
3345 char_u *fname;
3346 char_u *mods;
3347 int usedlen = 0;
3348 int len;
3349 char_u *fbuf = NULL;
3350 char_u buf[NUMBUFLEN];
3351
3352 fname = get_tv_string_chk(&argvars[0]);
3353 mods = get_tv_string_buf_chk(&argvars[1], buf);
3354 if (fname == NULL || mods == NULL)
3355 fname = NULL;
3356 else
3357 {
3358 len = (int)STRLEN(fname);
3359 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
3360 }
3361
3362 rettv->v_type = VAR_STRING;
3363 if (fname == NULL)
3364 rettv->vval.v_string = NULL;
3365 else
3366 rettv->vval.v_string = vim_strnsave(fname, len);
3367 vim_free(fbuf);
3368}
3369
3370static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end);
3371
3372/*
3373 * "foldclosed()" function
3374 */
3375 static void
3376foldclosed_both(
3377 typval_T *argvars UNUSED,
3378 typval_T *rettv,
3379 int end UNUSED)
3380{
3381#ifdef FEAT_FOLDING
3382 linenr_T lnum;
3383 linenr_T first, last;
3384
3385 lnum = get_tv_lnum(argvars);
3386 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3387 {
3388 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3389 {
3390 if (end)
3391 rettv->vval.v_number = (varnumber_T)last;
3392 else
3393 rettv->vval.v_number = (varnumber_T)first;
3394 return;
3395 }
3396 }
3397#endif
3398 rettv->vval.v_number = -1;
3399}
3400
3401/*
3402 * "foldclosed()" function
3403 */
3404 static void
3405f_foldclosed(typval_T *argvars, typval_T *rettv)
3406{
3407 foldclosed_both(argvars, rettv, FALSE);
3408}
3409
3410/*
3411 * "foldclosedend()" function
3412 */
3413 static void
3414f_foldclosedend(typval_T *argvars, typval_T *rettv)
3415{
3416 foldclosed_both(argvars, rettv, TRUE);
3417}
3418
3419/*
3420 * "foldlevel()" function
3421 */
3422 static void
3423f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3424{
3425#ifdef FEAT_FOLDING
3426 linenr_T lnum;
3427
3428 lnum = get_tv_lnum(argvars);
3429 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3430 rettv->vval.v_number = foldLevel(lnum);
3431#endif
3432}
3433
3434/*
3435 * "foldtext()" function
3436 */
3437 static void
3438f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3439{
3440#ifdef FEAT_FOLDING
3441 linenr_T foldstart;
3442 linenr_T foldend;
3443 char_u *dashes;
3444 linenr_T lnum;
3445 char_u *s;
3446 char_u *r;
3447 int len;
3448 char *txt;
3449#endif
3450
3451 rettv->v_type = VAR_STRING;
3452 rettv->vval.v_string = NULL;
3453#ifdef FEAT_FOLDING
3454 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3455 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3456 dashes = get_vim_var_str(VV_FOLDDASHES);
3457 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3458 && dashes != NULL)
3459 {
3460 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003461 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003462 if (!linewhite(lnum))
3463 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464
3465 /* Find interesting text in this line. */
3466 s = skipwhite(ml_get(lnum));
3467 /* skip C comment-start */
3468 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3469 {
3470 s = skipwhite(s + 2);
3471 if (*skipwhite(s) == NUL
3472 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3473 {
3474 s = skipwhite(ml_get(lnum + 1));
3475 if (*s == '*')
3476 s = skipwhite(s + 1);
3477 }
3478 }
3479 txt = _("+-%s%3ld lines: ");
3480 r = alloc((unsigned)(STRLEN(txt)
3481 + STRLEN(dashes) /* for %s */
3482 + 20 /* for %3ld */
3483 + STRLEN(s))); /* concatenated */
3484 if (r != NULL)
3485 {
3486 sprintf((char *)r, txt, dashes, (long)(foldend - foldstart + 1));
3487 len = (int)STRLEN(r);
3488 STRCAT(r, s);
3489 /* remove 'foldmarker' and 'commentstring' */
3490 foldtext_cleanup(r + len);
3491 rettv->vval.v_string = r;
3492 }
3493 }
3494#endif
3495}
3496
3497/*
3498 * "foldtextresult(lnum)" function
3499 */
3500 static void
3501f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3502{
3503#ifdef FEAT_FOLDING
3504 linenr_T lnum;
3505 char_u *text;
3506 char_u buf[51];
3507 foldinfo_T foldinfo;
3508 int fold_count;
3509#endif
3510
3511 rettv->v_type = VAR_STRING;
3512 rettv->vval.v_string = NULL;
3513#ifdef FEAT_FOLDING
3514 lnum = get_tv_lnum(argvars);
3515 /* treat illegal types and illegal string values for {lnum} the same */
3516 if (lnum < 0)
3517 lnum = 0;
3518 fold_count = foldedCount(curwin, lnum, &foldinfo);
3519 if (fold_count > 0)
3520 {
3521 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3522 &foldinfo, buf);
3523 if (text == buf)
3524 text = vim_strsave(text);
3525 rettv->vval.v_string = text;
3526 }
3527#endif
3528}
3529
3530/*
3531 * "foreground()" function
3532 */
3533 static void
3534f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3535{
3536#ifdef FEAT_GUI
3537 if (gui.in_use)
3538 gui_mch_set_foreground();
3539#else
3540# ifdef WIN32
3541 win32_set_foreground();
3542# endif
3543#endif
3544}
3545
3546/*
3547 * "function()" function
3548 */
3549 static void
3550f_function(typval_T *argvars, typval_T *rettv)
3551{
3552 char_u *s;
3553 char_u *name;
3554 int use_string = FALSE;
3555 partial_T *arg_pt = NULL;
3556
3557 if (argvars[0].v_type == VAR_FUNC)
3558 {
3559 /* function(MyFunc, [arg], dict) */
3560 s = argvars[0].vval.v_string;
3561 }
3562 else if (argvars[0].v_type == VAR_PARTIAL
3563 && argvars[0].vval.v_partial != NULL)
3564 {
3565 /* function(dict.MyFunc, [arg]) */
3566 arg_pt = argvars[0].vval.v_partial;
3567 s = arg_pt->pt_name;
3568 }
3569 else
3570 {
3571 /* function('MyFunc', [arg], dict) */
3572 s = get_tv_string(&argvars[0]);
3573 use_string = TRUE;
3574 }
3575
3576 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)))
3577 EMSG2(_(e_invarg2), s);
3578 /* Don't check an autoload name for existence here. */
3579 else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
3580 && !function_exists(s))
3581 EMSG2(_("E700: Unknown function: %s"), s);
3582 else
3583 {
3584 int dict_idx = 0;
3585 int arg_idx = 0;
3586 list_T *list = NULL;
3587
3588 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3589 {
3590 char sid_buf[25];
3591 int off = *s == 's' ? 2 : 5;
3592
3593 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3594 * also be called from another script. Using trans_function_name()
3595 * would also work, but some plugins depend on the name being
3596 * printable text. */
3597 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
3598 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
3599 if (name != NULL)
3600 {
3601 STRCPY(name, sid_buf);
3602 STRCAT(name, s + off);
3603 }
3604 }
3605 else
3606 name = vim_strsave(s);
3607
3608 if (argvars[1].v_type != VAR_UNKNOWN)
3609 {
3610 if (argvars[2].v_type != VAR_UNKNOWN)
3611 {
3612 /* function(name, [args], dict) */
3613 arg_idx = 1;
3614 dict_idx = 2;
3615 }
3616 else if (argvars[1].v_type == VAR_DICT)
3617 /* function(name, dict) */
3618 dict_idx = 1;
3619 else
3620 /* function(name, [args]) */
3621 arg_idx = 1;
3622 if (dict_idx > 0)
3623 {
3624 if (argvars[dict_idx].v_type != VAR_DICT)
3625 {
3626 EMSG(_("E922: expected a dict"));
3627 vim_free(name);
3628 return;
3629 }
3630 if (argvars[dict_idx].vval.v_dict == NULL)
3631 dict_idx = 0;
3632 }
3633 if (arg_idx > 0)
3634 {
3635 if (argvars[arg_idx].v_type != VAR_LIST)
3636 {
3637 EMSG(_("E923: Second argument of function() must be a list or a dict"));
3638 vim_free(name);
3639 return;
3640 }
3641 list = argvars[arg_idx].vval.v_list;
3642 if (list == NULL || list->lv_len == 0)
3643 arg_idx = 0;
3644 }
3645 }
3646 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL)
3647 {
3648 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
3649
3650 /* result is a VAR_PARTIAL */
3651 if (pt == NULL)
3652 vim_free(name);
3653 else
3654 {
3655 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3656 {
3657 listitem_T *li;
3658 int i = 0;
3659 int arg_len = 0;
3660 int lv_len = 0;
3661
3662 if (arg_pt != NULL)
3663 arg_len = arg_pt->pt_argc;
3664 if (list != NULL)
3665 lv_len = list->lv_len;
3666 pt->pt_argc = arg_len + lv_len;
3667 pt->pt_argv = (typval_T *)alloc(
3668 sizeof(typval_T) * pt->pt_argc);
3669 if (pt->pt_argv == NULL)
3670 {
3671 vim_free(pt);
3672 vim_free(name);
3673 return;
3674 }
3675 else
3676 {
3677 for (i = 0; i < arg_len; i++)
3678 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3679 if (lv_len > 0)
3680 for (li = list->lv_first; li != NULL;
3681 li = li->li_next)
3682 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
3683 }
3684 }
3685
3686 /* For "function(dict.func, [], dict)" and "func" is a partial
3687 * use "dict". That is backwards compatible. */
3688 if (dict_idx > 0)
3689 {
3690 /* The dict is bound explicitly, pt_auto is FALSE. */
3691 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3692 ++pt->pt_dict->dv_refcount;
3693 }
3694 else if (arg_pt != NULL)
3695 {
3696 /* If the dict was bound automatically the result is also
3697 * bound automatically. */
3698 pt->pt_dict = arg_pt->pt_dict;
3699 pt->pt_auto = arg_pt->pt_auto;
3700 if (pt->pt_dict != NULL)
3701 ++pt->pt_dict->dv_refcount;
3702 }
3703
3704 pt->pt_refcount = 1;
3705 pt->pt_name = name;
3706 func_ref(pt->pt_name);
3707 }
3708 rettv->v_type = VAR_PARTIAL;
3709 rettv->vval.v_partial = pt;
3710 }
3711 else
3712 {
3713 /* result is a VAR_FUNC */
3714 rettv->v_type = VAR_FUNC;
3715 rettv->vval.v_string = name;
3716 func_ref(name);
3717 }
3718 }
3719}
3720
3721/*
3722 * "garbagecollect()" function
3723 */
3724 static void
3725f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3726{
3727 /* This is postponed until we are back at the toplevel, because we may be
3728 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3729 want_garbage_collect = TRUE;
3730
3731 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1)
3732 garbage_collect_at_exit = TRUE;
3733}
3734
3735/*
3736 * "get()" function
3737 */
3738 static void
3739f_get(typval_T *argvars, typval_T *rettv)
3740{
3741 listitem_T *li;
3742 list_T *l;
3743 dictitem_T *di;
3744 dict_T *d;
3745 typval_T *tv = NULL;
3746
3747 if (argvars[0].v_type == VAR_LIST)
3748 {
3749 if ((l = argvars[0].vval.v_list) != NULL)
3750 {
3751 int error = FALSE;
3752
3753 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error));
3754 if (!error && li != NULL)
3755 tv = &li->li_tv;
3756 }
3757 }
3758 else if (argvars[0].v_type == VAR_DICT)
3759 {
3760 if ((d = argvars[0].vval.v_dict) != NULL)
3761 {
3762 di = dict_find(d, get_tv_string(&argvars[1]), -1);
3763 if (di != NULL)
3764 tv = &di->di_tv;
3765 }
3766 }
3767 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3768 {
3769 partial_T *pt;
3770 partial_T fref_pt;
3771
3772 if (argvars[0].v_type == VAR_PARTIAL)
3773 pt = argvars[0].vval.v_partial;
3774 else
3775 {
3776 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3777 fref_pt.pt_name = argvars[0].vval.v_string;
3778 pt = &fref_pt;
3779 }
3780
3781 if (pt != NULL)
3782 {
3783 char_u *what = get_tv_string(&argvars[1]);
3784
3785 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3786 {
3787 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
3788 if (pt->pt_name == NULL)
3789 rettv->vval.v_string = NULL;
3790 else
3791 rettv->vval.v_string = vim_strsave(pt->pt_name);
3792 }
3793 else if (STRCMP(what, "dict") == 0)
3794 {
3795 rettv->v_type = VAR_DICT;
3796 rettv->vval.v_dict = pt->pt_dict;
3797 if (pt->pt_dict != NULL)
3798 ++pt->pt_dict->dv_refcount;
3799 }
3800 else if (STRCMP(what, "args") == 0)
3801 {
3802 rettv->v_type = VAR_LIST;
3803 if (rettv_list_alloc(rettv) == OK)
3804 {
3805 int i;
3806
3807 for (i = 0; i < pt->pt_argc; ++i)
3808 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3809 }
3810 }
3811 else
3812 EMSG2(_(e_invarg2), what);
3813 return;
3814 }
3815 }
3816 else
3817 EMSG2(_(e_listdictarg), "get()");
3818
3819 if (tv == NULL)
3820 {
3821 if (argvars[2].v_type != VAR_UNKNOWN)
3822 copy_tv(&argvars[2], rettv);
3823 }
3824 else
3825 copy_tv(tv, rettv);
3826}
3827
3828static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv);
3829
3830/*
3831 * Get line or list of lines from buffer "buf" into "rettv".
3832 * Return a range (from start to end) of lines in rettv from the specified
3833 * buffer.
3834 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
3835 */
3836 static void
3837get_buffer_lines(
3838 buf_T *buf,
3839 linenr_T start,
3840 linenr_T end,
3841 int retlist,
3842 typval_T *rettv)
3843{
3844 char_u *p;
3845
3846 rettv->v_type = VAR_STRING;
3847 rettv->vval.v_string = NULL;
3848 if (retlist && rettv_list_alloc(rettv) == FAIL)
3849 return;
3850
3851 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
3852 return;
3853
3854 if (!retlist)
3855 {
3856 if (start >= 1 && start <= buf->b_ml.ml_line_count)
3857 p = ml_get_buf(buf, start, FALSE);
3858 else
3859 p = (char_u *)"";
3860 rettv->vval.v_string = vim_strsave(p);
3861 }
3862 else
3863 {
3864 if (end < start)
3865 return;
3866
3867 if (start < 1)
3868 start = 1;
3869 if (end > buf->b_ml.ml_line_count)
3870 end = buf->b_ml.ml_line_count;
3871 while (start <= end)
3872 if (list_append_string(rettv->vval.v_list,
3873 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
3874 break;
3875 }
3876}
3877
3878/*
3879 * Get the lnum from the first argument.
3880 * Also accepts "$", then "buf" is used.
3881 * Returns 0 on error.
3882 */
3883 static linenr_T
3884get_tv_lnum_buf(typval_T *argvars, buf_T *buf)
3885{
3886 if (argvars[0].v_type == VAR_STRING
3887 && argvars[0].vval.v_string != NULL
3888 && argvars[0].vval.v_string[0] == '$'
3889 && buf != NULL)
3890 return buf->b_ml.ml_line_count;
3891 return (linenr_T)get_tv_number_chk(&argvars[0], NULL);
3892}
3893
3894/*
3895 * "getbufline()" function
3896 */
3897 static void
3898f_getbufline(typval_T *argvars, typval_T *rettv)
3899{
3900 linenr_T lnum;
3901 linenr_T end;
3902 buf_T *buf;
3903
3904 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
3905 ++emsg_off;
3906 buf = get_buf_tv(&argvars[0], FALSE);
3907 --emsg_off;
3908
3909 lnum = get_tv_lnum_buf(&argvars[1], buf);
3910 if (argvars[2].v_type == VAR_UNKNOWN)
3911 end = lnum;
3912 else
3913 end = get_tv_lnum_buf(&argvars[2], buf);
3914
3915 get_buffer_lines(buf, lnum, end, TRUE, rettv);
3916}
3917
3918/*
3919 * "getbufvar()" function
3920 */
3921 static void
3922f_getbufvar(typval_T *argvars, typval_T *rettv)
3923{
3924 buf_T *buf;
3925 buf_T *save_curbuf;
3926 char_u *varname;
3927 dictitem_T *v;
3928 int done = FALSE;
3929
3930 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
3931 varname = get_tv_string_chk(&argvars[1]);
3932 ++emsg_off;
3933 buf = get_buf_tv(&argvars[0], FALSE);
3934
3935 rettv->v_type = VAR_STRING;
3936 rettv->vval.v_string = NULL;
3937
3938 if (buf != NULL && varname != NULL)
3939 {
3940 /* set curbuf to be our buf, temporarily */
3941 save_curbuf = curbuf;
3942 curbuf = buf;
3943
3944 if (*varname == '&') /* buffer-local-option */
3945 {
3946 if (get_option_tv(&varname, rettv, TRUE) == OK)
3947 done = TRUE;
3948 }
3949 else if (STRCMP(varname, "changedtick") == 0)
3950 {
3951 rettv->v_type = VAR_NUMBER;
3952 rettv->vval.v_number = curbuf->b_changedtick;
3953 done = TRUE;
3954 }
3955 else
3956 {
3957 /* Look up the variable. */
3958 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
3959 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
3960 'b', varname, FALSE);
3961 if (v != NULL)
3962 {
3963 copy_tv(&v->di_tv, rettv);
3964 done = TRUE;
3965 }
3966 }
3967
3968 /* restore previous notion of curbuf */
3969 curbuf = save_curbuf;
3970 }
3971
3972 if (!done && argvars[2].v_type != VAR_UNKNOWN)
3973 /* use the default value */
3974 copy_tv(&argvars[2], rettv);
3975
3976 --emsg_off;
3977}
3978
3979/*
3980 * "getchar()" function
3981 */
3982 static void
3983f_getchar(typval_T *argvars, typval_T *rettv)
3984{
3985 varnumber_T n;
3986 int error = FALSE;
3987
3988 /* Position the cursor. Needed after a message that ends in a space. */
3989 windgoto(msg_row, msg_col);
3990
3991 ++no_mapping;
3992 ++allow_keys;
3993 for (;;)
3994 {
3995 if (argvars[0].v_type == VAR_UNKNOWN)
3996 /* getchar(): blocking wait. */
3997 n = safe_vgetc();
3998 else if (get_tv_number_chk(&argvars[0], &error) == 1)
3999 /* getchar(1): only check if char avail */
4000 n = vpeekc_any();
4001 else if (error || vpeekc_any() == NUL)
4002 /* illegal argument or getchar(0) and no char avail: return zero */
4003 n = 0;
4004 else
4005 /* getchar(0) and char avail: return char */
4006 n = safe_vgetc();
4007
4008 if (n == K_IGNORE)
4009 continue;
4010 break;
4011 }
4012 --no_mapping;
4013 --allow_keys;
4014
4015 set_vim_var_nr(VV_MOUSE_WIN, 0);
4016 set_vim_var_nr(VV_MOUSE_WINID, 0);
4017 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4018 set_vim_var_nr(VV_MOUSE_COL, 0);
4019
4020 rettv->vval.v_number = n;
4021 if (IS_SPECIAL(n) || mod_mask != 0)
4022 {
4023 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4024 int i = 0;
4025
4026 /* Turn a special key into three bytes, plus modifier. */
4027 if (mod_mask != 0)
4028 {
4029 temp[i++] = K_SPECIAL;
4030 temp[i++] = KS_MODIFIER;
4031 temp[i++] = mod_mask;
4032 }
4033 if (IS_SPECIAL(n))
4034 {
4035 temp[i++] = K_SPECIAL;
4036 temp[i++] = K_SECOND(n);
4037 temp[i++] = K_THIRD(n);
4038 }
4039#ifdef FEAT_MBYTE
4040 else if (has_mbyte)
4041 i += (*mb_char2bytes)(n, temp + i);
4042#endif
4043 else
4044 temp[i++] = n;
4045 temp[i++] = NUL;
4046 rettv->v_type = VAR_STRING;
4047 rettv->vval.v_string = vim_strsave(temp);
4048
4049#ifdef FEAT_MOUSE
4050 if (is_mouse_key(n))
4051 {
4052 int row = mouse_row;
4053 int col = mouse_col;
4054 win_T *win;
4055 linenr_T lnum;
4056# ifdef FEAT_WINDOWS
4057 win_T *wp;
4058# endif
4059 int winnr = 1;
4060
4061 if (row >= 0 && col >= 0)
4062 {
4063 /* Find the window at the mouse coordinates and compute the
4064 * text position. */
4065 win = mouse_find_win(&row, &col);
4066 (void)mouse_comp_pos(win, &row, &col, &lnum);
4067# ifdef FEAT_WINDOWS
4068 for (wp = firstwin; wp != win; wp = wp->w_next)
4069 ++winnr;
4070# endif
4071 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4072 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4073 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4074 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4075 }
4076 }
4077#endif
4078 }
4079}
4080
4081/*
4082 * "getcharmod()" function
4083 */
4084 static void
4085f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4086{
4087 rettv->vval.v_number = mod_mask;
4088}
4089
4090/*
4091 * "getcharsearch()" function
4092 */
4093 static void
4094f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4095{
4096 if (rettv_dict_alloc(rettv) != FAIL)
4097 {
4098 dict_T *dict = rettv->vval.v_dict;
4099
4100 dict_add_nr_str(dict, "char", 0L, last_csearch());
4101 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL);
4102 dict_add_nr_str(dict, "until", last_csearch_until(), NULL);
4103 }
4104}
4105
4106/*
4107 * "getcmdline()" function
4108 */
4109 static void
4110f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4111{
4112 rettv->v_type = VAR_STRING;
4113 rettv->vval.v_string = get_cmdline_str();
4114}
4115
4116/*
4117 * "getcmdpos()" function
4118 */
4119 static void
4120f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4121{
4122 rettv->vval.v_number = get_cmdline_pos() + 1;
4123}
4124
4125/*
4126 * "getcmdtype()" function
4127 */
4128 static void
4129f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4130{
4131 rettv->v_type = VAR_STRING;
4132 rettv->vval.v_string = alloc(2);
4133 if (rettv->vval.v_string != NULL)
4134 {
4135 rettv->vval.v_string[0] = get_cmdline_type();
4136 rettv->vval.v_string[1] = NUL;
4137 }
4138}
4139
4140/*
4141 * "getcmdwintype()" function
4142 */
4143 static void
4144f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4145{
4146 rettv->v_type = VAR_STRING;
4147 rettv->vval.v_string = NULL;
4148#ifdef FEAT_CMDWIN
4149 rettv->vval.v_string = alloc(2);
4150 if (rettv->vval.v_string != NULL)
4151 {
4152 rettv->vval.v_string[0] = cmdwin_type;
4153 rettv->vval.v_string[1] = NUL;
4154 }
4155#endif
4156}
4157
4158#if defined(FEAT_CMDL_COMPL)
4159/*
4160 * "getcompletion()" function
4161 */
4162 static void
4163f_getcompletion(typval_T *argvars, typval_T *rettv)
4164{
4165 char_u *pat;
4166 expand_T xpc;
4167 int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL
4168 | WILD_LIST_NOTFOUND | WILD_NO_BEEP;
4169
4170 if (p_wic)
4171 options |= WILD_ICASE;
4172
4173 ExpandInit(&xpc);
4174 xpc.xp_pattern = get_tv_string(&argvars[0]);
4175 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4176 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1]));
4177 if (xpc.xp_context == EXPAND_NOTHING)
4178 {
4179 if (argvars[1].v_type == VAR_STRING)
4180 EMSG2(_(e_invarg2), argvars[1].vval.v_string);
4181 else
4182 EMSG(_(e_invarg));
4183 return;
4184 }
4185
4186# if defined(FEAT_MENU)
4187 if (xpc.xp_context == EXPAND_MENUS)
4188 {
4189 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4190 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4191 }
4192# endif
4193
4194 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4195 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4196 {
4197 int i;
4198
4199 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4200
4201 for (i = 0; i < xpc.xp_numfiles; i++)
4202 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4203 }
4204 vim_free(pat);
4205 ExpandCleanup(&xpc);
4206}
4207#endif
4208
4209/*
4210 * "getcwd()" function
4211 */
4212 static void
4213f_getcwd(typval_T *argvars, typval_T *rettv)
4214{
4215 win_T *wp = NULL;
4216 char_u *cwd;
4217
4218 rettv->v_type = VAR_STRING;
4219 rettv->vval.v_string = NULL;
4220
4221 wp = find_tabwin(&argvars[0], &argvars[1]);
4222 if (wp != NULL)
4223 {
4224 if (wp->w_localdir != NULL)
4225 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4226 else if (globaldir != NULL)
4227 rettv->vval.v_string = vim_strsave(globaldir);
4228 else
4229 {
4230 cwd = alloc(MAXPATHL);
4231 if (cwd != NULL)
4232 {
4233 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4234 rettv->vval.v_string = vim_strsave(cwd);
4235 vim_free(cwd);
4236 }
4237 }
4238#ifdef BACKSLASH_IN_FILENAME
4239 if (rettv->vval.v_string != NULL)
4240 slash_adjust(rettv->vval.v_string);
4241#endif
4242 }
4243}
4244
4245/*
4246 * "getfontname()" function
4247 */
4248 static void
4249f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4250{
4251 rettv->v_type = VAR_STRING;
4252 rettv->vval.v_string = NULL;
4253#ifdef FEAT_GUI
4254 if (gui.in_use)
4255 {
4256 GuiFont font;
4257 char_u *name = NULL;
4258
4259 if (argvars[0].v_type == VAR_UNKNOWN)
4260 {
4261 /* Get the "Normal" font. Either the name saved by
4262 * hl_set_font_name() or from the font ID. */
4263 font = gui.norm_font;
4264 name = hl_get_font_name();
4265 }
4266 else
4267 {
4268 name = get_tv_string(&argvars[0]);
4269 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4270 return;
4271 font = gui_mch_get_font(name, FALSE);
4272 if (font == NOFONT)
4273 return; /* Invalid font name, return empty string. */
4274 }
4275 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4276 if (argvars[0].v_type != VAR_UNKNOWN)
4277 gui_mch_free_font(font);
4278 }
4279#endif
4280}
4281
4282/*
4283 * "getfperm({fname})" function
4284 */
4285 static void
4286f_getfperm(typval_T *argvars, typval_T *rettv)
4287{
4288 char_u *fname;
4289 stat_T st;
4290 char_u *perm = NULL;
4291 char_u flags[] = "rwx";
4292 int i;
4293
4294 fname = get_tv_string(&argvars[0]);
4295
4296 rettv->v_type = VAR_STRING;
4297 if (mch_stat((char *)fname, &st) >= 0)
4298 {
4299 perm = vim_strsave((char_u *)"---------");
4300 if (perm != NULL)
4301 {
4302 for (i = 0; i < 9; i++)
4303 {
4304 if (st.st_mode & (1 << (8 - i)))
4305 perm[i] = flags[i % 3];
4306 }
4307 }
4308 }
4309 rettv->vval.v_string = perm;
4310}
4311
4312/*
4313 * "getfsize({fname})" function
4314 */
4315 static void
4316f_getfsize(typval_T *argvars, typval_T *rettv)
4317{
4318 char_u *fname;
4319 stat_T st;
4320
4321 fname = get_tv_string(&argvars[0]);
4322
4323 rettv->v_type = VAR_NUMBER;
4324
4325 if (mch_stat((char *)fname, &st) >= 0)
4326 {
4327 if (mch_isdir(fname))
4328 rettv->vval.v_number = 0;
4329 else
4330 {
4331 rettv->vval.v_number = (varnumber_T)st.st_size;
4332
4333 /* non-perfect check for overflow */
4334 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4335 rettv->vval.v_number = -2;
4336 }
4337 }
4338 else
4339 rettv->vval.v_number = -1;
4340}
4341
4342/*
4343 * "getftime({fname})" function
4344 */
4345 static void
4346f_getftime(typval_T *argvars, typval_T *rettv)
4347{
4348 char_u *fname;
4349 stat_T st;
4350
4351 fname = get_tv_string(&argvars[0]);
4352
4353 if (mch_stat((char *)fname, &st) >= 0)
4354 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4355 else
4356 rettv->vval.v_number = -1;
4357}
4358
4359/*
4360 * "getftype({fname})" function
4361 */
4362 static void
4363f_getftype(typval_T *argvars, typval_T *rettv)
4364{
4365 char_u *fname;
4366 stat_T st;
4367 char_u *type = NULL;
4368 char *t;
4369
4370 fname = get_tv_string(&argvars[0]);
4371
4372 rettv->v_type = VAR_STRING;
4373 if (mch_lstat((char *)fname, &st) >= 0)
4374 {
4375#ifdef S_ISREG
4376 if (S_ISREG(st.st_mode))
4377 t = "file";
4378 else if (S_ISDIR(st.st_mode))
4379 t = "dir";
4380# ifdef S_ISLNK
4381 else if (S_ISLNK(st.st_mode))
4382 t = "link";
4383# endif
4384# ifdef S_ISBLK
4385 else if (S_ISBLK(st.st_mode))
4386 t = "bdev";
4387# endif
4388# ifdef S_ISCHR
4389 else if (S_ISCHR(st.st_mode))
4390 t = "cdev";
4391# endif
4392# ifdef S_ISFIFO
4393 else if (S_ISFIFO(st.st_mode))
4394 t = "fifo";
4395# endif
4396# ifdef S_ISSOCK
4397 else if (S_ISSOCK(st.st_mode))
4398 t = "fifo";
4399# endif
4400 else
4401 t = "other";
4402#else
4403# ifdef S_IFMT
4404 switch (st.st_mode & S_IFMT)
4405 {
4406 case S_IFREG: t = "file"; break;
4407 case S_IFDIR: t = "dir"; break;
4408# ifdef S_IFLNK
4409 case S_IFLNK: t = "link"; break;
4410# endif
4411# ifdef S_IFBLK
4412 case S_IFBLK: t = "bdev"; break;
4413# endif
4414# ifdef S_IFCHR
4415 case S_IFCHR: t = "cdev"; break;
4416# endif
4417# ifdef S_IFIFO
4418 case S_IFIFO: t = "fifo"; break;
4419# endif
4420# ifdef S_IFSOCK
4421 case S_IFSOCK: t = "socket"; break;
4422# endif
4423 default: t = "other";
4424 }
4425# else
4426 if (mch_isdir(fname))
4427 t = "dir";
4428 else
4429 t = "file";
4430# endif
4431#endif
4432 type = vim_strsave((char_u *)t);
4433 }
4434 rettv->vval.v_string = type;
4435}
4436
4437/*
4438 * "getline(lnum, [end])" function
4439 */
4440 static void
4441f_getline(typval_T *argvars, typval_T *rettv)
4442{
4443 linenr_T lnum;
4444 linenr_T end;
4445 int retlist;
4446
4447 lnum = get_tv_lnum(argvars);
4448 if (argvars[1].v_type == VAR_UNKNOWN)
4449 {
4450 end = 0;
4451 retlist = FALSE;
4452 }
4453 else
4454 {
4455 end = get_tv_lnum(&argvars[1]);
4456 retlist = TRUE;
4457 }
4458
4459 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4460}
4461
4462/*
4463 * "getmatches()" function
4464 */
4465 static void
4466f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4467{
4468#ifdef FEAT_SEARCH_EXTRA
4469 dict_T *dict;
4470 matchitem_T *cur = curwin->w_match_head;
4471 int i;
4472
4473 if (rettv_list_alloc(rettv) == OK)
4474 {
4475 while (cur != NULL)
4476 {
4477 dict = dict_alloc();
4478 if (dict == NULL)
4479 return;
4480 if (cur->match.regprog == NULL)
4481 {
4482 /* match added with matchaddpos() */
4483 for (i = 0; i < MAXPOSMATCH; ++i)
4484 {
4485 llpos_T *llpos;
4486 char buf[6];
4487 list_T *l;
4488
4489 llpos = &cur->pos.pos[i];
4490 if (llpos->lnum == 0)
4491 break;
4492 l = list_alloc();
4493 if (l == NULL)
4494 break;
4495 list_append_number(l, (varnumber_T)llpos->lnum);
4496 if (llpos->col > 0)
4497 {
4498 list_append_number(l, (varnumber_T)llpos->col);
4499 list_append_number(l, (varnumber_T)llpos->len);
4500 }
4501 sprintf(buf, "pos%d", i + 1);
4502 dict_add_list(dict, buf, l);
4503 }
4504 }
4505 else
4506 {
4507 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4508 }
4509 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4510 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4511 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4512# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4513 if (cur->conceal_char)
4514 {
4515 char_u buf[MB_MAXBYTES + 1];
4516
4517 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4518 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4519 }
4520# endif
4521 list_append_dict(rettv->vval.v_list, dict);
4522 cur = cur->next;
4523 }
4524 }
4525#endif
4526}
4527
4528/*
4529 * "getpid()" function
4530 */
4531 static void
4532f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4533{
4534 rettv->vval.v_number = mch_get_pid();
4535}
4536
4537 static void
4538getpos_both(
4539 typval_T *argvars,
4540 typval_T *rettv,
4541 int getcurpos)
4542{
4543 pos_T *fp;
4544 list_T *l;
4545 int fnum = -1;
4546
4547 if (rettv_list_alloc(rettv) == OK)
4548 {
4549 l = rettv->vval.v_list;
4550 if (getcurpos)
4551 fp = &curwin->w_cursor;
4552 else
4553 fp = var2fpos(&argvars[0], TRUE, &fnum);
4554 if (fnum != -1)
4555 list_append_number(l, (varnumber_T)fnum);
4556 else
4557 list_append_number(l, (varnumber_T)0);
4558 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4559 : (varnumber_T)0);
4560 list_append_number(l, (fp != NULL)
4561 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4562 : (varnumber_T)0);
4563 list_append_number(l,
4564#ifdef FEAT_VIRTUALEDIT
4565 (fp != NULL) ? (varnumber_T)fp->coladd :
4566#endif
4567 (varnumber_T)0);
4568 if (getcurpos)
4569 {
4570 update_curswant();
4571 list_append_number(l, curwin->w_curswant == MAXCOL ?
4572 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
4573 }
4574 }
4575 else
4576 rettv->vval.v_number = FALSE;
4577}
4578
4579
4580/*
4581 * "getcurpos()" function
4582 */
4583 static void
4584f_getcurpos(typval_T *argvars, typval_T *rettv)
4585{
4586 getpos_both(argvars, rettv, TRUE);
4587}
4588
4589/*
4590 * "getpos(string)" function
4591 */
4592 static void
4593f_getpos(typval_T *argvars, typval_T *rettv)
4594{
4595 getpos_both(argvars, rettv, FALSE);
4596}
4597
4598/*
4599 * "getqflist()" and "getloclist()" functions
4600 */
4601 static void
4602f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4603{
4604#ifdef FEAT_QUICKFIX
4605 win_T *wp;
4606#endif
4607
4608#ifdef FEAT_QUICKFIX
4609 if (rettv_list_alloc(rettv) == OK)
4610 {
4611 wp = NULL;
4612 if (argvars[0].v_type != VAR_UNKNOWN) /* getloclist() */
4613 {
4614 wp = find_win_by_nr(&argvars[0], NULL);
4615 if (wp == NULL)
4616 return;
4617 }
4618
4619 (void)get_errorlist(wp, rettv->vval.v_list);
4620 }
4621#endif
4622}
4623
4624/*
4625 * "getreg()" function
4626 */
4627 static void
4628f_getreg(typval_T *argvars, typval_T *rettv)
4629{
4630 char_u *strregname;
4631 int regname;
4632 int arg2 = FALSE;
4633 int return_list = FALSE;
4634 int error = FALSE;
4635
4636 if (argvars[0].v_type != VAR_UNKNOWN)
4637 {
4638 strregname = get_tv_string_chk(&argvars[0]);
4639 error = strregname == NULL;
4640 if (argvars[1].v_type != VAR_UNKNOWN)
4641 {
4642 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
4643 if (!error && argvars[2].v_type != VAR_UNKNOWN)
4644 return_list = (int)get_tv_number_chk(&argvars[2], &error);
4645 }
4646 }
4647 else
4648 strregname = get_vim_var_str(VV_REG);
4649
4650 if (error)
4651 return;
4652
4653 regname = (strregname == NULL ? '"' : *strregname);
4654 if (regname == 0)
4655 regname = '"';
4656
4657 if (return_list)
4658 {
4659 rettv->v_type = VAR_LIST;
4660 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4661 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4662 if (rettv->vval.v_list == NULL)
4663 (void)rettv_list_alloc(rettv);
4664 else
4665 ++rettv->vval.v_list->lv_refcount;
4666 }
4667 else
4668 {
4669 rettv->v_type = VAR_STRING;
4670 rettv->vval.v_string = get_reg_contents(regname,
4671 arg2 ? GREG_EXPR_SRC : 0);
4672 }
4673}
4674
4675/*
4676 * "getregtype()" function
4677 */
4678 static void
4679f_getregtype(typval_T *argvars, typval_T *rettv)
4680{
4681 char_u *strregname;
4682 int regname;
4683 char_u buf[NUMBUFLEN + 2];
4684 long reglen = 0;
4685
4686 if (argvars[0].v_type != VAR_UNKNOWN)
4687 {
4688 strregname = get_tv_string_chk(&argvars[0]);
4689 if (strregname == NULL) /* type error; errmsg already given */
4690 {
4691 rettv->v_type = VAR_STRING;
4692 rettv->vval.v_string = NULL;
4693 return;
4694 }
4695 }
4696 else
4697 /* Default to v:register */
4698 strregname = get_vim_var_str(VV_REG);
4699
4700 regname = (strregname == NULL ? '"' : *strregname);
4701 if (regname == 0)
4702 regname = '"';
4703
4704 buf[0] = NUL;
4705 buf[1] = NUL;
4706 switch (get_reg_type(regname, &reglen))
4707 {
4708 case MLINE: buf[0] = 'V'; break;
4709 case MCHAR: buf[0] = 'v'; break;
4710 case MBLOCK:
4711 buf[0] = Ctrl_V;
4712 sprintf((char *)buf + 1, "%ld", reglen + 1);
4713 break;
4714 }
4715 rettv->v_type = VAR_STRING;
4716 rettv->vval.v_string = vim_strsave(buf);
4717}
4718
4719/*
4720 * "gettabvar()" function
4721 */
4722 static void
4723f_gettabvar(typval_T *argvars, typval_T *rettv)
4724{
4725 win_T *oldcurwin;
4726 tabpage_T *tp, *oldtabpage;
4727 dictitem_T *v;
4728 char_u *varname;
4729 int done = FALSE;
4730
4731 rettv->v_type = VAR_STRING;
4732 rettv->vval.v_string = NULL;
4733
4734 varname = get_tv_string_chk(&argvars[1]);
4735 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
4736 if (tp != NULL && varname != NULL)
4737 {
4738 /* Set tp to be our tabpage, temporarily. Also set the window to the
4739 * first window in the tabpage, otherwise the window is not valid. */
4740 if (switch_win(&oldcurwin, &oldtabpage,
4741 tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE)
4742 == OK)
4743 {
4744 /* look up the variable */
4745 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
4746 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
4747 if (v != NULL)
4748 {
4749 copy_tv(&v->di_tv, rettv);
4750 done = TRUE;
4751 }
4752 }
4753
4754 /* restore previous notion of curwin */
4755 restore_win(oldcurwin, oldtabpage, TRUE);
4756 }
4757
4758 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4759 copy_tv(&argvars[2], rettv);
4760}
4761
4762/*
4763 * "gettabwinvar()" function
4764 */
4765 static void
4766f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4767{
4768 getwinvar(argvars, rettv, 1);
4769}
4770
4771/*
4772 * "getwinposx()" function
4773 */
4774 static void
4775f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
4776{
4777 rettv->vval.v_number = -1;
4778#ifdef FEAT_GUI
4779 if (gui.in_use)
4780 {
4781 int x, y;
4782
4783 if (gui_mch_get_winpos(&x, &y) == OK)
4784 rettv->vval.v_number = x;
4785 }
4786#endif
4787}
4788
4789/*
4790 * "win_findbuf()" function
4791 */
4792 static void
4793f_win_findbuf(typval_T *argvars, typval_T *rettv)
4794{
4795 if (rettv_list_alloc(rettv) != FAIL)
4796 win_findbuf(argvars, rettv->vval.v_list);
4797}
4798
4799/*
4800 * "win_getid()" function
4801 */
4802 static void
4803f_win_getid(typval_T *argvars, typval_T *rettv)
4804{
4805 rettv->vval.v_number = win_getid(argvars);
4806}
4807
4808/*
4809 * "win_gotoid()" function
4810 */
4811 static void
4812f_win_gotoid(typval_T *argvars, typval_T *rettv)
4813{
4814 rettv->vval.v_number = win_gotoid(argvars);
4815}
4816
4817/*
4818 * "win_id2tabwin()" function
4819 */
4820 static void
4821f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
4822{
4823 if (rettv_list_alloc(rettv) != FAIL)
4824 win_id2tabwin(argvars, rettv->vval.v_list);
4825}
4826
4827/*
4828 * "win_id2win()" function
4829 */
4830 static void
4831f_win_id2win(typval_T *argvars, typval_T *rettv)
4832{
4833 rettv->vval.v_number = win_id2win(argvars);
4834}
4835
4836/*
4837 * "getwinposy()" function
4838 */
4839 static void
4840f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
4841{
4842 rettv->vval.v_number = -1;
4843#ifdef FEAT_GUI
4844 if (gui.in_use)
4845 {
4846 int x, y;
4847
4848 if (gui_mch_get_winpos(&x, &y) == OK)
4849 rettv->vval.v_number = y;
4850 }
4851#endif
4852}
4853
4854/*
4855 * "getwinvar()" function
4856 */
4857 static void
4858f_getwinvar(typval_T *argvars, typval_T *rettv)
4859{
4860 getwinvar(argvars, rettv, 0);
4861}
4862
4863/*
4864 * "glob()" function
4865 */
4866 static void
4867f_glob(typval_T *argvars, typval_T *rettv)
4868{
4869 int options = WILD_SILENT|WILD_USE_NL;
4870 expand_T xpc;
4871 int error = FALSE;
4872
4873 /* When the optional second argument is non-zero, don't remove matches
4874 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
4875 rettv->v_type = VAR_STRING;
4876 if (argvars[1].v_type != VAR_UNKNOWN)
4877 {
4878 if (get_tv_number_chk(&argvars[1], &error))
4879 options |= WILD_KEEP_ALL;
4880 if (argvars[2].v_type != VAR_UNKNOWN)
4881 {
4882 if (get_tv_number_chk(&argvars[2], &error))
4883 {
4884 rettv->v_type = VAR_LIST;
4885 rettv->vval.v_list = NULL;
4886 }
4887 if (argvars[3].v_type != VAR_UNKNOWN
4888 && get_tv_number_chk(&argvars[3], &error))
4889 options |= WILD_ALLLINKS;
4890 }
4891 }
4892 if (!error)
4893 {
4894 ExpandInit(&xpc);
4895 xpc.xp_context = EXPAND_FILES;
4896 if (p_wic)
4897 options += WILD_ICASE;
4898 if (rettv->v_type == VAR_STRING)
4899 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
4900 NULL, options, WILD_ALL);
4901 else if (rettv_list_alloc(rettv) != FAIL)
4902 {
4903 int i;
4904
4905 ExpandOne(&xpc, get_tv_string(&argvars[0]),
4906 NULL, options, WILD_ALL_KEEP);
4907 for (i = 0; i < xpc.xp_numfiles; i++)
4908 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4909
4910 ExpandCleanup(&xpc);
4911 }
4912 }
4913 else
4914 rettv->vval.v_string = NULL;
4915}
4916
4917/*
4918 * "globpath()" function
4919 */
4920 static void
4921f_globpath(typval_T *argvars, typval_T *rettv)
4922{
4923 int flags = 0;
4924 char_u buf1[NUMBUFLEN];
4925 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
4926 int error = FALSE;
4927 garray_T ga;
4928 int i;
4929
4930 /* When the optional second argument is non-zero, don't remove matches
4931 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
4932 rettv->v_type = VAR_STRING;
4933 if (argvars[2].v_type != VAR_UNKNOWN)
4934 {
4935 if (get_tv_number_chk(&argvars[2], &error))
4936 flags |= WILD_KEEP_ALL;
4937 if (argvars[3].v_type != VAR_UNKNOWN)
4938 {
4939 if (get_tv_number_chk(&argvars[3], &error))
4940 {
4941 rettv->v_type = VAR_LIST;
4942 rettv->vval.v_list = NULL;
4943 }
4944 if (argvars[4].v_type != VAR_UNKNOWN
4945 && get_tv_number_chk(&argvars[4], &error))
4946 flags |= WILD_ALLLINKS;
4947 }
4948 }
4949 if (file != NULL && !error)
4950 {
4951 ga_init2(&ga, (int)sizeof(char_u *), 10);
4952 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
4953 if (rettv->v_type == VAR_STRING)
4954 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
4955 else if (rettv_list_alloc(rettv) != FAIL)
4956 for (i = 0; i < ga.ga_len; ++i)
4957 list_append_string(rettv->vval.v_list,
4958 ((char_u **)(ga.ga_data))[i], -1);
4959 ga_clear_strings(&ga);
4960 }
4961 else
4962 rettv->vval.v_string = NULL;
4963}
4964
4965/*
4966 * "glob2regpat()" function
4967 */
4968 static void
4969f_glob2regpat(typval_T *argvars, typval_T *rettv)
4970{
4971 char_u *pat = get_tv_string_chk(&argvars[0]);
4972
4973 rettv->v_type = VAR_STRING;
4974 rettv->vval.v_string = (pat == NULL)
4975 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
4976}
4977
4978/* for VIM_VERSION_ defines */
4979#include "version.h"
4980
4981/*
4982 * "has()" function
4983 */
4984 static void
4985f_has(typval_T *argvars, typval_T *rettv)
4986{
4987 int i;
4988 char_u *name;
4989 int n = FALSE;
4990 static char *(has_list[]) =
4991 {
4992#ifdef AMIGA
4993 "amiga",
4994# ifdef FEAT_ARP
4995 "arp",
4996# endif
4997#endif
4998#ifdef __BEOS__
4999 "beos",
5000#endif
5001#ifdef MACOS
5002 "mac",
5003#endif
5004#if defined(MACOS_X_UNIX)
5005 "macunix", /* built with 'darwin' enabled */
5006#endif
5007#if defined(__APPLE__) && __APPLE__ == 1
5008 "osx", /* built with or without 'darwin' enabled */
5009#endif
5010#ifdef __QNX__
5011 "qnx",
5012#endif
5013#ifdef UNIX
5014 "unix",
5015#endif
5016#ifdef VMS
5017 "vms",
5018#endif
5019#ifdef WIN32
5020 "win32",
5021#endif
5022#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5023 "win32unix",
5024#endif
5025#if defined(WIN64) || defined(_WIN64)
5026 "win64",
5027#endif
5028#ifdef EBCDIC
5029 "ebcdic",
5030#endif
5031#ifndef CASE_INSENSITIVE_FILENAME
5032 "fname_case",
5033#endif
5034#ifdef HAVE_ACL
5035 "acl",
5036#endif
5037#ifdef FEAT_ARABIC
5038 "arabic",
5039#endif
5040#ifdef FEAT_AUTOCMD
5041 "autocmd",
5042#endif
5043#ifdef FEAT_BEVAL
5044 "balloon_eval",
5045# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5046 "balloon_multiline",
5047# endif
5048#endif
5049#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5050 "builtin_terms",
5051# ifdef ALL_BUILTIN_TCAPS
5052 "all_builtin_terms",
5053# endif
5054#endif
5055#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5056 || defined(FEAT_GUI_W32) \
5057 || defined(FEAT_GUI_MOTIF))
5058 "browsefilter",
5059#endif
5060#ifdef FEAT_BYTEOFF
5061 "byte_offset",
5062#endif
5063#ifdef FEAT_JOB_CHANNEL
5064 "channel",
5065#endif
5066#ifdef FEAT_CINDENT
5067 "cindent",
5068#endif
5069#ifdef FEAT_CLIENTSERVER
5070 "clientserver",
5071#endif
5072#ifdef FEAT_CLIPBOARD
5073 "clipboard",
5074#endif
5075#ifdef FEAT_CMDL_COMPL
5076 "cmdline_compl",
5077#endif
5078#ifdef FEAT_CMDHIST
5079 "cmdline_hist",
5080#endif
5081#ifdef FEAT_COMMENTS
5082 "comments",
5083#endif
5084#ifdef FEAT_CONCEAL
5085 "conceal",
5086#endif
5087#ifdef FEAT_CRYPT
5088 "cryptv",
5089 "crypt-blowfish",
5090 "crypt-blowfish2",
5091#endif
5092#ifdef FEAT_CSCOPE
5093 "cscope",
5094#endif
5095#ifdef FEAT_CURSORBIND
5096 "cursorbind",
5097#endif
5098#ifdef CURSOR_SHAPE
5099 "cursorshape",
5100#endif
5101#ifdef DEBUG
5102 "debug",
5103#endif
5104#ifdef FEAT_CON_DIALOG
5105 "dialog_con",
5106#endif
5107#ifdef FEAT_GUI_DIALOG
5108 "dialog_gui",
5109#endif
5110#ifdef FEAT_DIFF
5111 "diff",
5112#endif
5113#ifdef FEAT_DIGRAPHS
5114 "digraphs",
5115#endif
5116#ifdef FEAT_DIRECTX
5117 "directx",
5118#endif
5119#ifdef FEAT_DND
5120 "dnd",
5121#endif
5122#ifdef FEAT_EMACS_TAGS
5123 "emacs_tags",
5124#endif
5125 "eval", /* always present, of course! */
5126 "ex_extra", /* graduated feature */
5127#ifdef FEAT_SEARCH_EXTRA
5128 "extra_search",
5129#endif
5130#ifdef FEAT_FKMAP
5131 "farsi",
5132#endif
5133#ifdef FEAT_SEARCHPATH
5134 "file_in_path",
5135#endif
5136#ifdef FEAT_FILTERPIPE
5137 "filterpipe",
5138#endif
5139#ifdef FEAT_FIND_ID
5140 "find_in_path",
5141#endif
5142#ifdef FEAT_FLOAT
5143 "float",
5144#endif
5145#ifdef FEAT_FOLDING
5146 "folding",
5147#endif
5148#ifdef FEAT_FOOTER
5149 "footer",
5150#endif
5151#if !defined(USE_SYSTEM) && defined(UNIX)
5152 "fork",
5153#endif
5154#ifdef FEAT_GETTEXT
5155 "gettext",
5156#endif
5157#ifdef FEAT_GUI
5158 "gui",
5159#endif
5160#ifdef FEAT_GUI_ATHENA
5161# ifdef FEAT_GUI_NEXTAW
5162 "gui_neXtaw",
5163# else
5164 "gui_athena",
5165# endif
5166#endif
5167#ifdef FEAT_GUI_GTK
5168 "gui_gtk",
5169# ifdef USE_GTK3
5170 "gui_gtk3",
5171# else
5172 "gui_gtk2",
5173# endif
5174#endif
5175#ifdef FEAT_GUI_GNOME
5176 "gui_gnome",
5177#endif
5178#ifdef FEAT_GUI_MAC
5179 "gui_mac",
5180#endif
5181#ifdef FEAT_GUI_MOTIF
5182 "gui_motif",
5183#endif
5184#ifdef FEAT_GUI_PHOTON
5185 "gui_photon",
5186#endif
5187#ifdef FEAT_GUI_W32
5188 "gui_win32",
5189#endif
5190#ifdef FEAT_HANGULIN
5191 "hangul_input",
5192#endif
5193#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5194 "iconv",
5195#endif
5196#ifdef FEAT_INS_EXPAND
5197 "insert_expand",
5198#endif
5199#ifdef FEAT_JOB_CHANNEL
5200 "job",
5201#endif
5202#ifdef FEAT_JUMPLIST
5203 "jumplist",
5204#endif
5205#ifdef FEAT_KEYMAP
5206 "keymap",
5207#endif
5208#ifdef FEAT_LANGMAP
5209 "langmap",
5210#endif
5211#ifdef FEAT_LIBCALL
5212 "libcall",
5213#endif
5214#ifdef FEAT_LINEBREAK
5215 "linebreak",
5216#endif
5217#ifdef FEAT_LISP
5218 "lispindent",
5219#endif
5220#ifdef FEAT_LISTCMDS
5221 "listcmds",
5222#endif
5223#ifdef FEAT_LOCALMAP
5224 "localmap",
5225#endif
5226#ifdef FEAT_LUA
5227# ifndef DYNAMIC_LUA
5228 "lua",
5229# endif
5230#endif
5231#ifdef FEAT_MENU
5232 "menu",
5233#endif
5234#ifdef FEAT_SESSION
5235 "mksession",
5236#endif
5237#ifdef FEAT_MODIFY_FNAME
5238 "modify_fname",
5239#endif
5240#ifdef FEAT_MOUSE
5241 "mouse",
5242#endif
5243#ifdef FEAT_MOUSESHAPE
5244 "mouseshape",
5245#endif
5246#if defined(UNIX) || defined(VMS)
5247# ifdef FEAT_MOUSE_DEC
5248 "mouse_dec",
5249# endif
5250# ifdef FEAT_MOUSE_GPM
5251 "mouse_gpm",
5252# endif
5253# ifdef FEAT_MOUSE_JSB
5254 "mouse_jsbterm",
5255# endif
5256# ifdef FEAT_MOUSE_NET
5257 "mouse_netterm",
5258# endif
5259# ifdef FEAT_MOUSE_PTERM
5260 "mouse_pterm",
5261# endif
5262# ifdef FEAT_MOUSE_SGR
5263 "mouse_sgr",
5264# endif
5265# ifdef FEAT_SYSMOUSE
5266 "mouse_sysmouse",
5267# endif
5268# ifdef FEAT_MOUSE_URXVT
5269 "mouse_urxvt",
5270# endif
5271# ifdef FEAT_MOUSE_XTERM
5272 "mouse_xterm",
5273# endif
5274#endif
5275#ifdef FEAT_MBYTE
5276 "multi_byte",
5277#endif
5278#ifdef FEAT_MBYTE_IME
5279 "multi_byte_ime",
5280#endif
5281#ifdef FEAT_MULTI_LANG
5282 "multi_lang",
5283#endif
5284#ifdef FEAT_MZSCHEME
5285#ifndef DYNAMIC_MZSCHEME
5286 "mzscheme",
5287#endif
5288#endif
5289#ifdef FEAT_NUM64
5290 "num64",
5291#endif
5292#ifdef FEAT_OLE
5293 "ole",
5294#endif
5295 "packages",
5296#ifdef FEAT_PATH_EXTRA
5297 "path_extra",
5298#endif
5299#ifdef FEAT_PERL
5300#ifndef DYNAMIC_PERL
5301 "perl",
5302#endif
5303#endif
5304#ifdef FEAT_PERSISTENT_UNDO
5305 "persistent_undo",
5306#endif
5307#ifdef FEAT_PYTHON
5308#ifndef DYNAMIC_PYTHON
5309 "python",
5310#endif
5311#endif
5312#ifdef FEAT_PYTHON3
5313#ifndef DYNAMIC_PYTHON3
5314 "python3",
5315#endif
5316#endif
5317#ifdef FEAT_POSTSCRIPT
5318 "postscript",
5319#endif
5320#ifdef FEAT_PRINTER
5321 "printer",
5322#endif
5323#ifdef FEAT_PROFILE
5324 "profile",
5325#endif
5326#ifdef FEAT_RELTIME
5327 "reltime",
5328#endif
5329#ifdef FEAT_QUICKFIX
5330 "quickfix",
5331#endif
5332#ifdef FEAT_RIGHTLEFT
5333 "rightleft",
5334#endif
5335#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5336 "ruby",
5337#endif
5338#ifdef FEAT_SCROLLBIND
5339 "scrollbind",
5340#endif
5341#ifdef FEAT_CMDL_INFO
5342 "showcmd",
5343 "cmdline_info",
5344#endif
5345#ifdef FEAT_SIGNS
5346 "signs",
5347#endif
5348#ifdef FEAT_SMARTINDENT
5349 "smartindent",
5350#endif
5351#ifdef STARTUPTIME
5352 "startuptime",
5353#endif
5354#ifdef FEAT_STL_OPT
5355 "statusline",
5356#endif
5357#ifdef FEAT_SUN_WORKSHOP
5358 "sun_workshop",
5359#endif
5360#ifdef FEAT_NETBEANS_INTG
5361 "netbeans_intg",
5362#endif
5363#ifdef FEAT_SPELL
5364 "spell",
5365#endif
5366#ifdef FEAT_SYN_HL
5367 "syntax",
5368#endif
5369#if defined(USE_SYSTEM) || !defined(UNIX)
5370 "system",
5371#endif
5372#ifdef FEAT_TAG_BINS
5373 "tag_binary",
5374#endif
5375#ifdef FEAT_TAG_OLDSTATIC
5376 "tag_old_static",
5377#endif
5378#ifdef FEAT_TAG_ANYWHITE
5379 "tag_any_white",
5380#endif
5381#ifdef FEAT_TCL
5382# ifndef DYNAMIC_TCL
5383 "tcl",
5384# endif
5385#endif
5386#ifdef FEAT_TERMGUICOLORS
5387 "termguicolors",
5388#endif
5389#ifdef TERMINFO
5390 "terminfo",
5391#endif
5392#ifdef FEAT_TERMRESPONSE
5393 "termresponse",
5394#endif
5395#ifdef FEAT_TEXTOBJ
5396 "textobjects",
5397#endif
5398#ifdef HAVE_TGETENT
5399 "tgetent",
5400#endif
5401#ifdef FEAT_TIMERS
5402 "timers",
5403#endif
5404#ifdef FEAT_TITLE
5405 "title",
5406#endif
5407#ifdef FEAT_TOOLBAR
5408 "toolbar",
5409#endif
5410#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5411 "unnamedplus",
5412#endif
5413#ifdef FEAT_USR_CMDS
5414 "user-commands", /* was accidentally included in 5.4 */
5415 "user_commands",
5416#endif
5417#ifdef FEAT_VIMINFO
5418 "viminfo",
5419#endif
5420#ifdef FEAT_WINDOWS
5421 "vertsplit",
5422#endif
5423#ifdef FEAT_VIRTUALEDIT
5424 "virtualedit",
5425#endif
5426 "visual",
5427#ifdef FEAT_VISUALEXTRA
5428 "visualextra",
5429#endif
5430#ifdef FEAT_VREPLACE
5431 "vreplace",
5432#endif
5433#ifdef FEAT_WILDIGN
5434 "wildignore",
5435#endif
5436#ifdef FEAT_WILDMENU
5437 "wildmenu",
5438#endif
5439#ifdef FEAT_WINDOWS
5440 "windows",
5441#endif
5442#ifdef FEAT_WAK
5443 "winaltkeys",
5444#endif
5445#ifdef FEAT_WRITEBACKUP
5446 "writebackup",
5447#endif
5448#ifdef FEAT_XIM
5449 "xim",
5450#endif
5451#ifdef FEAT_XFONTSET
5452 "xfontset",
5453#endif
5454#ifdef FEAT_XPM_W32
5455 "xpm",
5456 "xpm_w32", /* for backward compatibility */
5457#else
5458# if defined(HAVE_XPM)
5459 "xpm",
5460# endif
5461#endif
5462#ifdef USE_XSMP
5463 "xsmp",
5464#endif
5465#ifdef USE_XSMP_INTERACT
5466 "xsmp_interact",
5467#endif
5468#ifdef FEAT_XCLIPBOARD
5469 "xterm_clipboard",
5470#endif
5471#ifdef FEAT_XTERM_SAVE
5472 "xterm_save",
5473#endif
5474#if defined(UNIX) && defined(FEAT_X11)
5475 "X11",
5476#endif
5477 NULL
5478 };
5479
5480 name = get_tv_string(&argvars[0]);
5481 for (i = 0; has_list[i] != NULL; ++i)
5482 if (STRICMP(name, has_list[i]) == 0)
5483 {
5484 n = TRUE;
5485 break;
5486 }
5487
5488 if (n == FALSE)
5489 {
5490 if (STRNICMP(name, "patch", 5) == 0)
5491 {
5492 if (name[5] == '-'
5493 && STRLEN(name) >= 11
5494 && vim_isdigit(name[6])
5495 && vim_isdigit(name[8])
5496 && vim_isdigit(name[10]))
5497 {
5498 int major = atoi((char *)name + 6);
5499 int minor = atoi((char *)name + 8);
5500
5501 /* Expect "patch-9.9.01234". */
5502 n = (major < VIM_VERSION_MAJOR
5503 || (major == VIM_VERSION_MAJOR
5504 && (minor < VIM_VERSION_MINOR
5505 || (minor == VIM_VERSION_MINOR
5506 && has_patch(atoi((char *)name + 10))))));
5507 }
5508 else
5509 n = has_patch(atoi((char *)name + 5));
5510 }
5511 else if (STRICMP(name, "vim_starting") == 0)
5512 n = (starting != 0);
5513#ifdef FEAT_MBYTE
5514 else if (STRICMP(name, "multi_byte_encoding") == 0)
5515 n = has_mbyte;
5516#endif
5517#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
5518 else if (STRICMP(name, "balloon_multiline") == 0)
5519 n = multiline_balloon_available();
5520#endif
5521#ifdef DYNAMIC_TCL
5522 else if (STRICMP(name, "tcl") == 0)
5523 n = tcl_enabled(FALSE);
5524#endif
5525#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5526 else if (STRICMP(name, "iconv") == 0)
5527 n = iconv_enabled(FALSE);
5528#endif
5529#ifdef DYNAMIC_LUA
5530 else if (STRICMP(name, "lua") == 0)
5531 n = lua_enabled(FALSE);
5532#endif
5533#ifdef DYNAMIC_MZSCHEME
5534 else if (STRICMP(name, "mzscheme") == 0)
5535 n = mzscheme_enabled(FALSE);
5536#endif
5537#ifdef DYNAMIC_RUBY
5538 else if (STRICMP(name, "ruby") == 0)
5539 n = ruby_enabled(FALSE);
5540#endif
5541#ifdef FEAT_PYTHON
5542#ifdef DYNAMIC_PYTHON
5543 else if (STRICMP(name, "python") == 0)
5544 n = python_enabled(FALSE);
5545#endif
5546#endif
5547#ifdef FEAT_PYTHON3
5548#ifdef DYNAMIC_PYTHON3
5549 else if (STRICMP(name, "python3") == 0)
5550 n = python3_enabled(FALSE);
5551#endif
5552#endif
5553#ifdef DYNAMIC_PERL
5554 else if (STRICMP(name, "perl") == 0)
5555 n = perl_enabled(FALSE);
5556#endif
5557#ifdef FEAT_GUI
5558 else if (STRICMP(name, "gui_running") == 0)
5559 n = (gui.in_use || gui.starting);
5560# ifdef FEAT_GUI_W32
5561 else if (STRICMP(name, "gui_win32s") == 0)
5562 n = gui_is_win32s();
5563# endif
5564# ifdef FEAT_BROWSE
5565 else if (STRICMP(name, "browse") == 0)
5566 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5567# endif
5568#endif
5569#ifdef FEAT_SYN_HL
5570 else if (STRICMP(name, "syntax_items") == 0)
5571 n = syntax_present(curwin);
5572#endif
5573#if defined(WIN3264)
5574 else if (STRICMP(name, "win95") == 0)
5575 n = mch_windows95();
5576#endif
5577#ifdef FEAT_NETBEANS_INTG
5578 else if (STRICMP(name, "netbeans_enabled") == 0)
5579 n = netbeans_active();
5580#endif
5581 }
5582
5583 rettv->vval.v_number = n;
5584}
5585
5586/*
5587 * "has_key()" function
5588 */
5589 static void
5590f_has_key(typval_T *argvars, typval_T *rettv)
5591{
5592 if (argvars[0].v_type != VAR_DICT)
5593 {
5594 EMSG(_(e_dictreq));
5595 return;
5596 }
5597 if (argvars[0].vval.v_dict == NULL)
5598 return;
5599
5600 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
5601 get_tv_string(&argvars[1]), -1) != NULL;
5602}
5603
5604/*
5605 * "haslocaldir()" function
5606 */
5607 static void
5608f_haslocaldir(typval_T *argvars, typval_T *rettv)
5609{
5610 win_T *wp = NULL;
5611
5612 wp = find_tabwin(&argvars[0], &argvars[1]);
5613 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
5614}
5615
5616/*
5617 * "hasmapto()" function
5618 */
5619 static void
5620f_hasmapto(typval_T *argvars, typval_T *rettv)
5621{
5622 char_u *name;
5623 char_u *mode;
5624 char_u buf[NUMBUFLEN];
5625 int abbr = FALSE;
5626
5627 name = get_tv_string(&argvars[0]);
5628 if (argvars[1].v_type == VAR_UNKNOWN)
5629 mode = (char_u *)"nvo";
5630 else
5631 {
5632 mode = get_tv_string_buf(&argvars[1], buf);
5633 if (argvars[2].v_type != VAR_UNKNOWN)
5634 abbr = (int)get_tv_number(&argvars[2]);
5635 }
5636
5637 if (map_to_exists(name, mode, abbr))
5638 rettv->vval.v_number = TRUE;
5639 else
5640 rettv->vval.v_number = FALSE;
5641}
5642
5643/*
5644 * "histadd()" function
5645 */
5646 static void
5647f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
5648{
5649#ifdef FEAT_CMDHIST
5650 int histype;
5651 char_u *str;
5652 char_u buf[NUMBUFLEN];
5653#endif
5654
5655 rettv->vval.v_number = FALSE;
5656 if (check_restricted() || check_secure())
5657 return;
5658#ifdef FEAT_CMDHIST
5659 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5660 histype = str != NULL ? get_histtype(str) : -1;
5661 if (histype >= 0)
5662 {
5663 str = get_tv_string_buf(&argvars[1], buf);
5664 if (*str != NUL)
5665 {
5666 init_history();
5667 add_to_history(histype, str, FALSE, NUL);
5668 rettv->vval.v_number = TRUE;
5669 return;
5670 }
5671 }
5672#endif
5673}
5674
5675/*
5676 * "histdel()" function
5677 */
5678 static void
5679f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5680{
5681#ifdef FEAT_CMDHIST
5682 int n;
5683 char_u buf[NUMBUFLEN];
5684 char_u *str;
5685
5686 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5687 if (str == NULL)
5688 n = 0;
5689 else if (argvars[1].v_type == VAR_UNKNOWN)
5690 /* only one argument: clear entire history */
5691 n = clr_history(get_histtype(str));
5692 else if (argvars[1].v_type == VAR_NUMBER)
5693 /* index given: remove that entry */
5694 n = del_history_idx(get_histtype(str),
5695 (int)get_tv_number(&argvars[1]));
5696 else
5697 /* string given: remove all matching entries */
5698 n = del_history_entry(get_histtype(str),
5699 get_tv_string_buf(&argvars[1], buf));
5700 rettv->vval.v_number = n;
5701#endif
5702}
5703
5704/*
5705 * "histget()" function
5706 */
5707 static void
5708f_histget(typval_T *argvars UNUSED, typval_T *rettv)
5709{
5710#ifdef FEAT_CMDHIST
5711 int type;
5712 int idx;
5713 char_u *str;
5714
5715 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5716 if (str == NULL)
5717 rettv->vval.v_string = NULL;
5718 else
5719 {
5720 type = get_histtype(str);
5721 if (argvars[1].v_type == VAR_UNKNOWN)
5722 idx = get_history_idx(type);
5723 else
5724 idx = (int)get_tv_number_chk(&argvars[1], NULL);
5725 /* -1 on type error */
5726 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
5727 }
5728#else
5729 rettv->vval.v_string = NULL;
5730#endif
5731 rettv->v_type = VAR_STRING;
5732}
5733
5734/*
5735 * "histnr()" function
5736 */
5737 static void
5738f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
5739{
5740 int i;
5741
5742#ifdef FEAT_CMDHIST
5743 char_u *history = get_tv_string_chk(&argvars[0]);
5744
5745 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
5746 if (i >= HIST_CMD && i < HIST_COUNT)
5747 i = get_history_idx(i);
5748 else
5749#endif
5750 i = -1;
5751 rettv->vval.v_number = i;
5752}
5753
5754/*
5755 * "highlightID(name)" function
5756 */
5757 static void
5758f_hlID(typval_T *argvars, typval_T *rettv)
5759{
5760 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
5761}
5762
5763/*
5764 * "highlight_exists()" function
5765 */
5766 static void
5767f_hlexists(typval_T *argvars, typval_T *rettv)
5768{
5769 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
5770}
5771
5772/*
5773 * "hostname()" function
5774 */
5775 static void
5776f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5777{
5778 char_u hostname[256];
5779
5780 mch_get_host_name(hostname, 256);
5781 rettv->v_type = VAR_STRING;
5782 rettv->vval.v_string = vim_strsave(hostname);
5783}
5784
5785/*
5786 * iconv() function
5787 */
5788 static void
5789f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5790{
5791#ifdef FEAT_MBYTE
5792 char_u buf1[NUMBUFLEN];
5793 char_u buf2[NUMBUFLEN];
5794 char_u *from, *to, *str;
5795 vimconv_T vimconv;
5796#endif
5797
5798 rettv->v_type = VAR_STRING;
5799 rettv->vval.v_string = NULL;
5800
5801#ifdef FEAT_MBYTE
5802 str = get_tv_string(&argvars[0]);
5803 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
5804 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
5805 vimconv.vc_type = CONV_NONE;
5806 convert_setup(&vimconv, from, to);
5807
5808 /* If the encodings are equal, no conversion needed. */
5809 if (vimconv.vc_type == CONV_NONE)
5810 rettv->vval.v_string = vim_strsave(str);
5811 else
5812 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5813
5814 convert_setup(&vimconv, NULL, NULL);
5815 vim_free(from);
5816 vim_free(to);
5817#endif
5818}
5819
5820/*
5821 * "indent()" function
5822 */
5823 static void
5824f_indent(typval_T *argvars, typval_T *rettv)
5825{
5826 linenr_T lnum;
5827
5828 lnum = get_tv_lnum(argvars);
5829 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5830 rettv->vval.v_number = get_indent_lnum(lnum);
5831 else
5832 rettv->vval.v_number = -1;
5833}
5834
5835/*
5836 * "index()" function
5837 */
5838 static void
5839f_index(typval_T *argvars, typval_T *rettv)
5840{
5841 list_T *l;
5842 listitem_T *item;
5843 long idx = 0;
5844 int ic = FALSE;
5845
5846 rettv->vval.v_number = -1;
5847 if (argvars[0].v_type != VAR_LIST)
5848 {
5849 EMSG(_(e_listreq));
5850 return;
5851 }
5852 l = argvars[0].vval.v_list;
5853 if (l != NULL)
5854 {
5855 item = l->lv_first;
5856 if (argvars[2].v_type != VAR_UNKNOWN)
5857 {
5858 int error = FALSE;
5859
5860 /* Start at specified item. Use the cached index that list_find()
5861 * sets, so that a negative number also works. */
5862 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
5863 idx = l->lv_idx;
5864 if (argvars[3].v_type != VAR_UNKNOWN)
5865 ic = (int)get_tv_number_chk(&argvars[3], &error);
5866 if (error)
5867 item = NULL;
5868 }
5869
5870 for ( ; item != NULL; item = item->li_next, ++idx)
5871 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5872 {
5873 rettv->vval.v_number = idx;
5874 break;
5875 }
5876 }
5877}
5878
5879static int inputsecret_flag = 0;
5880
5881/*
5882 * "input()" function
5883 * Also handles inputsecret() when inputsecret is set.
5884 */
5885 static void
5886f_input(typval_T *argvars, typval_T *rettv)
5887{
5888 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5889}
5890
5891/*
5892 * "inputdialog()" function
5893 */
5894 static void
5895f_inputdialog(typval_T *argvars, typval_T *rettv)
5896{
5897#if defined(FEAT_GUI_TEXTDIALOG)
5898 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5899 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5900 {
5901 char_u *message;
5902 char_u buf[NUMBUFLEN];
5903 char_u *defstr = (char_u *)"";
5904
5905 message = get_tv_string_chk(&argvars[0]);
5906 if (argvars[1].v_type != VAR_UNKNOWN
5907 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
5908 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5909 else
5910 IObuff[0] = NUL;
5911 if (message != NULL && defstr != NULL
5912 && do_dialog(VIM_QUESTION, NULL, message,
5913 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5914 rettv->vval.v_string = vim_strsave(IObuff);
5915 else
5916 {
5917 if (message != NULL && defstr != NULL
5918 && argvars[1].v_type != VAR_UNKNOWN
5919 && argvars[2].v_type != VAR_UNKNOWN)
5920 rettv->vval.v_string = vim_strsave(
5921 get_tv_string_buf(&argvars[2], buf));
5922 else
5923 rettv->vval.v_string = NULL;
5924 }
5925 rettv->v_type = VAR_STRING;
5926 }
5927 else
5928#endif
5929 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5930}
5931
5932/*
5933 * "inputlist()" function
5934 */
5935 static void
5936f_inputlist(typval_T *argvars, typval_T *rettv)
5937{
5938 listitem_T *li;
5939 int selected;
5940 int mouse_used;
5941
5942#ifdef NO_CONSOLE_INPUT
5943 /* While starting up, there is no place to enter text. */
5944 if (no_console_input())
5945 return;
5946#endif
5947 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5948 {
5949 EMSG2(_(e_listarg), "inputlist()");
5950 return;
5951 }
5952
5953 msg_start();
5954 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
5955 lines_left = Rows; /* avoid more prompt */
5956 msg_scroll = TRUE;
5957 msg_clr_eos();
5958
5959 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
5960 {
5961 msg_puts(get_tv_string(&li->li_tv));
5962 msg_putchar('\n');
5963 }
5964
5965 /* Ask for choice. */
5966 selected = prompt_for_number(&mouse_used);
5967 if (mouse_used)
5968 selected -= lines_left;
5969
5970 rettv->vval.v_number = selected;
5971}
5972
5973
5974static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5975
5976/*
5977 * "inputrestore()" function
5978 */
5979 static void
5980f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5981{
5982 if (ga_userinput.ga_len > 0)
5983 {
5984 --ga_userinput.ga_len;
5985 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5986 + ga_userinput.ga_len);
5987 /* default return is zero == OK */
5988 }
5989 else if (p_verbose > 1)
5990 {
5991 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
5992 rettv->vval.v_number = 1; /* Failed */
5993 }
5994}
5995
5996/*
5997 * "inputsave()" function
5998 */
5999 static void
6000f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6001{
6002 /* Add an entry to the stack of typeahead storage. */
6003 if (ga_grow(&ga_userinput, 1) == OK)
6004 {
6005 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6006 + ga_userinput.ga_len);
6007 ++ga_userinput.ga_len;
6008 /* default return is zero == OK */
6009 }
6010 else
6011 rettv->vval.v_number = 1; /* Failed */
6012}
6013
6014/*
6015 * "inputsecret()" function
6016 */
6017 static void
6018f_inputsecret(typval_T *argvars, typval_T *rettv)
6019{
6020 ++cmdline_star;
6021 ++inputsecret_flag;
6022 f_input(argvars, rettv);
6023 --cmdline_star;
6024 --inputsecret_flag;
6025}
6026
6027/*
6028 * "insert()" function
6029 */
6030 static void
6031f_insert(typval_T *argvars, typval_T *rettv)
6032{
6033 long before = 0;
6034 listitem_T *item;
6035 list_T *l;
6036 int error = FALSE;
6037
6038 if (argvars[0].v_type != VAR_LIST)
6039 EMSG2(_(e_listarg), "insert()");
6040 else if ((l = argvars[0].vval.v_list) != NULL
6041 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6042 {
6043 if (argvars[2].v_type != VAR_UNKNOWN)
6044 before = (long)get_tv_number_chk(&argvars[2], &error);
6045 if (error)
6046 return; /* type error; errmsg already given */
6047
6048 if (before == l->lv_len)
6049 item = NULL;
6050 else
6051 {
6052 item = list_find(l, before);
6053 if (item == NULL)
6054 {
6055 EMSGN(_(e_listidx), before);
6056 l = NULL;
6057 }
6058 }
6059 if (l != NULL)
6060 {
6061 list_insert_tv(l, &argvars[1], item);
6062 copy_tv(&argvars[0], rettv);
6063 }
6064 }
6065}
6066
6067/*
6068 * "invert(expr)" function
6069 */
6070 static void
6071f_invert(typval_T *argvars, typval_T *rettv)
6072{
6073 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6074}
6075
6076/*
6077 * "isdirectory()" function
6078 */
6079 static void
6080f_isdirectory(typval_T *argvars, typval_T *rettv)
6081{
6082 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6083}
6084
6085/*
6086 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6087 * or it refers to a List or Dictionary that is locked.
6088 */
6089 static int
6090tv_islocked(typval_T *tv)
6091{
6092 return (tv->v_lock & VAR_LOCKED)
6093 || (tv->v_type == VAR_LIST
6094 && tv->vval.v_list != NULL
6095 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6096 || (tv->v_type == VAR_DICT
6097 && tv->vval.v_dict != NULL
6098 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6099}
6100
6101/*
6102 * "islocked()" function
6103 */
6104 static void
6105f_islocked(typval_T *argvars, typval_T *rettv)
6106{
6107 lval_T lv;
6108 char_u *end;
6109 dictitem_T *di;
6110
6111 rettv->vval.v_number = -1;
6112 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
6113 GLV_NO_AUTOLOAD, FNE_CHECK_START);
6114 if (end != NULL && lv.ll_name != NULL)
6115 {
6116 if (*end != NUL)
6117 EMSG(_(e_trailing));
6118 else
6119 {
6120 if (lv.ll_tv == NULL)
6121 {
6122 if (check_changedtick(lv.ll_name))
6123 rettv->vval.v_number = 1; /* always locked */
6124 else
6125 {
6126 di = find_var(lv.ll_name, NULL, TRUE);
6127 if (di != NULL)
6128 {
6129 /* Consider a variable locked when:
6130 * 1. the variable itself is locked
6131 * 2. the value of the variable is locked.
6132 * 3. the List or Dict value is locked.
6133 */
6134 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6135 || tv_islocked(&di->di_tv));
6136 }
6137 }
6138 }
6139 else if (lv.ll_range)
6140 EMSG(_("E786: Range not allowed"));
6141 else if (lv.ll_newkey != NULL)
6142 EMSG2(_(e_dictkey), lv.ll_newkey);
6143 else if (lv.ll_list != NULL)
6144 /* List item. */
6145 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6146 else
6147 /* Dictionary item. */
6148 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6149 }
6150 }
6151
6152 clear_lval(&lv);
6153}
6154
6155#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6156/*
6157 * "isnan()" function
6158 */
6159 static void
6160f_isnan(typval_T *argvars, typval_T *rettv)
6161{
6162 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6163 && isnan(argvars[0].vval.v_float);
6164}
6165#endif
6166
6167/*
6168 * "items(dict)" function
6169 */
6170 static void
6171f_items(typval_T *argvars, typval_T *rettv)
6172{
6173 dict_list(argvars, rettv, 2);
6174}
6175
6176#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6177/*
6178 * Get the job from the argument.
6179 * Returns NULL if the job is invalid.
6180 */
6181 static job_T *
6182get_job_arg(typval_T *tv)
6183{
6184 job_T *job;
6185
6186 if (tv->v_type != VAR_JOB)
6187 {
6188 EMSG2(_(e_invarg2), get_tv_string(tv));
6189 return NULL;
6190 }
6191 job = tv->vval.v_job;
6192
6193 if (job == NULL)
6194 EMSG(_("E916: not a valid job"));
6195 return job;
6196}
6197
6198/*
6199 * "job_getchannel()" function
6200 */
6201 static void
6202f_job_getchannel(typval_T *argvars, typval_T *rettv)
6203{
6204 job_T *job = get_job_arg(&argvars[0]);
6205
6206 if (job != NULL)
6207 {
6208 rettv->v_type = VAR_CHANNEL;
6209 rettv->vval.v_channel = job->jv_channel;
6210 if (job->jv_channel != NULL)
6211 ++job->jv_channel->ch_refcount;
6212 }
6213}
6214
6215/*
6216 * "job_info()" function
6217 */
6218 static void
6219f_job_info(typval_T *argvars, typval_T *rettv)
6220{
6221 job_T *job = get_job_arg(&argvars[0]);
6222
6223 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6224 job_info(job, rettv->vval.v_dict);
6225}
6226
6227/*
6228 * "job_setoptions()" function
6229 */
6230 static void
6231f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6232{
6233 job_T *job = get_job_arg(&argvars[0]);
6234 jobopt_T opt;
6235
6236 if (job == NULL)
6237 return;
6238 clear_job_options(&opt);
6239 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK)
6240 job_set_options(job, &opt);
6241 free_job_options(&opt);
6242}
6243
6244/*
6245 * "job_start()" function
6246 */
6247 static void
6248f_job_start(typval_T *argvars, typval_T *rettv)
6249{
6250 rettv->v_type = VAR_JOB;
6251 if (check_restricted() || check_secure())
6252 return;
6253 rettv->vval.v_job = job_start(argvars);
6254}
6255
6256/*
6257 * "job_status()" function
6258 */
6259 static void
6260f_job_status(typval_T *argvars, typval_T *rettv)
6261{
6262 job_T *job = get_job_arg(&argvars[0]);
6263
6264 if (job != NULL)
6265 {
6266 rettv->v_type = VAR_STRING;
6267 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6268 }
6269}
6270
6271/*
6272 * "job_stop()" function
6273 */
6274 static void
6275f_job_stop(typval_T *argvars, typval_T *rettv)
6276{
6277 job_T *job = get_job_arg(&argvars[0]);
6278
6279 if (job != NULL)
6280 rettv->vval.v_number = job_stop(job, argvars);
6281}
6282#endif
6283
6284/*
6285 * "join()" function
6286 */
6287 static void
6288f_join(typval_T *argvars, typval_T *rettv)
6289{
6290 garray_T ga;
6291 char_u *sep;
6292
6293 if (argvars[0].v_type != VAR_LIST)
6294 {
6295 EMSG(_(e_listreq));
6296 return;
6297 }
6298 if (argvars[0].vval.v_list == NULL)
6299 return;
6300 if (argvars[1].v_type == VAR_UNKNOWN)
6301 sep = (char_u *)" ";
6302 else
6303 sep = get_tv_string_chk(&argvars[1]);
6304
6305 rettv->v_type = VAR_STRING;
6306
6307 if (sep != NULL)
6308 {
6309 ga_init2(&ga, (int)sizeof(char), 80);
6310 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6311 ga_append(&ga, NUL);
6312 rettv->vval.v_string = (char_u *)ga.ga_data;
6313 }
6314 else
6315 rettv->vval.v_string = NULL;
6316}
6317
6318/*
6319 * "js_decode()" function
6320 */
6321 static void
6322f_js_decode(typval_T *argvars, typval_T *rettv)
6323{
6324 js_read_T reader;
6325
6326 reader.js_buf = get_tv_string(&argvars[0]);
6327 reader.js_fill = NULL;
6328 reader.js_used = 0;
6329 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6330 EMSG(_(e_invarg));
6331}
6332
6333/*
6334 * "js_encode()" function
6335 */
6336 static void
6337f_js_encode(typval_T *argvars, typval_T *rettv)
6338{
6339 rettv->v_type = VAR_STRING;
6340 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6341}
6342
6343/*
6344 * "json_decode()" function
6345 */
6346 static void
6347f_json_decode(typval_T *argvars, typval_T *rettv)
6348{
6349 js_read_T reader;
6350
6351 reader.js_buf = get_tv_string(&argvars[0]);
6352 reader.js_fill = NULL;
6353 reader.js_used = 0;
6354 if (json_decode_all(&reader, rettv, 0) != OK)
6355 EMSG(_(e_invarg));
6356}
6357
6358/*
6359 * "json_encode()" function
6360 */
6361 static void
6362f_json_encode(typval_T *argvars, typval_T *rettv)
6363{
6364 rettv->v_type = VAR_STRING;
6365 rettv->vval.v_string = json_encode(&argvars[0], 0);
6366}
6367
6368/*
6369 * "keys()" function
6370 */
6371 static void
6372f_keys(typval_T *argvars, typval_T *rettv)
6373{
6374 dict_list(argvars, rettv, 0);
6375}
6376
6377/*
6378 * "last_buffer_nr()" function.
6379 */
6380 static void
6381f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6382{
6383 int n = 0;
6384 buf_T *buf;
6385
Bram Moolenaar29323592016-07-24 22:04:11 +02006386 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387 if (n < buf->b_fnum)
6388 n = buf->b_fnum;
6389
6390 rettv->vval.v_number = n;
6391}
6392
6393/*
6394 * "len()" function
6395 */
6396 static void
6397f_len(typval_T *argvars, typval_T *rettv)
6398{
6399 switch (argvars[0].v_type)
6400 {
6401 case VAR_STRING:
6402 case VAR_NUMBER:
6403 rettv->vval.v_number = (varnumber_T)STRLEN(
6404 get_tv_string(&argvars[0]));
6405 break;
6406 case VAR_LIST:
6407 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6408 break;
6409 case VAR_DICT:
6410 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6411 break;
6412 case VAR_UNKNOWN:
6413 case VAR_SPECIAL:
6414 case VAR_FLOAT:
6415 case VAR_FUNC:
6416 case VAR_PARTIAL:
6417 case VAR_JOB:
6418 case VAR_CHANNEL:
6419 EMSG(_("E701: Invalid type for len()"));
6420 break;
6421 }
6422}
6423
6424static void libcall_common(typval_T *argvars, typval_T *rettv, int type);
6425
6426 static void
6427libcall_common(typval_T *argvars, typval_T *rettv, int type)
6428{
6429#ifdef FEAT_LIBCALL
6430 char_u *string_in;
6431 char_u **string_result;
6432 int nr_result;
6433#endif
6434
6435 rettv->v_type = type;
6436 if (type != VAR_NUMBER)
6437 rettv->vval.v_string = NULL;
6438
6439 if (check_restricted() || check_secure())
6440 return;
6441
6442#ifdef FEAT_LIBCALL
6443 /* The first two args must be strings, otherwise its meaningless */
6444 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6445 {
6446 string_in = NULL;
6447 if (argvars[2].v_type == VAR_STRING)
6448 string_in = argvars[2].vval.v_string;
6449 if (type == VAR_NUMBER)
6450 string_result = NULL;
6451 else
6452 string_result = &rettv->vval.v_string;
6453 if (mch_libcall(argvars[0].vval.v_string,
6454 argvars[1].vval.v_string,
6455 string_in,
6456 argvars[2].vval.v_number,
6457 string_result,
6458 &nr_result) == OK
6459 && type == VAR_NUMBER)
6460 rettv->vval.v_number = nr_result;
6461 }
6462#endif
6463}
6464
6465/*
6466 * "libcall()" function
6467 */
6468 static void
6469f_libcall(typval_T *argvars, typval_T *rettv)
6470{
6471 libcall_common(argvars, rettv, VAR_STRING);
6472}
6473
6474/*
6475 * "libcallnr()" function
6476 */
6477 static void
6478f_libcallnr(typval_T *argvars, typval_T *rettv)
6479{
6480 libcall_common(argvars, rettv, VAR_NUMBER);
6481}
6482
6483/*
6484 * "line(string)" function
6485 */
6486 static void
6487f_line(typval_T *argvars, typval_T *rettv)
6488{
6489 linenr_T lnum = 0;
6490 pos_T *fp;
6491 int fnum;
6492
6493 fp = var2fpos(&argvars[0], TRUE, &fnum);
6494 if (fp != NULL)
6495 lnum = fp->lnum;
6496 rettv->vval.v_number = lnum;
6497}
6498
6499/*
6500 * "line2byte(lnum)" function
6501 */
6502 static void
6503f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6504{
6505#ifndef FEAT_BYTEOFF
6506 rettv->vval.v_number = -1;
6507#else
6508 linenr_T lnum;
6509
6510 lnum = get_tv_lnum(argvars);
6511 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6512 rettv->vval.v_number = -1;
6513 else
6514 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6515 if (rettv->vval.v_number >= 0)
6516 ++rettv->vval.v_number;
6517#endif
6518}
6519
6520/*
6521 * "lispindent(lnum)" function
6522 */
6523 static void
6524f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
6525{
6526#ifdef FEAT_LISP
6527 pos_T pos;
6528 linenr_T lnum;
6529
6530 pos = curwin->w_cursor;
6531 lnum = get_tv_lnum(argvars);
6532 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6533 {
6534 curwin->w_cursor.lnum = lnum;
6535 rettv->vval.v_number = get_lisp_indent();
6536 curwin->w_cursor = pos;
6537 }
6538 else
6539#endif
6540 rettv->vval.v_number = -1;
6541}
6542
6543/*
6544 * "localtime()" function
6545 */
6546 static void
6547f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
6548{
6549 rettv->vval.v_number = (varnumber_T)time(NULL);
6550}
6551
6552static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
6553
6554 static void
6555get_maparg(typval_T *argvars, typval_T *rettv, int exact)
6556{
6557 char_u *keys;
6558 char_u *which;
6559 char_u buf[NUMBUFLEN];
6560 char_u *keys_buf = NULL;
6561 char_u *rhs;
6562 int mode;
6563 int abbr = FALSE;
6564 int get_dict = FALSE;
6565 mapblock_T *mp;
6566 int buffer_local;
6567
6568 /* return empty string for failure */
6569 rettv->v_type = VAR_STRING;
6570 rettv->vval.v_string = NULL;
6571
6572 keys = get_tv_string(&argvars[0]);
6573 if (*keys == NUL)
6574 return;
6575
6576 if (argvars[1].v_type != VAR_UNKNOWN)
6577 {
6578 which = get_tv_string_buf_chk(&argvars[1], buf);
6579 if (argvars[2].v_type != VAR_UNKNOWN)
6580 {
6581 abbr = (int)get_tv_number(&argvars[2]);
6582 if (argvars[3].v_type != VAR_UNKNOWN)
6583 get_dict = (int)get_tv_number(&argvars[3]);
6584 }
6585 }
6586 else
6587 which = (char_u *)"";
6588 if (which == NULL)
6589 return;
6590
6591 mode = get_map_mode(&which, 0);
6592
6593 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
6594 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
6595 vim_free(keys_buf);
6596
6597 if (!get_dict)
6598 {
6599 /* Return a string. */
6600 if (rhs != NULL)
6601 rettv->vval.v_string = str2special_save(rhs, FALSE);
6602
6603 }
6604 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
6605 {
6606 /* Return a dictionary. */
6607 char_u *lhs = str2special_save(mp->m_keys, TRUE);
6608 char_u *mapmode = map_mode_to_chars(mp->m_mode);
6609 dict_T *dict = rettv->vval.v_dict;
6610
6611 dict_add_nr_str(dict, "lhs", 0L, lhs);
6612 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
6613 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
6614 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
6615 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
6616 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
6617 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
6618 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
6619 dict_add_nr_str(dict, "mode", 0L, mapmode);
6620
6621 vim_free(lhs);
6622 vim_free(mapmode);
6623 }
6624}
6625
6626#ifdef FEAT_FLOAT
6627/*
6628 * "log()" function
6629 */
6630 static void
6631f_log(typval_T *argvars, typval_T *rettv)
6632{
6633 float_T f = 0.0;
6634
6635 rettv->v_type = VAR_FLOAT;
6636 if (get_float_arg(argvars, &f) == OK)
6637 rettv->vval.v_float = log(f);
6638 else
6639 rettv->vval.v_float = 0.0;
6640}
6641
6642/*
6643 * "log10()" function
6644 */
6645 static void
6646f_log10(typval_T *argvars, typval_T *rettv)
6647{
6648 float_T f = 0.0;
6649
6650 rettv->v_type = VAR_FLOAT;
6651 if (get_float_arg(argvars, &f) == OK)
6652 rettv->vval.v_float = log10(f);
6653 else
6654 rettv->vval.v_float = 0.0;
6655}
6656#endif
6657
6658#ifdef FEAT_LUA
6659/*
6660 * "luaeval()" function
6661 */
6662 static void
6663f_luaeval(typval_T *argvars, typval_T *rettv)
6664{
6665 char_u *str;
6666 char_u buf[NUMBUFLEN];
6667
6668 str = get_tv_string_buf(&argvars[0], buf);
6669 do_luaeval(str, argvars + 1, rettv);
6670}
6671#endif
6672
6673/*
6674 * "map()" function
6675 */
6676 static void
6677f_map(typval_T *argvars, typval_T *rettv)
6678{
6679 filter_map(argvars, rettv, TRUE);
6680}
6681
6682/*
6683 * "maparg()" function
6684 */
6685 static void
6686f_maparg(typval_T *argvars, typval_T *rettv)
6687{
6688 get_maparg(argvars, rettv, TRUE);
6689}
6690
6691/*
6692 * "mapcheck()" function
6693 */
6694 static void
6695f_mapcheck(typval_T *argvars, typval_T *rettv)
6696{
6697 get_maparg(argvars, rettv, FALSE);
6698}
6699
6700static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
6701
6702 static void
6703find_some_match(typval_T *argvars, typval_T *rettv, int type)
6704{
6705 char_u *str = NULL;
6706 long len = 0;
6707 char_u *expr = NULL;
6708 char_u *pat;
6709 regmatch_T regmatch;
6710 char_u patbuf[NUMBUFLEN];
6711 char_u strbuf[NUMBUFLEN];
6712 char_u *save_cpo;
6713 long start = 0;
6714 long nth = 1;
6715 colnr_T startcol = 0;
6716 int match = 0;
6717 list_T *l = NULL;
6718 listitem_T *li = NULL;
6719 long idx = 0;
6720 char_u *tofree = NULL;
6721
6722 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6723 save_cpo = p_cpo;
6724 p_cpo = (char_u *)"";
6725
6726 rettv->vval.v_number = -1;
6727 if (type == 3 || type == 4)
6728 {
6729 /* type 3: return empty list when there are no matches.
6730 * type 4: return ["", -1, -1, -1] */
6731 if (rettv_list_alloc(rettv) == FAIL)
6732 goto theend;
6733 if (type == 4
6734 && (list_append_string(rettv->vval.v_list,
6735 (char_u *)"", 0) == FAIL
6736 || list_append_number(rettv->vval.v_list,
6737 (varnumber_T)-1) == FAIL
6738 || list_append_number(rettv->vval.v_list,
6739 (varnumber_T)-1) == FAIL
6740 || list_append_number(rettv->vval.v_list,
6741 (varnumber_T)-1) == FAIL))
6742 {
6743 list_free(rettv->vval.v_list);
6744 rettv->vval.v_list = NULL;
6745 goto theend;
6746 }
6747 }
6748 else if (type == 2)
6749 {
6750 rettv->v_type = VAR_STRING;
6751 rettv->vval.v_string = NULL;
6752 }
6753
6754 if (argvars[0].v_type == VAR_LIST)
6755 {
6756 if ((l = argvars[0].vval.v_list) == NULL)
6757 goto theend;
6758 li = l->lv_first;
6759 }
6760 else
6761 {
6762 expr = str = get_tv_string(&argvars[0]);
6763 len = (long)STRLEN(str);
6764 }
6765
6766 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
6767 if (pat == NULL)
6768 goto theend;
6769
6770 if (argvars[2].v_type != VAR_UNKNOWN)
6771 {
6772 int error = FALSE;
6773
6774 start = (long)get_tv_number_chk(&argvars[2], &error);
6775 if (error)
6776 goto theend;
6777 if (l != NULL)
6778 {
6779 li = list_find(l, start);
6780 if (li == NULL)
6781 goto theend;
6782 idx = l->lv_idx; /* use the cached index */
6783 }
6784 else
6785 {
6786 if (start < 0)
6787 start = 0;
6788 if (start > len)
6789 goto theend;
6790 /* When "count" argument is there ignore matches before "start",
6791 * otherwise skip part of the string. Differs when pattern is "^"
6792 * or "\<". */
6793 if (argvars[3].v_type != VAR_UNKNOWN)
6794 startcol = start;
6795 else
6796 {
6797 str += start;
6798 len -= start;
6799 }
6800 }
6801
6802 if (argvars[3].v_type != VAR_UNKNOWN)
6803 nth = (long)get_tv_number_chk(&argvars[3], &error);
6804 if (error)
6805 goto theend;
6806 }
6807
6808 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6809 if (regmatch.regprog != NULL)
6810 {
6811 regmatch.rm_ic = p_ic;
6812
6813 for (;;)
6814 {
6815 if (l != NULL)
6816 {
6817 if (li == NULL)
6818 {
6819 match = FALSE;
6820 break;
6821 }
6822 vim_free(tofree);
6823 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6824 if (str == NULL)
6825 break;
6826 }
6827
6828 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6829
6830 if (match && --nth <= 0)
6831 break;
6832 if (l == NULL && !match)
6833 break;
6834
6835 /* Advance to just after the match. */
6836 if (l != NULL)
6837 {
6838 li = li->li_next;
6839 ++idx;
6840 }
6841 else
6842 {
6843#ifdef FEAT_MBYTE
6844 startcol = (colnr_T)(regmatch.startp[0]
6845 + (*mb_ptr2len)(regmatch.startp[0]) - str);
6846#else
6847 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
6848#endif
6849 if (startcol > (colnr_T)len
6850 || str + startcol <= regmatch.startp[0])
6851 {
6852 match = FALSE;
6853 break;
6854 }
6855 }
6856 }
6857
6858 if (match)
6859 {
6860 if (type == 4)
6861 {
6862 listitem_T *li1 = rettv->vval.v_list->lv_first;
6863 listitem_T *li2 = li1->li_next;
6864 listitem_T *li3 = li2->li_next;
6865 listitem_T *li4 = li3->li_next;
6866
6867 vim_free(li1->li_tv.vval.v_string);
6868 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
6869 (int)(regmatch.endp[0] - regmatch.startp[0]));
6870 li3->li_tv.vval.v_number =
6871 (varnumber_T)(regmatch.startp[0] - expr);
6872 li4->li_tv.vval.v_number =
6873 (varnumber_T)(regmatch.endp[0] - expr);
6874 if (l != NULL)
6875 li2->li_tv.vval.v_number = (varnumber_T)idx;
6876 }
6877 else if (type == 3)
6878 {
6879 int i;
6880
6881 /* return list with matched string and submatches */
6882 for (i = 0; i < NSUBEXP; ++i)
6883 {
6884 if (regmatch.endp[i] == NULL)
6885 {
6886 if (list_append_string(rettv->vval.v_list,
6887 (char_u *)"", 0) == FAIL)
6888 break;
6889 }
6890 else if (list_append_string(rettv->vval.v_list,
6891 regmatch.startp[i],
6892 (int)(regmatch.endp[i] - regmatch.startp[i]))
6893 == FAIL)
6894 break;
6895 }
6896 }
6897 else if (type == 2)
6898 {
6899 /* return matched string */
6900 if (l != NULL)
6901 copy_tv(&li->li_tv, rettv);
6902 else
6903 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
6904 (int)(regmatch.endp[0] - regmatch.startp[0]));
6905 }
6906 else if (l != NULL)
6907 rettv->vval.v_number = idx;
6908 else
6909 {
6910 if (type != 0)
6911 rettv->vval.v_number =
6912 (varnumber_T)(regmatch.startp[0] - str);
6913 else
6914 rettv->vval.v_number =
6915 (varnumber_T)(regmatch.endp[0] - str);
6916 rettv->vval.v_number += (varnumber_T)(str - expr);
6917 }
6918 }
6919 vim_regfree(regmatch.regprog);
6920 }
6921
6922 if (type == 4 && l == NULL)
6923 /* matchstrpos() without a list: drop the second item. */
6924 listitem_remove(rettv->vval.v_list,
6925 rettv->vval.v_list->lv_first->li_next);
6926
6927theend:
6928 vim_free(tofree);
6929 p_cpo = save_cpo;
6930}
6931
6932/*
6933 * "match()" function
6934 */
6935 static void
6936f_match(typval_T *argvars, typval_T *rettv)
6937{
6938 find_some_match(argvars, rettv, 1);
6939}
6940
6941/*
6942 * "matchadd()" function
6943 */
6944 static void
6945f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6946{
6947#ifdef FEAT_SEARCH_EXTRA
6948 char_u buf[NUMBUFLEN];
6949 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
6950 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
6951 int prio = 10; /* default priority */
6952 int id = -1;
6953 int error = FALSE;
6954 char_u *conceal_char = NULL;
6955
6956 rettv->vval.v_number = -1;
6957
6958 if (grp == NULL || pat == NULL)
6959 return;
6960 if (argvars[2].v_type != VAR_UNKNOWN)
6961 {
6962 prio = (int)get_tv_number_chk(&argvars[2], &error);
6963 if (argvars[3].v_type != VAR_UNKNOWN)
6964 {
6965 id = (int)get_tv_number_chk(&argvars[3], &error);
6966 if (argvars[4].v_type != VAR_UNKNOWN)
6967 {
6968 if (argvars[4].v_type != VAR_DICT)
6969 {
6970 EMSG(_(e_dictreq));
6971 return;
6972 }
6973 if (dict_find(argvars[4].vval.v_dict,
6974 (char_u *)"conceal", -1) != NULL)
6975 conceal_char = get_dict_string(argvars[4].vval.v_dict,
6976 (char_u *)"conceal", FALSE);
6977 }
6978 }
6979 }
6980 if (error == TRUE)
6981 return;
6982 if (id >= 1 && id <= 3)
6983 {
6984 EMSGN("E798: ID is reserved for \":match\": %ld", id);
6985 return;
6986 }
6987
6988 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
6989 conceal_char);
6990#endif
6991}
6992
6993/*
6994 * "matchaddpos()" function
6995 */
6996 static void
6997f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6998{
6999#ifdef FEAT_SEARCH_EXTRA
7000 char_u buf[NUMBUFLEN];
7001 char_u *group;
7002 int prio = 10;
7003 int id = -1;
7004 int error = FALSE;
7005 list_T *l;
7006 char_u *conceal_char = NULL;
7007
7008 rettv->vval.v_number = -1;
7009
7010 group = get_tv_string_buf_chk(&argvars[0], buf);
7011 if (group == NULL)
7012 return;
7013
7014 if (argvars[1].v_type != VAR_LIST)
7015 {
7016 EMSG2(_(e_listarg), "matchaddpos()");
7017 return;
7018 }
7019 l = argvars[1].vval.v_list;
7020 if (l == NULL)
7021 return;
7022
7023 if (argvars[2].v_type != VAR_UNKNOWN)
7024 {
7025 prio = (int)get_tv_number_chk(&argvars[2], &error);
7026 if (argvars[3].v_type != VAR_UNKNOWN)
7027 {
7028 id = (int)get_tv_number_chk(&argvars[3], &error);
7029 if (argvars[4].v_type != VAR_UNKNOWN)
7030 {
7031 if (argvars[4].v_type != VAR_DICT)
7032 {
7033 EMSG(_(e_dictreq));
7034 return;
7035 }
7036 if (dict_find(argvars[4].vval.v_dict,
7037 (char_u *)"conceal", -1) != NULL)
7038 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7039 (char_u *)"conceal", FALSE);
7040 }
7041 }
7042 }
7043 if (error == TRUE)
7044 return;
7045
7046 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7047 if (id == 1 || id == 2)
7048 {
7049 EMSGN("E798: ID is reserved for \":match\": %ld", id);
7050 return;
7051 }
7052
7053 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7054 conceal_char);
7055#endif
7056}
7057
7058/*
7059 * "matcharg()" function
7060 */
7061 static void
7062f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7063{
7064 if (rettv_list_alloc(rettv) == OK)
7065 {
7066#ifdef FEAT_SEARCH_EXTRA
7067 int id = (int)get_tv_number(&argvars[0]);
7068 matchitem_T *m;
7069
7070 if (id >= 1 && id <= 3)
7071 {
7072 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7073 {
7074 list_append_string(rettv->vval.v_list,
7075 syn_id2name(m->hlg_id), -1);
7076 list_append_string(rettv->vval.v_list, m->pattern, -1);
7077 }
7078 else
7079 {
7080 list_append_string(rettv->vval.v_list, NULL, -1);
7081 list_append_string(rettv->vval.v_list, NULL, -1);
7082 }
7083 }
7084#endif
7085 }
7086}
7087
7088/*
7089 * "matchdelete()" function
7090 */
7091 static void
7092f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7093{
7094#ifdef FEAT_SEARCH_EXTRA
7095 rettv->vval.v_number = match_delete(curwin,
7096 (int)get_tv_number(&argvars[0]), TRUE);
7097#endif
7098}
7099
7100/*
7101 * "matchend()" function
7102 */
7103 static void
7104f_matchend(typval_T *argvars, typval_T *rettv)
7105{
7106 find_some_match(argvars, rettv, 0);
7107}
7108
7109/*
7110 * "matchlist()" function
7111 */
7112 static void
7113f_matchlist(typval_T *argvars, typval_T *rettv)
7114{
7115 find_some_match(argvars, rettv, 3);
7116}
7117
7118/*
7119 * "matchstr()" function
7120 */
7121 static void
7122f_matchstr(typval_T *argvars, typval_T *rettv)
7123{
7124 find_some_match(argvars, rettv, 2);
7125}
7126
7127/*
7128 * "matchstrpos()" function
7129 */
7130 static void
7131f_matchstrpos(typval_T *argvars, typval_T *rettv)
7132{
7133 find_some_match(argvars, rettv, 4);
7134}
7135
7136static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7137
7138 static void
7139max_min(typval_T *argvars, typval_T *rettv, int domax)
7140{
7141 varnumber_T n = 0;
7142 varnumber_T i;
7143 int error = FALSE;
7144
7145 if (argvars[0].v_type == VAR_LIST)
7146 {
7147 list_T *l;
7148 listitem_T *li;
7149
7150 l = argvars[0].vval.v_list;
7151 if (l != NULL)
7152 {
7153 li = l->lv_first;
7154 if (li != NULL)
7155 {
7156 n = get_tv_number_chk(&li->li_tv, &error);
7157 for (;;)
7158 {
7159 li = li->li_next;
7160 if (li == NULL)
7161 break;
7162 i = get_tv_number_chk(&li->li_tv, &error);
7163 if (domax ? i > n : i < n)
7164 n = i;
7165 }
7166 }
7167 }
7168 }
7169 else if (argvars[0].v_type == VAR_DICT)
7170 {
7171 dict_T *d;
7172 int first = TRUE;
7173 hashitem_T *hi;
7174 int todo;
7175
7176 d = argvars[0].vval.v_dict;
7177 if (d != NULL)
7178 {
7179 todo = (int)d->dv_hashtab.ht_used;
7180 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7181 {
7182 if (!HASHITEM_EMPTY(hi))
7183 {
7184 --todo;
7185 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7186 if (first)
7187 {
7188 n = i;
7189 first = FALSE;
7190 }
7191 else if (domax ? i > n : i < n)
7192 n = i;
7193 }
7194 }
7195 }
7196 }
7197 else
7198 EMSG(_(e_listdictarg));
7199 rettv->vval.v_number = error ? 0 : n;
7200}
7201
7202/*
7203 * "max()" function
7204 */
7205 static void
7206f_max(typval_T *argvars, typval_T *rettv)
7207{
7208 max_min(argvars, rettv, TRUE);
7209}
7210
7211/*
7212 * "min()" function
7213 */
7214 static void
7215f_min(typval_T *argvars, typval_T *rettv)
7216{
7217 max_min(argvars, rettv, FALSE);
7218}
7219
7220static int mkdir_recurse(char_u *dir, int prot);
7221
7222/*
7223 * Create the directory in which "dir" is located, and higher levels when
7224 * needed.
7225 */
7226 static int
7227mkdir_recurse(char_u *dir, int prot)
7228{
7229 char_u *p;
7230 char_u *updir;
7231 int r = FAIL;
7232
7233 /* Get end of directory name in "dir".
7234 * We're done when it's "/" or "c:/". */
7235 p = gettail_sep(dir);
7236 if (p <= get_past_head(dir))
7237 return OK;
7238
7239 /* If the directory exists we're done. Otherwise: create it.*/
7240 updir = vim_strnsave(dir, (int)(p - dir));
7241 if (updir == NULL)
7242 return FAIL;
7243 if (mch_isdir(updir))
7244 r = OK;
7245 else if (mkdir_recurse(updir, prot) == OK)
7246 r = vim_mkdir_emsg(updir, prot);
7247 vim_free(updir);
7248 return r;
7249}
7250
7251#ifdef vim_mkdir
7252/*
7253 * "mkdir()" function
7254 */
7255 static void
7256f_mkdir(typval_T *argvars, typval_T *rettv)
7257{
7258 char_u *dir;
7259 char_u buf[NUMBUFLEN];
7260 int prot = 0755;
7261
7262 rettv->vval.v_number = FAIL;
7263 if (check_restricted() || check_secure())
7264 return;
7265
7266 dir = get_tv_string_buf(&argvars[0], buf);
7267 if (*dir == NUL)
7268 rettv->vval.v_number = FAIL;
7269 else
7270 {
7271 if (*gettail(dir) == NUL)
7272 /* remove trailing slashes */
7273 *gettail_sep(dir) = NUL;
7274
7275 if (argvars[1].v_type != VAR_UNKNOWN)
7276 {
7277 if (argvars[2].v_type != VAR_UNKNOWN)
7278 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7279 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7280 mkdir_recurse(dir, prot);
7281 }
7282 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7283 }
7284}
7285#endif
7286
7287/*
7288 * "mode()" function
7289 */
7290 static void
7291f_mode(typval_T *argvars, typval_T *rettv)
7292{
7293 char_u buf[3];
7294
7295 buf[1] = NUL;
7296 buf[2] = NUL;
7297
7298 if (time_for_testing == 93784)
7299 {
7300 /* Testing the two-character code. */
7301 buf[0] = 'x';
7302 buf[1] = '!';
7303 }
7304 else if (VIsual_active)
7305 {
7306 if (VIsual_select)
7307 buf[0] = VIsual_mode + 's' - 'v';
7308 else
7309 buf[0] = VIsual_mode;
7310 }
7311 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7312 || State == CONFIRM)
7313 {
7314 buf[0] = 'r';
7315 if (State == ASKMORE)
7316 buf[1] = 'm';
7317 else if (State == CONFIRM)
7318 buf[1] = '?';
7319 }
7320 else if (State == EXTERNCMD)
7321 buf[0] = '!';
7322 else if (State & INSERT)
7323 {
7324#ifdef FEAT_VREPLACE
7325 if (State & VREPLACE_FLAG)
7326 {
7327 buf[0] = 'R';
7328 buf[1] = 'v';
7329 }
7330 else
7331#endif
7332 if (State & REPLACE_FLAG)
7333 buf[0] = 'R';
7334 else
7335 buf[0] = 'i';
7336 }
7337 else if (State & CMDLINE)
7338 {
7339 buf[0] = 'c';
7340 if (exmode_active)
7341 buf[1] = 'v';
7342 }
7343 else if (exmode_active)
7344 {
7345 buf[0] = 'c';
7346 buf[1] = 'e';
7347 }
7348 else
7349 {
7350 buf[0] = 'n';
7351 if (finish_op)
7352 buf[1] = 'o';
7353 }
7354
7355 /* Clear out the minor mode when the argument is not a non-zero number or
7356 * non-empty string. */
7357 if (!non_zero_arg(&argvars[0]))
7358 buf[1] = NUL;
7359
7360 rettv->vval.v_string = vim_strsave(buf);
7361 rettv->v_type = VAR_STRING;
7362}
7363
7364#if defined(FEAT_MZSCHEME) || defined(PROTO)
7365/*
7366 * "mzeval()" function
7367 */
7368 static void
7369f_mzeval(typval_T *argvars, typval_T *rettv)
7370{
7371 char_u *str;
7372 char_u buf[NUMBUFLEN];
7373
7374 str = get_tv_string_buf(&argvars[0], buf);
7375 do_mzeval(str, rettv);
7376}
7377
7378 void
7379mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7380{
7381 typval_T argvars[3];
7382
7383 argvars[0].v_type = VAR_STRING;
7384 argvars[0].vval.v_string = name;
7385 copy_tv(args, &argvars[1]);
7386 argvars[2].v_type = VAR_UNKNOWN;
7387 f_call(argvars, rettv);
7388 clear_tv(&argvars[1]);
7389}
7390#endif
7391
7392/*
7393 * "nextnonblank()" function
7394 */
7395 static void
7396f_nextnonblank(typval_T *argvars, typval_T *rettv)
7397{
7398 linenr_T lnum;
7399
7400 for (lnum = get_tv_lnum(argvars); ; ++lnum)
7401 {
7402 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7403 {
7404 lnum = 0;
7405 break;
7406 }
7407 if (*skipwhite(ml_get(lnum)) != NUL)
7408 break;
7409 }
7410 rettv->vval.v_number = lnum;
7411}
7412
7413/*
7414 * "nr2char()" function
7415 */
7416 static void
7417f_nr2char(typval_T *argvars, typval_T *rettv)
7418{
7419 char_u buf[NUMBUFLEN];
7420
7421#ifdef FEAT_MBYTE
7422 if (has_mbyte)
7423 {
7424 int utf8 = 0;
7425
7426 if (argvars[1].v_type != VAR_UNKNOWN)
7427 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7428 if (utf8)
7429 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7430 else
7431 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7432 }
7433 else
7434#endif
7435 {
7436 buf[0] = (char_u)get_tv_number(&argvars[0]);
7437 buf[1] = NUL;
7438 }
7439 rettv->v_type = VAR_STRING;
7440 rettv->vval.v_string = vim_strsave(buf);
7441}
7442
7443/*
7444 * "or(expr, expr)" function
7445 */
7446 static void
7447f_or(typval_T *argvars, typval_T *rettv)
7448{
7449 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
7450 | get_tv_number_chk(&argvars[1], NULL);
7451}
7452
7453/*
7454 * "pathshorten()" function
7455 */
7456 static void
7457f_pathshorten(typval_T *argvars, typval_T *rettv)
7458{
7459 char_u *p;
7460
7461 rettv->v_type = VAR_STRING;
7462 p = get_tv_string_chk(&argvars[0]);
7463 if (p == NULL)
7464 rettv->vval.v_string = NULL;
7465 else
7466 {
7467 p = vim_strsave(p);
7468 rettv->vval.v_string = p;
7469 if (p != NULL)
7470 shorten_dir(p);
7471 }
7472}
7473
7474#ifdef FEAT_PERL
7475/*
7476 * "perleval()" function
7477 */
7478 static void
7479f_perleval(typval_T *argvars, typval_T *rettv)
7480{
7481 char_u *str;
7482 char_u buf[NUMBUFLEN];
7483
7484 str = get_tv_string_buf(&argvars[0], buf);
7485 do_perleval(str, rettv);
7486}
7487#endif
7488
7489#ifdef FEAT_FLOAT
7490/*
7491 * "pow()" function
7492 */
7493 static void
7494f_pow(typval_T *argvars, typval_T *rettv)
7495{
7496 float_T fx = 0.0, fy = 0.0;
7497
7498 rettv->v_type = VAR_FLOAT;
7499 if (get_float_arg(argvars, &fx) == OK
7500 && get_float_arg(&argvars[1], &fy) == OK)
7501 rettv->vval.v_float = pow(fx, fy);
7502 else
7503 rettv->vval.v_float = 0.0;
7504}
7505#endif
7506
7507/*
7508 * "prevnonblank()" function
7509 */
7510 static void
7511f_prevnonblank(typval_T *argvars, typval_T *rettv)
7512{
7513 linenr_T lnum;
7514
7515 lnum = get_tv_lnum(argvars);
7516 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7517 lnum = 0;
7518 else
7519 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7520 --lnum;
7521 rettv->vval.v_number = lnum;
7522}
7523
7524/* This dummy va_list is here because:
7525 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7526 * - locally in the function results in a "used before set" warning
7527 * - using va_start() to initialize it gives "function with fixed args" error */
7528static va_list ap;
7529
7530/*
7531 * "printf()" function
7532 */
7533 static void
7534f_printf(typval_T *argvars, typval_T *rettv)
7535{
7536 char_u buf[NUMBUFLEN];
7537 int len;
7538 char_u *s;
7539 int saved_did_emsg = did_emsg;
7540 char *fmt;
7541
7542 rettv->v_type = VAR_STRING;
7543 rettv->vval.v_string = NULL;
7544
7545 /* Get the required length, allocate the buffer and do it for real. */
7546 did_emsg = FALSE;
7547 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
7548 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
7549 if (!did_emsg)
7550 {
7551 s = alloc(len + 1);
7552 if (s != NULL)
7553 {
7554 rettv->vval.v_string = s;
7555 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
7556 }
7557 }
7558 did_emsg |= saved_did_emsg;
7559}
7560
7561/*
7562 * "pumvisible()" function
7563 */
7564 static void
7565f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7566{
7567#ifdef FEAT_INS_EXPAND
7568 if (pum_visible())
7569 rettv->vval.v_number = 1;
7570#endif
7571}
7572
7573#ifdef FEAT_PYTHON3
7574/*
7575 * "py3eval()" function
7576 */
7577 static void
7578f_py3eval(typval_T *argvars, typval_T *rettv)
7579{
7580 char_u *str;
7581 char_u buf[NUMBUFLEN];
7582
7583 str = get_tv_string_buf(&argvars[0], buf);
7584 do_py3eval(str, rettv);
7585}
7586#endif
7587
7588#ifdef FEAT_PYTHON
7589/*
7590 * "pyeval()" function
7591 */
7592 static void
7593f_pyeval(typval_T *argvars, typval_T *rettv)
7594{
7595 char_u *str;
7596 char_u buf[NUMBUFLEN];
7597
7598 str = get_tv_string_buf(&argvars[0], buf);
7599 do_pyeval(str, rettv);
7600}
7601#endif
7602
7603/*
7604 * "range()" function
7605 */
7606 static void
7607f_range(typval_T *argvars, typval_T *rettv)
7608{
7609 varnumber_T start;
7610 varnumber_T end;
7611 varnumber_T stride = 1;
7612 varnumber_T i;
7613 int error = FALSE;
7614
7615 start = get_tv_number_chk(&argvars[0], &error);
7616 if (argvars[1].v_type == VAR_UNKNOWN)
7617 {
7618 end = start - 1;
7619 start = 0;
7620 }
7621 else
7622 {
7623 end = get_tv_number_chk(&argvars[1], &error);
7624 if (argvars[2].v_type != VAR_UNKNOWN)
7625 stride = get_tv_number_chk(&argvars[2], &error);
7626 }
7627
7628 if (error)
7629 return; /* type error; errmsg already given */
7630 if (stride == 0)
7631 EMSG(_("E726: Stride is zero"));
7632 else if (stride > 0 ? end + 1 < start : end - 1 > start)
7633 EMSG(_("E727: Start past end"));
7634 else
7635 {
7636 if (rettv_list_alloc(rettv) == OK)
7637 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7638 if (list_append_number(rettv->vval.v_list,
7639 (varnumber_T)i) == FAIL)
7640 break;
7641 }
7642}
7643
7644/*
7645 * "readfile()" function
7646 */
7647 static void
7648f_readfile(typval_T *argvars, typval_T *rettv)
7649{
7650 int binary = FALSE;
7651 int failed = FALSE;
7652 char_u *fname;
7653 FILE *fd;
7654 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
7655 int io_size = sizeof(buf);
7656 int readlen; /* size of last fread() */
7657 char_u *prev = NULL; /* previously read bytes, if any */
7658 long prevlen = 0; /* length of data in prev */
7659 long prevsize = 0; /* size of prev buffer */
7660 long maxline = MAXLNUM;
7661 long cnt = 0;
7662 char_u *p; /* position in buf */
7663 char_u *start; /* start of current line */
7664
7665 if (argvars[1].v_type != VAR_UNKNOWN)
7666 {
7667 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
7668 binary = TRUE;
7669 if (argvars[2].v_type != VAR_UNKNOWN)
7670 maxline = (long)get_tv_number(&argvars[2]);
7671 }
7672
7673 if (rettv_list_alloc(rettv) == FAIL)
7674 return;
7675
7676 /* Always open the file in binary mode, library functions have a mind of
7677 * their own about CR-LF conversion. */
7678 fname = get_tv_string(&argvars[0]);
7679 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
7680 {
7681 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
7682 return;
7683 }
7684
7685 while (cnt < maxline || maxline < 0)
7686 {
7687 readlen = (int)fread(buf, 1, io_size, fd);
7688
7689 /* This for loop processes what was read, but is also entered at end
7690 * of file so that either:
7691 * - an incomplete line gets written
7692 * - a "binary" file gets an empty line at the end if it ends in a
7693 * newline. */
7694 for (p = buf, start = buf;
7695 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
7696 ++p)
7697 {
7698 if (*p == '\n' || readlen <= 0)
7699 {
7700 listitem_T *li;
7701 char_u *s = NULL;
7702 long_u len = p - start;
7703
7704 /* Finished a line. Remove CRs before NL. */
7705 if (readlen > 0 && !binary)
7706 {
7707 while (len > 0 && start[len - 1] == '\r')
7708 --len;
7709 /* removal may cross back to the "prev" string */
7710 if (len == 0)
7711 while (prevlen > 0 && prev[prevlen - 1] == '\r')
7712 --prevlen;
7713 }
7714 if (prevlen == 0)
7715 s = vim_strnsave(start, (int)len);
7716 else
7717 {
7718 /* Change "prev" buffer to be the right size. This way
7719 * the bytes are only copied once, and very long lines are
7720 * allocated only once. */
7721 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
7722 {
7723 mch_memmove(s + prevlen, start, len);
7724 s[prevlen + len] = NUL;
7725 prev = NULL; /* the list will own the string */
7726 prevlen = prevsize = 0;
7727 }
7728 }
7729 if (s == NULL)
7730 {
7731 do_outofmem_msg((long_u) prevlen + len + 1);
7732 failed = TRUE;
7733 break;
7734 }
7735
7736 if ((li = listitem_alloc()) == NULL)
7737 {
7738 vim_free(s);
7739 failed = TRUE;
7740 break;
7741 }
7742 li->li_tv.v_type = VAR_STRING;
7743 li->li_tv.v_lock = 0;
7744 li->li_tv.vval.v_string = s;
7745 list_append(rettv->vval.v_list, li);
7746
7747 start = p + 1; /* step over newline */
7748 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
7749 break;
7750 }
7751 else if (*p == NUL)
7752 *p = '\n';
7753#ifdef FEAT_MBYTE
7754 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
7755 * when finding the BF and check the previous two bytes. */
7756 else if (*p == 0xbf && enc_utf8 && !binary)
7757 {
7758 /* Find the two bytes before the 0xbf. If p is at buf, or buf
7759 * + 1, these may be in the "prev" string. */
7760 char_u back1 = p >= buf + 1 ? p[-1]
7761 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
7762 char_u back2 = p >= buf + 2 ? p[-2]
7763 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
7764 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
7765
7766 if (back2 == 0xef && back1 == 0xbb)
7767 {
7768 char_u *dest = p - 2;
7769
7770 /* Usually a BOM is at the beginning of a file, and so at
7771 * the beginning of a line; then we can just step over it.
7772 */
7773 if (start == dest)
7774 start = p + 1;
7775 else
7776 {
7777 /* have to shuffle buf to close gap */
7778 int adjust_prevlen = 0;
7779
7780 if (dest < buf)
7781 {
7782 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
7783 dest = buf;
7784 }
7785 if (readlen > p - buf + 1)
7786 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
7787 readlen -= 3 - adjust_prevlen;
7788 prevlen -= adjust_prevlen;
7789 p = dest - 1;
7790 }
7791 }
7792 }
7793#endif
7794 } /* for */
7795
7796 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
7797 break;
7798 if (start < p)
7799 {
7800 /* There's part of a line in buf, store it in "prev". */
7801 if (p - start + prevlen >= prevsize)
7802 {
7803 /* need bigger "prev" buffer */
7804 char_u *newprev;
7805
7806 /* A common use case is ordinary text files and "prev" gets a
7807 * fragment of a line, so the first allocation is made
7808 * small, to avoid repeatedly 'allocing' large and
7809 * 'reallocing' small. */
7810 if (prevsize == 0)
7811 prevsize = (long)(p - start);
7812 else
7813 {
7814 long grow50pc = (prevsize * 3) / 2;
7815 long growmin = (long)((p - start) * 2 + prevlen);
7816 prevsize = grow50pc > growmin ? grow50pc : growmin;
7817 }
7818 newprev = prev == NULL ? alloc(prevsize)
7819 : vim_realloc(prev, prevsize);
7820 if (newprev == NULL)
7821 {
7822 do_outofmem_msg((long_u)prevsize);
7823 failed = TRUE;
7824 break;
7825 }
7826 prev = newprev;
7827 }
7828 /* Add the line part to end of "prev". */
7829 mch_memmove(prev + prevlen, start, p - start);
7830 prevlen += (long)(p - start);
7831 }
7832 } /* while */
7833
7834 /*
7835 * For a negative line count use only the lines at the end of the file,
7836 * free the rest.
7837 */
7838 if (!failed && maxline < 0)
7839 while (cnt > -maxline)
7840 {
7841 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
7842 --cnt;
7843 }
7844
7845 if (failed)
7846 {
7847 list_free(rettv->vval.v_list);
7848 /* readfile doc says an empty list is returned on error */
7849 rettv->vval.v_list = list_alloc();
7850 }
7851
7852 vim_free(prev);
7853 fclose(fd);
7854}
7855
7856#if defined(FEAT_RELTIME)
7857static int list2proftime(typval_T *arg, proftime_T *tm);
7858
7859/*
7860 * Convert a List to proftime_T.
7861 * Return FAIL when there is something wrong.
7862 */
7863 static int
7864list2proftime(typval_T *arg, proftime_T *tm)
7865{
7866 long n1, n2;
7867 int error = FALSE;
7868
7869 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
7870 || arg->vval.v_list->lv_len != 2)
7871 return FAIL;
7872 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
7873 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
7874# ifdef WIN3264
7875 tm->HighPart = n1;
7876 tm->LowPart = n2;
7877# else
7878 tm->tv_sec = n1;
7879 tm->tv_usec = n2;
7880# endif
7881 return error ? FAIL : OK;
7882}
7883#endif /* FEAT_RELTIME */
7884
7885/*
7886 * "reltime()" function
7887 */
7888 static void
7889f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7890{
7891#ifdef FEAT_RELTIME
7892 proftime_T res;
7893 proftime_T start;
7894
7895 if (argvars[0].v_type == VAR_UNKNOWN)
7896 {
7897 /* No arguments: get current time. */
7898 profile_start(&res);
7899 }
7900 else if (argvars[1].v_type == VAR_UNKNOWN)
7901 {
7902 if (list2proftime(&argvars[0], &res) == FAIL)
7903 return;
7904 profile_end(&res);
7905 }
7906 else
7907 {
7908 /* Two arguments: compute the difference. */
7909 if (list2proftime(&argvars[0], &start) == FAIL
7910 || list2proftime(&argvars[1], &res) == FAIL)
7911 return;
7912 profile_sub(&res, &start);
7913 }
7914
7915 if (rettv_list_alloc(rettv) == OK)
7916 {
7917 long n1, n2;
7918
7919# ifdef WIN3264
7920 n1 = res.HighPart;
7921 n2 = res.LowPart;
7922# else
7923 n1 = res.tv_sec;
7924 n2 = res.tv_usec;
7925# endif
7926 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
7927 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
7928 }
7929#endif
7930}
7931
7932#ifdef FEAT_FLOAT
7933/*
7934 * "reltimefloat()" function
7935 */
7936 static void
7937f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
7938{
7939# ifdef FEAT_RELTIME
7940 proftime_T tm;
7941# endif
7942
7943 rettv->v_type = VAR_FLOAT;
7944 rettv->vval.v_float = 0;
7945# ifdef FEAT_RELTIME
7946 if (list2proftime(&argvars[0], &tm) == OK)
7947 rettv->vval.v_float = profile_float(&tm);
7948# endif
7949}
7950#endif
7951
7952/*
7953 * "reltimestr()" function
7954 */
7955 static void
7956f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
7957{
7958#ifdef FEAT_RELTIME
7959 proftime_T tm;
7960#endif
7961
7962 rettv->v_type = VAR_STRING;
7963 rettv->vval.v_string = NULL;
7964#ifdef FEAT_RELTIME
7965 if (list2proftime(&argvars[0], &tm) == OK)
7966 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
7967#endif
7968}
7969
7970#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
7971static void make_connection(void);
7972static int check_connection(void);
7973
7974 static void
7975make_connection(void)
7976{
7977 if (X_DISPLAY == NULL
7978# ifdef FEAT_GUI
7979 && !gui.in_use
7980# endif
7981 )
7982 {
7983 x_force_connect = TRUE;
7984 setup_term_clip();
7985 x_force_connect = FALSE;
7986 }
7987}
7988
7989 static int
7990check_connection(void)
7991{
7992 make_connection();
7993 if (X_DISPLAY == NULL)
7994 {
7995 EMSG(_("E240: No connection to Vim server"));
7996 return FAIL;
7997 }
7998 return OK;
7999}
8000#endif
8001
8002#ifdef FEAT_CLIENTSERVER
8003 static void
8004remote_common(typval_T *argvars, typval_T *rettv, int expr)
8005{
8006 char_u *server_name;
8007 char_u *keys;
8008 char_u *r = NULL;
8009 char_u buf[NUMBUFLEN];
8010# ifdef WIN32
8011 HWND w;
8012# else
8013 Window w;
8014# endif
8015
8016 if (check_restricted() || check_secure())
8017 return;
8018
8019# ifdef FEAT_X11
8020 if (check_connection() == FAIL)
8021 return;
8022# endif
8023
8024 server_name = get_tv_string_chk(&argvars[0]);
8025 if (server_name == NULL)
8026 return; /* type error; errmsg already given */
8027 keys = get_tv_string_buf(&argvars[1], buf);
8028# ifdef WIN32
8029 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
8030# else
8031 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
8032 < 0)
8033# endif
8034 {
8035 if (r != NULL)
8036 EMSG(r); /* sending worked but evaluation failed */
8037 else
8038 EMSG2(_("E241: Unable to send to %s"), server_name);
8039 return;
8040 }
8041
8042 rettv->vval.v_string = r;
8043
8044 if (argvars[2].v_type != VAR_UNKNOWN)
8045 {
8046 dictitem_T v;
8047 char_u str[30];
8048 char_u *idvar;
8049
8050 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8051 v.di_tv.v_type = VAR_STRING;
8052 v.di_tv.vval.v_string = vim_strsave(str);
8053 idvar = get_tv_string_chk(&argvars[2]);
8054 if (idvar != NULL)
8055 set_var(idvar, &v.di_tv, FALSE);
8056 vim_free(v.di_tv.vval.v_string);
8057 }
8058}
8059#endif
8060
8061/*
8062 * "remote_expr()" function
8063 */
8064 static void
8065f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8066{
8067 rettv->v_type = VAR_STRING;
8068 rettv->vval.v_string = NULL;
8069#ifdef FEAT_CLIENTSERVER
8070 remote_common(argvars, rettv, TRUE);
8071#endif
8072}
8073
8074/*
8075 * "remote_foreground()" function
8076 */
8077 static void
8078f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8079{
8080#ifdef FEAT_CLIENTSERVER
8081# ifdef WIN32
8082 /* On Win32 it's done in this application. */
8083 {
8084 char_u *server_name = get_tv_string_chk(&argvars[0]);
8085
8086 if (server_name != NULL)
8087 serverForeground(server_name);
8088 }
8089# else
8090 /* Send a foreground() expression to the server. */
8091 argvars[1].v_type = VAR_STRING;
8092 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8093 argvars[2].v_type = VAR_UNKNOWN;
8094 remote_common(argvars, rettv, TRUE);
8095 vim_free(argvars[1].vval.v_string);
8096# endif
8097#endif
8098}
8099
8100 static void
8101f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8102{
8103#ifdef FEAT_CLIENTSERVER
8104 dictitem_T v;
8105 char_u *s = NULL;
8106# ifdef WIN32
8107 long_u n = 0;
8108# endif
8109 char_u *serverid;
8110
8111 if (check_restricted() || check_secure())
8112 {
8113 rettv->vval.v_number = -1;
8114 return;
8115 }
8116 serverid = get_tv_string_chk(&argvars[0]);
8117 if (serverid == NULL)
8118 {
8119 rettv->vval.v_number = -1;
8120 return; /* type error; errmsg already given */
8121 }
8122# ifdef WIN32
8123 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8124 if (n == 0)
8125 rettv->vval.v_number = -1;
8126 else
8127 {
8128 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
8129 rettv->vval.v_number = (s != NULL);
8130 }
8131# else
8132 if (check_connection() == FAIL)
8133 return;
8134
8135 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8136 serverStrToWin(serverid), &s);
8137# endif
8138
8139 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8140 {
8141 char_u *retvar;
8142
8143 v.di_tv.v_type = VAR_STRING;
8144 v.di_tv.vval.v_string = vim_strsave(s);
8145 retvar = get_tv_string_chk(&argvars[1]);
8146 if (retvar != NULL)
8147 set_var(retvar, &v.di_tv, FALSE);
8148 vim_free(v.di_tv.vval.v_string);
8149 }
8150#else
8151 rettv->vval.v_number = -1;
8152#endif
8153}
8154
8155 static void
8156f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8157{
8158 char_u *r = NULL;
8159
8160#ifdef FEAT_CLIENTSERVER
8161 char_u *serverid = get_tv_string_chk(&argvars[0]);
8162
8163 if (serverid != NULL && !check_restricted() && !check_secure())
8164 {
8165# ifdef WIN32
8166 /* The server's HWND is encoded in the 'id' parameter */
8167 long_u n = 0;
8168
8169 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8170 if (n != 0)
8171 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
8172 if (r == NULL)
8173# else
8174 if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
8175 serverStrToWin(serverid), &r, FALSE) < 0)
8176# endif
8177 EMSG(_("E277: Unable to read a server reply"));
8178 }
8179#endif
8180 rettv->v_type = VAR_STRING;
8181 rettv->vval.v_string = r;
8182}
8183
8184/*
8185 * "remote_send()" function
8186 */
8187 static void
8188f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8189{
8190 rettv->v_type = VAR_STRING;
8191 rettv->vval.v_string = NULL;
8192#ifdef FEAT_CLIENTSERVER
8193 remote_common(argvars, rettv, FALSE);
8194#endif
8195}
8196
8197/*
8198 * "remove()" function
8199 */
8200 static void
8201f_remove(typval_T *argvars, typval_T *rettv)
8202{
8203 list_T *l;
8204 listitem_T *item, *item2;
8205 listitem_T *li;
8206 long idx;
8207 long end;
8208 char_u *key;
8209 dict_T *d;
8210 dictitem_T *di;
8211 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8212
8213 if (argvars[0].v_type == VAR_DICT)
8214 {
8215 if (argvars[2].v_type != VAR_UNKNOWN)
8216 EMSG2(_(e_toomanyarg), "remove()");
8217 else if ((d = argvars[0].vval.v_dict) != NULL
8218 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8219 {
8220 key = get_tv_string_chk(&argvars[1]);
8221 if (key != NULL)
8222 {
8223 di = dict_find(d, key, -1);
8224 if (di == NULL)
8225 EMSG2(_(e_dictkey), key);
8226 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8227 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8228 {
8229 *rettv = di->di_tv;
8230 init_tv(&di->di_tv);
8231 dictitem_remove(d, di);
8232 }
8233 }
8234 }
8235 }
8236 else if (argvars[0].v_type != VAR_LIST)
8237 EMSG2(_(e_listdictarg), "remove()");
8238 else if ((l = argvars[0].vval.v_list) != NULL
8239 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8240 {
8241 int error = FALSE;
8242
8243 idx = (long)get_tv_number_chk(&argvars[1], &error);
8244 if (error)
8245 ; /* type error: do nothing, errmsg already given */
8246 else if ((item = list_find(l, idx)) == NULL)
8247 EMSGN(_(e_listidx), idx);
8248 else
8249 {
8250 if (argvars[2].v_type == VAR_UNKNOWN)
8251 {
8252 /* Remove one item, return its value. */
8253 vimlist_remove(l, item, item);
8254 *rettv = item->li_tv;
8255 vim_free(item);
8256 }
8257 else
8258 {
8259 /* Remove range of items, return list with values. */
8260 end = (long)get_tv_number_chk(&argvars[2], &error);
8261 if (error)
8262 ; /* type error: do nothing */
8263 else if ((item2 = list_find(l, end)) == NULL)
8264 EMSGN(_(e_listidx), end);
8265 else
8266 {
8267 int cnt = 0;
8268
8269 for (li = item; li != NULL; li = li->li_next)
8270 {
8271 ++cnt;
8272 if (li == item2)
8273 break;
8274 }
8275 if (li == NULL) /* didn't find "item2" after "item" */
8276 EMSG(_(e_invrange));
8277 else
8278 {
8279 vimlist_remove(l, item, item2);
8280 if (rettv_list_alloc(rettv) == OK)
8281 {
8282 l = rettv->vval.v_list;
8283 l->lv_first = item;
8284 l->lv_last = item2;
8285 item->li_prev = NULL;
8286 item2->li_next = NULL;
8287 l->lv_len = cnt;
8288 }
8289 }
8290 }
8291 }
8292 }
8293 }
8294}
8295
8296/*
8297 * "rename({from}, {to})" function
8298 */
8299 static void
8300f_rename(typval_T *argvars, typval_T *rettv)
8301{
8302 char_u buf[NUMBUFLEN];
8303
8304 if (check_restricted() || check_secure())
8305 rettv->vval.v_number = -1;
8306 else
8307 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8308 get_tv_string_buf(&argvars[1], buf));
8309}
8310
8311/*
8312 * "repeat()" function
8313 */
8314 static void
8315f_repeat(typval_T *argvars, typval_T *rettv)
8316{
8317 char_u *p;
8318 int n;
8319 int slen;
8320 int len;
8321 char_u *r;
8322 int i;
8323
8324 n = (int)get_tv_number(&argvars[1]);
8325 if (argvars[0].v_type == VAR_LIST)
8326 {
8327 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8328 while (n-- > 0)
8329 if (list_extend(rettv->vval.v_list,
8330 argvars[0].vval.v_list, NULL) == FAIL)
8331 break;
8332 }
8333 else
8334 {
8335 p = get_tv_string(&argvars[0]);
8336 rettv->v_type = VAR_STRING;
8337 rettv->vval.v_string = NULL;
8338
8339 slen = (int)STRLEN(p);
8340 len = slen * n;
8341 if (len <= 0)
8342 return;
8343
8344 r = alloc(len + 1);
8345 if (r != NULL)
8346 {
8347 for (i = 0; i < n; i++)
8348 mch_memmove(r + i * slen, p, (size_t)slen);
8349 r[len] = NUL;
8350 }
8351
8352 rettv->vval.v_string = r;
8353 }
8354}
8355
8356/*
8357 * "resolve()" function
8358 */
8359 static void
8360f_resolve(typval_T *argvars, typval_T *rettv)
8361{
8362 char_u *p;
8363#ifdef HAVE_READLINK
8364 char_u *buf = NULL;
8365#endif
8366
8367 p = get_tv_string(&argvars[0]);
8368#ifdef FEAT_SHORTCUT
8369 {
8370 char_u *v = NULL;
8371
8372 v = mch_resolve_shortcut(p);
8373 if (v != NULL)
8374 rettv->vval.v_string = v;
8375 else
8376 rettv->vval.v_string = vim_strsave(p);
8377 }
8378#else
8379# ifdef HAVE_READLINK
8380 {
8381 char_u *cpy;
8382 int len;
8383 char_u *remain = NULL;
8384 char_u *q;
8385 int is_relative_to_current = FALSE;
8386 int has_trailing_pathsep = FALSE;
8387 int limit = 100;
8388
8389 p = vim_strsave(p);
8390
8391 if (p[0] == '.' && (vim_ispathsep(p[1])
8392 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8393 is_relative_to_current = TRUE;
8394
8395 len = STRLEN(p);
8396 if (len > 0 && after_pathsep(p, p + len))
8397 {
8398 has_trailing_pathsep = TRUE;
8399 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8400 }
8401
8402 q = getnextcomp(p);
8403 if (*q != NUL)
8404 {
8405 /* Separate the first path component in "p", and keep the
8406 * remainder (beginning with the path separator). */
8407 remain = vim_strsave(q - 1);
8408 q[-1] = NUL;
8409 }
8410
8411 buf = alloc(MAXPATHL + 1);
8412 if (buf == NULL)
8413 goto fail;
8414
8415 for (;;)
8416 {
8417 for (;;)
8418 {
8419 len = readlink((char *)p, (char *)buf, MAXPATHL);
8420 if (len <= 0)
8421 break;
8422 buf[len] = NUL;
8423
8424 if (limit-- == 0)
8425 {
8426 vim_free(p);
8427 vim_free(remain);
8428 EMSG(_("E655: Too many symbolic links (cycle?)"));
8429 rettv->vval.v_string = NULL;
8430 goto fail;
8431 }
8432
8433 /* Ensure that the result will have a trailing path separator
8434 * if the argument has one. */
8435 if (remain == NULL && has_trailing_pathsep)
8436 add_pathsep(buf);
8437
8438 /* Separate the first path component in the link value and
8439 * concatenate the remainders. */
8440 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8441 if (*q != NUL)
8442 {
8443 if (remain == NULL)
8444 remain = vim_strsave(q - 1);
8445 else
8446 {
8447 cpy = concat_str(q - 1, remain);
8448 if (cpy != NULL)
8449 {
8450 vim_free(remain);
8451 remain = cpy;
8452 }
8453 }
8454 q[-1] = NUL;
8455 }
8456
8457 q = gettail(p);
8458 if (q > p && *q == NUL)
8459 {
8460 /* Ignore trailing path separator. */
8461 q[-1] = NUL;
8462 q = gettail(p);
8463 }
8464 if (q > p && !mch_isFullName(buf))
8465 {
8466 /* symlink is relative to directory of argument */
8467 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
8468 if (cpy != NULL)
8469 {
8470 STRCPY(cpy, p);
8471 STRCPY(gettail(cpy), buf);
8472 vim_free(p);
8473 p = cpy;
8474 }
8475 }
8476 else
8477 {
8478 vim_free(p);
8479 p = vim_strsave(buf);
8480 }
8481 }
8482
8483 if (remain == NULL)
8484 break;
8485
8486 /* Append the first path component of "remain" to "p". */
8487 q = getnextcomp(remain + 1);
8488 len = q - remain - (*q != NUL);
8489 cpy = vim_strnsave(p, STRLEN(p) + len);
8490 if (cpy != NULL)
8491 {
8492 STRNCAT(cpy, remain, len);
8493 vim_free(p);
8494 p = cpy;
8495 }
8496 /* Shorten "remain". */
8497 if (*q != NUL)
8498 STRMOVE(remain, q - 1);
8499 else
8500 {
8501 vim_free(remain);
8502 remain = NULL;
8503 }
8504 }
8505
8506 /* If the result is a relative path name, make it explicitly relative to
8507 * the current directory if and only if the argument had this form. */
8508 if (!vim_ispathsep(*p))
8509 {
8510 if (is_relative_to_current
8511 && *p != NUL
8512 && !(p[0] == '.'
8513 && (p[1] == NUL
8514 || vim_ispathsep(p[1])
8515 || (p[1] == '.'
8516 && (p[2] == NUL
8517 || vim_ispathsep(p[2]))))))
8518 {
8519 /* Prepend "./". */
8520 cpy = concat_str((char_u *)"./", p);
8521 if (cpy != NULL)
8522 {
8523 vim_free(p);
8524 p = cpy;
8525 }
8526 }
8527 else if (!is_relative_to_current)
8528 {
8529 /* Strip leading "./". */
8530 q = p;
8531 while (q[0] == '.' && vim_ispathsep(q[1]))
8532 q += 2;
8533 if (q > p)
8534 STRMOVE(p, p + 2);
8535 }
8536 }
8537
8538 /* Ensure that the result will have no trailing path separator
8539 * if the argument had none. But keep "/" or "//". */
8540 if (!has_trailing_pathsep)
8541 {
8542 q = p + STRLEN(p);
8543 if (after_pathsep(p, q))
8544 *gettail_sep(p) = NUL;
8545 }
8546
8547 rettv->vval.v_string = p;
8548 }
8549# else
8550 rettv->vval.v_string = vim_strsave(p);
8551# endif
8552#endif
8553
8554 simplify_filename(rettv->vval.v_string);
8555
8556#ifdef HAVE_READLINK
8557fail:
8558 vim_free(buf);
8559#endif
8560 rettv->v_type = VAR_STRING;
8561}
8562
8563/*
8564 * "reverse({list})" function
8565 */
8566 static void
8567f_reverse(typval_T *argvars, typval_T *rettv)
8568{
8569 list_T *l;
8570 listitem_T *li, *ni;
8571
8572 if (argvars[0].v_type != VAR_LIST)
8573 EMSG2(_(e_listarg), "reverse()");
8574 else if ((l = argvars[0].vval.v_list) != NULL
8575 && !tv_check_lock(l->lv_lock,
8576 (char_u *)N_("reverse() argument"), TRUE))
8577 {
8578 li = l->lv_last;
8579 l->lv_first = l->lv_last = NULL;
8580 l->lv_len = 0;
8581 while (li != NULL)
8582 {
8583 ni = li->li_prev;
8584 list_append(l, li);
8585 li = ni;
8586 }
8587 rettv->vval.v_list = l;
8588 rettv->v_type = VAR_LIST;
8589 ++l->lv_refcount;
8590 l->lv_idx = l->lv_len - l->lv_idx - 1;
8591 }
8592}
8593
8594#define SP_NOMOVE 0x01 /* don't move cursor */
8595#define SP_REPEAT 0x02 /* repeat to find outer pair */
8596#define SP_RETCOUNT 0x04 /* return matchcount */
8597#define SP_SETPCMARK 0x08 /* set previous context mark */
8598#define SP_START 0x10 /* accept match at start position */
8599#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
8600#define SP_END 0x40 /* leave cursor at end of match */
8601#define SP_COLUMN 0x80 /* start at cursor column */
8602
8603static int get_search_arg(typval_T *varp, int *flagsp);
8604
8605/*
8606 * Get flags for a search function.
8607 * Possibly sets "p_ws".
8608 * Returns BACKWARD, FORWARD or zero (for an error).
8609 */
8610 static int
8611get_search_arg(typval_T *varp, int *flagsp)
8612{
8613 int dir = FORWARD;
8614 char_u *flags;
8615 char_u nbuf[NUMBUFLEN];
8616 int mask;
8617
8618 if (varp->v_type != VAR_UNKNOWN)
8619 {
8620 flags = get_tv_string_buf_chk(varp, nbuf);
8621 if (flags == NULL)
8622 return 0; /* type error; errmsg already given */
8623 while (*flags != NUL)
8624 {
8625 switch (*flags)
8626 {
8627 case 'b': dir = BACKWARD; break;
8628 case 'w': p_ws = TRUE; break;
8629 case 'W': p_ws = FALSE; break;
8630 default: mask = 0;
8631 if (flagsp != NULL)
8632 switch (*flags)
8633 {
8634 case 'c': mask = SP_START; break;
8635 case 'e': mask = SP_END; break;
8636 case 'm': mask = SP_RETCOUNT; break;
8637 case 'n': mask = SP_NOMOVE; break;
8638 case 'p': mask = SP_SUBPAT; break;
8639 case 'r': mask = SP_REPEAT; break;
8640 case 's': mask = SP_SETPCMARK; break;
8641 case 'z': mask = SP_COLUMN; break;
8642 }
8643 if (mask == 0)
8644 {
8645 EMSG2(_(e_invarg2), flags);
8646 dir = 0;
8647 }
8648 else
8649 *flagsp |= mask;
8650 }
8651 if (dir == 0)
8652 break;
8653 ++flags;
8654 }
8655 }
8656 return dir;
8657}
8658
8659/*
8660 * Shared by search() and searchpos() functions.
8661 */
8662 static int
8663search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8664{
8665 int flags;
8666 char_u *pat;
8667 pos_T pos;
8668 pos_T save_cursor;
8669 int save_p_ws = p_ws;
8670 int dir;
8671 int retval = 0; /* default: FAIL */
8672 long lnum_stop = 0;
8673 proftime_T tm;
8674#ifdef FEAT_RELTIME
8675 long time_limit = 0;
8676#endif
8677 int options = SEARCH_KEEP;
8678 int subpatnum;
8679
8680 pat = get_tv_string(&argvars[0]);
8681 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
8682 if (dir == 0)
8683 goto theend;
8684 flags = *flagsp;
8685 if (flags & SP_START)
8686 options |= SEARCH_START;
8687 if (flags & SP_END)
8688 options |= SEARCH_END;
8689 if (flags & SP_COLUMN)
8690 options |= SEARCH_COL;
8691
8692 /* Optional arguments: line number to stop searching and timeout. */
8693 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
8694 {
8695 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
8696 if (lnum_stop < 0)
8697 goto theend;
8698#ifdef FEAT_RELTIME
8699 if (argvars[3].v_type != VAR_UNKNOWN)
8700 {
8701 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
8702 if (time_limit < 0)
8703 goto theend;
8704 }
8705#endif
8706 }
8707
8708#ifdef FEAT_RELTIME
8709 /* Set the time limit, if there is one. */
8710 profile_setlimit(time_limit, &tm);
8711#endif
8712
8713 /*
8714 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
8715 * Check to make sure only those flags are set.
8716 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
8717 * flags cannot be set. Check for that condition also.
8718 */
8719 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
8720 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8721 {
8722 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
8723 goto theend;
8724 }
8725
8726 pos = save_cursor = curwin->w_cursor;
8727 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
8728 options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
8729 if (subpatnum != FAIL)
8730 {
8731 if (flags & SP_SUBPAT)
8732 retval = subpatnum;
8733 else
8734 retval = pos.lnum;
8735 if (flags & SP_SETPCMARK)
8736 setpcmark();
8737 curwin->w_cursor = pos;
8738 if (match_pos != NULL)
8739 {
8740 /* Store the match cursor position */
8741 match_pos->lnum = pos.lnum;
8742 match_pos->col = pos.col + 1;
8743 }
8744 /* "/$" will put the cursor after the end of the line, may need to
8745 * correct that here */
8746 check_cursor();
8747 }
8748
8749 /* If 'n' flag is used: restore cursor position. */
8750 if (flags & SP_NOMOVE)
8751 curwin->w_cursor = save_cursor;
8752 else
8753 curwin->w_set_curswant = TRUE;
8754theend:
8755 p_ws = save_p_ws;
8756
8757 return retval;
8758}
8759
8760#ifdef FEAT_FLOAT
8761
8762/*
8763 * round() is not in C90, use ceil() or floor() instead.
8764 */
8765 float_T
8766vim_round(float_T f)
8767{
8768 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
8769}
8770
8771/*
8772 * "round({float})" function
8773 */
8774 static void
8775f_round(typval_T *argvars, typval_T *rettv)
8776{
8777 float_T f = 0.0;
8778
8779 rettv->v_type = VAR_FLOAT;
8780 if (get_float_arg(argvars, &f) == OK)
8781 rettv->vval.v_float = vim_round(f);
8782 else
8783 rettv->vval.v_float = 0.0;
8784}
8785#endif
8786
8787/*
8788 * "screenattr()" function
8789 */
8790 static void
8791f_screenattr(typval_T *argvars, typval_T *rettv)
8792{
8793 int row;
8794 int col;
8795 int c;
8796
8797 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
8798 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
8799 if (row < 0 || row >= screen_Rows
8800 || col < 0 || col >= screen_Columns)
8801 c = -1;
8802 else
8803 c = ScreenAttrs[LineOffset[row] + col];
8804 rettv->vval.v_number = c;
8805}
8806
8807/*
8808 * "screenchar()" function
8809 */
8810 static void
8811f_screenchar(typval_T *argvars, typval_T *rettv)
8812{
8813 int row;
8814 int col;
8815 int off;
8816 int c;
8817
8818 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
8819 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
8820 if (row < 0 || row >= screen_Rows
8821 || col < 0 || col >= screen_Columns)
8822 c = -1;
8823 else
8824 {
8825 off = LineOffset[row] + col;
8826#ifdef FEAT_MBYTE
8827 if (enc_utf8 && ScreenLinesUC[off] != 0)
8828 c = ScreenLinesUC[off];
8829 else
8830#endif
8831 c = ScreenLines[off];
8832 }
8833 rettv->vval.v_number = c;
8834}
8835
8836/*
8837 * "screencol()" function
8838 *
8839 * First column is 1 to be consistent with virtcol().
8840 */
8841 static void
8842f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
8843{
8844 rettv->vval.v_number = screen_screencol() + 1;
8845}
8846
8847/*
8848 * "screenrow()" function
8849 */
8850 static void
8851f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
8852{
8853 rettv->vval.v_number = screen_screenrow() + 1;
8854}
8855
8856/*
8857 * "search()" function
8858 */
8859 static void
8860f_search(typval_T *argvars, typval_T *rettv)
8861{
8862 int flags = 0;
8863
8864 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
8865}
8866
8867/*
8868 * "searchdecl()" function
8869 */
8870 static void
8871f_searchdecl(typval_T *argvars, typval_T *rettv)
8872{
8873 int locally = 1;
8874 int thisblock = 0;
8875 int error = FALSE;
8876 char_u *name;
8877
8878 rettv->vval.v_number = 1; /* default: FAIL */
8879
8880 name = get_tv_string_chk(&argvars[0]);
8881 if (argvars[1].v_type != VAR_UNKNOWN)
8882 {
8883 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
8884 if (!error && argvars[2].v_type != VAR_UNKNOWN)
8885 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
8886 }
8887 if (!error && name != NULL)
8888 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
8889 locally, thisblock, SEARCH_KEEP) == FAIL;
8890}
8891
8892/*
8893 * Used by searchpair() and searchpairpos()
8894 */
8895 static int
8896searchpair_cmn(typval_T *argvars, pos_T *match_pos)
8897{
8898 char_u *spat, *mpat, *epat;
8899 char_u *skip;
8900 int save_p_ws = p_ws;
8901 int dir;
8902 int flags = 0;
8903 char_u nbuf1[NUMBUFLEN];
8904 char_u nbuf2[NUMBUFLEN];
8905 char_u nbuf3[NUMBUFLEN];
8906 int retval = 0; /* default: FAIL */
8907 long lnum_stop = 0;
8908 long time_limit = 0;
8909
8910 /* Get the three pattern arguments: start, middle, end. */
8911 spat = get_tv_string_chk(&argvars[0]);
8912 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
8913 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
8914 if (spat == NULL || mpat == NULL || epat == NULL)
8915 goto theend; /* type error */
8916
8917 /* Handle the optional fourth argument: flags */
8918 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
8919 if (dir == 0)
8920 goto theend;
8921
8922 /* Don't accept SP_END or SP_SUBPAT.
8923 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
8924 */
8925 if ((flags & (SP_END | SP_SUBPAT)) != 0
8926 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8927 {
8928 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
8929 goto theend;
8930 }
8931
8932 /* Using 'r' implies 'W', otherwise it doesn't work. */
8933 if (flags & SP_REPEAT)
8934 p_ws = FALSE;
8935
8936 /* Optional fifth argument: skip expression */
8937 if (argvars[3].v_type == VAR_UNKNOWN
8938 || argvars[4].v_type == VAR_UNKNOWN)
8939 skip = (char_u *)"";
8940 else
8941 {
8942 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
8943 if (argvars[5].v_type != VAR_UNKNOWN)
8944 {
8945 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
8946 if (lnum_stop < 0)
8947 goto theend;
8948#ifdef FEAT_RELTIME
8949 if (argvars[6].v_type != VAR_UNKNOWN)
8950 {
8951 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
8952 if (time_limit < 0)
8953 goto theend;
8954 }
8955#endif
8956 }
8957 }
8958 if (skip == NULL)
8959 goto theend; /* type error */
8960
8961 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
8962 match_pos, lnum_stop, time_limit);
8963
8964theend:
8965 p_ws = save_p_ws;
8966
8967 return retval;
8968}
8969
8970/*
8971 * "searchpair()" function
8972 */
8973 static void
8974f_searchpair(typval_T *argvars, typval_T *rettv)
8975{
8976 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
8977}
8978
8979/*
8980 * "searchpairpos()" function
8981 */
8982 static void
8983f_searchpairpos(typval_T *argvars, typval_T *rettv)
8984{
8985 pos_T match_pos;
8986 int lnum = 0;
8987 int col = 0;
8988
8989 if (rettv_list_alloc(rettv) == FAIL)
8990 return;
8991
8992 if (searchpair_cmn(argvars, &match_pos) > 0)
8993 {
8994 lnum = match_pos.lnum;
8995 col = match_pos.col;
8996 }
8997
8998 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8999 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9000}
9001
9002/*
9003 * Search for a start/middle/end thing.
9004 * Used by searchpair(), see its documentation for the details.
9005 * Returns 0 or -1 for no match,
9006 */
9007 long
9008do_searchpair(
9009 char_u *spat, /* start pattern */
9010 char_u *mpat, /* middle pattern */
9011 char_u *epat, /* end pattern */
9012 int dir, /* BACKWARD or FORWARD */
9013 char_u *skip, /* skip expression */
9014 int flags, /* SP_SETPCMARK and other SP_ values */
9015 pos_T *match_pos,
9016 linenr_T lnum_stop, /* stop at this line if not zero */
9017 long time_limit UNUSED) /* stop after this many msec */
9018{
9019 char_u *save_cpo;
9020 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9021 long retval = 0;
9022 pos_T pos;
9023 pos_T firstpos;
9024 pos_T foundpos;
9025 pos_T save_cursor;
9026 pos_T save_pos;
9027 int n;
9028 int r;
9029 int nest = 1;
9030 int err;
9031 int options = SEARCH_KEEP;
9032 proftime_T tm;
9033
9034 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9035 save_cpo = p_cpo;
9036 p_cpo = empty_option;
9037
9038#ifdef FEAT_RELTIME
9039 /* Set the time limit, if there is one. */
9040 profile_setlimit(time_limit, &tm);
9041#endif
9042
9043 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9044 * start/middle/end (pat3, for the top pair). */
9045 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15));
9046 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23));
9047 if (pat2 == NULL || pat3 == NULL)
9048 goto theend;
9049 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
9050 if (*mpat == NUL)
9051 STRCPY(pat3, pat2);
9052 else
9053 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
9054 spat, epat, mpat);
9055 if (flags & SP_START)
9056 options |= SEARCH_START;
9057
9058 save_cursor = curwin->w_cursor;
9059 pos = curwin->w_cursor;
9060 clearpos(&firstpos);
9061 clearpos(&foundpos);
9062 pat = pat3;
9063 for (;;)
9064 {
9065 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9066 options, RE_SEARCH, lnum_stop, &tm);
9067 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
9068 /* didn't find it or found the first match again: FAIL */
9069 break;
9070
9071 if (firstpos.lnum == 0)
9072 firstpos = pos;
9073 if (equalpos(pos, foundpos))
9074 {
9075 /* Found the same position again. Can happen with a pattern that
9076 * has "\zs" at the end and searching backwards. Advance one
9077 * character and try again. */
9078 if (dir == BACKWARD)
9079 decl(&pos);
9080 else
9081 incl(&pos);
9082 }
9083 foundpos = pos;
9084
9085 /* clear the start flag to avoid getting stuck here */
9086 options &= ~SEARCH_START;
9087
9088 /* If the skip pattern matches, ignore this match. */
9089 if (*skip != NUL)
9090 {
9091 save_pos = curwin->w_cursor;
9092 curwin->w_cursor = pos;
9093 r = eval_to_bool(skip, &err, NULL, FALSE);
9094 curwin->w_cursor = save_pos;
9095 if (err)
9096 {
9097 /* Evaluating {skip} caused an error, break here. */
9098 curwin->w_cursor = save_cursor;
9099 retval = -1;
9100 break;
9101 }
9102 if (r)
9103 continue;
9104 }
9105
9106 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9107 {
9108 /* Found end when searching backwards or start when searching
9109 * forward: nested pair. */
9110 ++nest;
9111 pat = pat2; /* nested, don't search for middle */
9112 }
9113 else
9114 {
9115 /* Found end when searching forward or start when searching
9116 * backward: end of (nested) pair; or found middle in outer pair. */
9117 if (--nest == 1)
9118 pat = pat3; /* outer level, search for middle */
9119 }
9120
9121 if (nest == 0)
9122 {
9123 /* Found the match: return matchcount or line number. */
9124 if (flags & SP_RETCOUNT)
9125 ++retval;
9126 else
9127 retval = pos.lnum;
9128 if (flags & SP_SETPCMARK)
9129 setpcmark();
9130 curwin->w_cursor = pos;
9131 if (!(flags & SP_REPEAT))
9132 break;
9133 nest = 1; /* search for next unmatched */
9134 }
9135 }
9136
9137 if (match_pos != NULL)
9138 {
9139 /* Store the match cursor position */
9140 match_pos->lnum = curwin->w_cursor.lnum;
9141 match_pos->col = curwin->w_cursor.col + 1;
9142 }
9143
9144 /* If 'n' flag is used or search failed: restore cursor position. */
9145 if ((flags & SP_NOMOVE) || retval == 0)
9146 curwin->w_cursor = save_cursor;
9147
9148theend:
9149 vim_free(pat2);
9150 vim_free(pat3);
9151 if (p_cpo == empty_option)
9152 p_cpo = save_cpo;
9153 else
9154 /* Darn, evaluating the {skip} expression changed the value. */
9155 free_string_option(save_cpo);
9156
9157 return retval;
9158}
9159
9160/*
9161 * "searchpos()" function
9162 */
9163 static void
9164f_searchpos(typval_T *argvars, typval_T *rettv)
9165{
9166 pos_T match_pos;
9167 int lnum = 0;
9168 int col = 0;
9169 int n;
9170 int flags = 0;
9171
9172 if (rettv_list_alloc(rettv) == FAIL)
9173 return;
9174
9175 n = search_cmn(argvars, &match_pos, &flags);
9176 if (n > 0)
9177 {
9178 lnum = match_pos.lnum;
9179 col = match_pos.col;
9180 }
9181
9182 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9183 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9184 if (flags & SP_SUBPAT)
9185 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9186}
9187
9188 static void
9189f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9190{
9191#ifdef FEAT_CLIENTSERVER
9192 char_u buf[NUMBUFLEN];
9193 char_u *server = get_tv_string_chk(&argvars[0]);
9194 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9195
9196 rettv->vval.v_number = -1;
9197 if (server == NULL || reply == NULL)
9198 return;
9199 if (check_restricted() || check_secure())
9200 return;
9201# ifdef FEAT_X11
9202 if (check_connection() == FAIL)
9203 return;
9204# endif
9205
9206 if (serverSendReply(server, reply) < 0)
9207 {
9208 EMSG(_("E258: Unable to send to client"));
9209 return;
9210 }
9211 rettv->vval.v_number = 0;
9212#else
9213 rettv->vval.v_number = -1;
9214#endif
9215}
9216
9217 static void
9218f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9219{
9220 char_u *r = NULL;
9221
9222#ifdef FEAT_CLIENTSERVER
9223# ifdef WIN32
9224 r = serverGetVimNames();
9225# else
9226 make_connection();
9227 if (X_DISPLAY != NULL)
9228 r = serverGetVimNames(X_DISPLAY);
9229# endif
9230#endif
9231 rettv->v_type = VAR_STRING;
9232 rettv->vval.v_string = r;
9233}
9234
9235/*
9236 * "setbufvar()" function
9237 */
9238 static void
9239f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9240{
9241 buf_T *buf;
9242 char_u *varname, *bufvarname;
9243 typval_T *varp;
9244 char_u nbuf[NUMBUFLEN];
9245
9246 if (check_restricted() || check_secure())
9247 return;
9248 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
9249 varname = get_tv_string_chk(&argvars[1]);
9250 buf = get_buf_tv(&argvars[0], FALSE);
9251 varp = &argvars[2];
9252
9253 if (buf != NULL && varname != NULL && varp != NULL)
9254 {
9255 if (*varname == '&')
9256 {
9257 long numval;
9258 char_u *strval;
9259 int error = FALSE;
9260 aco_save_T aco;
9261
9262 /* set curbuf to be our buf, temporarily */
9263 aucmd_prepbuf(&aco, buf);
9264
9265 ++varname;
9266 numval = (long)get_tv_number_chk(varp, &error);
9267 strval = get_tv_string_buf_chk(varp, nbuf);
9268 if (!error && strval != NULL)
9269 set_option_value(varname, numval, strval, OPT_LOCAL);
9270
9271 /* reset notion of buffer */
9272 aucmd_restbuf(&aco);
9273 }
9274 else
9275 {
9276 buf_T *save_curbuf = curbuf;
9277
9278 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9279 if (bufvarname != NULL)
9280 {
9281 curbuf = buf;
9282 STRCPY(bufvarname, "b:");
9283 STRCPY(bufvarname + 2, varname);
9284 set_var(bufvarname, varp, TRUE);
9285 vim_free(bufvarname);
9286 curbuf = save_curbuf;
9287 }
9288 }
9289 }
9290}
9291
9292 static void
9293f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9294{
9295 dict_T *d;
9296 dictitem_T *di;
9297 char_u *csearch;
9298
9299 if (argvars[0].v_type != VAR_DICT)
9300 {
9301 EMSG(_(e_dictreq));
9302 return;
9303 }
9304
9305 if ((d = argvars[0].vval.v_dict) != NULL)
9306 {
9307 csearch = get_dict_string(d, (char_u *)"char", FALSE);
9308 if (csearch != NULL)
9309 {
9310#ifdef FEAT_MBYTE
9311 if (enc_utf8)
9312 {
9313 int pcc[MAX_MCO];
9314 int c = utfc_ptr2char(csearch, pcc);
9315
9316 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9317 }
9318 else
9319#endif
9320 set_last_csearch(PTR2CHAR(csearch),
9321 csearch, MB_PTR2LEN(csearch));
9322 }
9323
9324 di = dict_find(d, (char_u *)"forward", -1);
9325 if (di != NULL)
9326 set_csearch_direction((int)get_tv_number(&di->di_tv)
9327 ? FORWARD : BACKWARD);
9328
9329 di = dict_find(d, (char_u *)"until", -1);
9330 if (di != NULL)
9331 set_csearch_until(!!get_tv_number(&di->di_tv));
9332 }
9333}
9334
9335/*
9336 * "setcmdpos()" function
9337 */
9338 static void
9339f_setcmdpos(typval_T *argvars, typval_T *rettv)
9340{
9341 int pos = (int)get_tv_number(&argvars[0]) - 1;
9342
9343 if (pos >= 0)
9344 rettv->vval.v_number = set_cmdline_pos(pos);
9345}
9346
9347/*
9348 * "setfperm({fname}, {mode})" function
9349 */
9350 static void
9351f_setfperm(typval_T *argvars, typval_T *rettv)
9352{
9353 char_u *fname;
9354 char_u modebuf[NUMBUFLEN];
9355 char_u *mode_str;
9356 int i;
9357 int mask;
9358 int mode = 0;
9359
9360 rettv->vval.v_number = 0;
9361 fname = get_tv_string_chk(&argvars[0]);
9362 if (fname == NULL)
9363 return;
9364 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9365 if (mode_str == NULL)
9366 return;
9367 if (STRLEN(mode_str) != 9)
9368 {
9369 EMSG2(_(e_invarg2), mode_str);
9370 return;
9371 }
9372
9373 mask = 1;
9374 for (i = 8; i >= 0; --i)
9375 {
9376 if (mode_str[i] != '-')
9377 mode |= mask;
9378 mask = mask << 1;
9379 }
9380 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9381}
9382
9383/*
9384 * "setline()" function
9385 */
9386 static void
9387f_setline(typval_T *argvars, typval_T *rettv)
9388{
9389 linenr_T lnum;
9390 char_u *line = NULL;
9391 list_T *l = NULL;
9392 listitem_T *li = NULL;
9393 long added = 0;
9394 linenr_T lcount = curbuf->b_ml.ml_line_count;
9395
9396 lnum = get_tv_lnum(&argvars[0]);
9397 if (argvars[1].v_type == VAR_LIST)
9398 {
9399 l = argvars[1].vval.v_list;
9400 li = l->lv_first;
9401 }
9402 else
9403 line = get_tv_string_chk(&argvars[1]);
9404
9405 /* default result is zero == OK */
9406 for (;;)
9407 {
9408 if (l != NULL)
9409 {
9410 /* list argument, get next string */
9411 if (li == NULL)
9412 break;
9413 line = get_tv_string_chk(&li->li_tv);
9414 li = li->li_next;
9415 }
9416
9417 rettv->vval.v_number = 1; /* FAIL */
9418 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9419 break;
9420
9421 /* When coming here from Insert mode, sync undo, so that this can be
9422 * undone separately from what was previously inserted. */
9423 if (u_sync_once == 2)
9424 {
9425 u_sync_once = 1; /* notify that u_sync() was called */
9426 u_sync(TRUE);
9427 }
9428
9429 if (lnum <= curbuf->b_ml.ml_line_count)
9430 {
9431 /* existing line, replace it */
9432 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
9433 {
9434 changed_bytes(lnum, 0);
9435 if (lnum == curwin->w_cursor.lnum)
9436 check_cursor_col();
9437 rettv->vval.v_number = 0; /* OK */
9438 }
9439 }
9440 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
9441 {
9442 /* lnum is one past the last line, append the line */
9443 ++added;
9444 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
9445 rettv->vval.v_number = 0; /* OK */
9446 }
9447
9448 if (l == NULL) /* only one string argument */
9449 break;
9450 ++lnum;
9451 }
9452
9453 if (added > 0)
9454 appended_lines_mark(lcount, added);
9455}
9456
9457static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv);
9458
9459/*
9460 * Used by "setqflist()" and "setloclist()" functions
9461 */
9462 static void
9463set_qf_ll_list(
9464 win_T *wp UNUSED,
9465 typval_T *list_arg UNUSED,
9466 typval_T *action_arg UNUSED,
9467 typval_T *rettv)
9468{
9469#ifdef FEAT_QUICKFIX
9470 static char *e_invact = N_("E927: Invalid action: '%s'");
9471 char_u *act;
9472 int action = 0;
9473#endif
9474
9475 rettv->vval.v_number = -1;
9476
9477#ifdef FEAT_QUICKFIX
9478 if (list_arg->v_type != VAR_LIST)
9479 EMSG(_(e_listreq));
9480 else
9481 {
9482 list_T *l = list_arg->vval.v_list;
9483
9484 if (action_arg->v_type == VAR_STRING)
9485 {
9486 act = get_tv_string_chk(action_arg);
9487 if (act == NULL)
9488 return; /* type error; errmsg already given */
9489 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL)
9490 action = *act;
9491 else
9492 EMSG2(_(e_invact), act);
9493 }
9494 else if (action_arg->v_type == VAR_UNKNOWN)
9495 action = ' ';
9496 else
9497 EMSG(_(e_stringreq));
9498
9499 if (l != NULL && action && set_errorlist(wp, l, action,
9500 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK)
9501 rettv->vval.v_number = 0;
9502 }
9503#endif
9504}
9505
9506/*
9507 * "setloclist()" function
9508 */
9509 static void
9510f_setloclist(typval_T *argvars, typval_T *rettv)
9511{
9512 win_T *win;
9513
9514 rettv->vval.v_number = -1;
9515
9516 win = find_win_by_nr(&argvars[0], NULL);
9517 if (win != NULL)
9518 set_qf_ll_list(win, &argvars[1], &argvars[2], rettv);
9519}
9520
9521/*
9522 * "setmatches()" function
9523 */
9524 static void
9525f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9526{
9527#ifdef FEAT_SEARCH_EXTRA
9528 list_T *l;
9529 listitem_T *li;
9530 dict_T *d;
9531 list_T *s = NULL;
9532
9533 rettv->vval.v_number = -1;
9534 if (argvars[0].v_type != VAR_LIST)
9535 {
9536 EMSG(_(e_listreq));
9537 return;
9538 }
9539 if ((l = argvars[0].vval.v_list) != NULL)
9540 {
9541
9542 /* To some extent make sure that we are dealing with a list from
9543 * "getmatches()". */
9544 li = l->lv_first;
9545 while (li != NULL)
9546 {
9547 if (li->li_tv.v_type != VAR_DICT
9548 || (d = li->li_tv.vval.v_dict) == NULL)
9549 {
9550 EMSG(_(e_invarg));
9551 return;
9552 }
9553 if (!(dict_find(d, (char_u *)"group", -1) != NULL
9554 && (dict_find(d, (char_u *)"pattern", -1) != NULL
9555 || dict_find(d, (char_u *)"pos1", -1) != NULL)
9556 && dict_find(d, (char_u *)"priority", -1) != NULL
9557 && dict_find(d, (char_u *)"id", -1) != NULL))
9558 {
9559 EMSG(_(e_invarg));
9560 return;
9561 }
9562 li = li->li_next;
9563 }
9564
9565 clear_matches(curwin);
9566 li = l->lv_first;
9567 while (li != NULL)
9568 {
9569 int i = 0;
9570 char_u buf[5];
9571 dictitem_T *di;
9572 char_u *group;
9573 int priority;
9574 int id;
9575 char_u *conceal;
9576
9577 d = li->li_tv.vval.v_dict;
9578 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
9579 {
9580 if (s == NULL)
9581 {
9582 s = list_alloc();
9583 if (s == NULL)
9584 return;
9585 }
9586
9587 /* match from matchaddpos() */
9588 for (i = 1; i < 9; i++)
9589 {
9590 sprintf((char *)buf, (char *)"pos%d", i);
9591 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
9592 {
9593 if (di->di_tv.v_type != VAR_LIST)
9594 return;
9595
9596 list_append_tv(s, &di->di_tv);
9597 s->lv_refcount++;
9598 }
9599 else
9600 break;
9601 }
9602 }
9603
9604 group = get_dict_string(d, (char_u *)"group", FALSE);
9605 priority = (int)get_dict_number(d, (char_u *)"priority");
9606 id = (int)get_dict_number(d, (char_u *)"id");
9607 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
9608 ? get_dict_string(d, (char_u *)"conceal", FALSE)
9609 : NULL;
9610 if (i == 0)
9611 {
9612 match_add(curwin, group,
9613 get_dict_string(d, (char_u *)"pattern", FALSE),
9614 priority, id, NULL, conceal);
9615 }
9616 else
9617 {
9618 match_add(curwin, group, NULL, priority, id, s, conceal);
9619 list_unref(s);
9620 s = NULL;
9621 }
9622
9623 li = li->li_next;
9624 }
9625 rettv->vval.v_number = 0;
9626 }
9627#endif
9628}
9629
9630/*
9631 * "setpos()" function
9632 */
9633 static void
9634f_setpos(typval_T *argvars, typval_T *rettv)
9635{
9636 pos_T pos;
9637 int fnum;
9638 char_u *name;
9639 colnr_T curswant = -1;
9640
9641 rettv->vval.v_number = -1;
9642 name = get_tv_string_chk(argvars);
9643 if (name != NULL)
9644 {
9645 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
9646 {
9647 if (--pos.col < 0)
9648 pos.col = 0;
9649 if (name[0] == '.' && name[1] == NUL)
9650 {
9651 /* set cursor */
9652 if (fnum == curbuf->b_fnum)
9653 {
9654 curwin->w_cursor = pos;
9655 if (curswant >= 0)
9656 {
9657 curwin->w_curswant = curswant - 1;
9658 curwin->w_set_curswant = FALSE;
9659 }
9660 check_cursor();
9661 rettv->vval.v_number = 0;
9662 }
9663 else
9664 EMSG(_(e_invarg));
9665 }
9666 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
9667 {
9668 /* set mark */
9669 if (setmark_pos(name[1], &pos, fnum) == OK)
9670 rettv->vval.v_number = 0;
9671 }
9672 else
9673 EMSG(_(e_invarg));
9674 }
9675 }
9676}
9677
9678/*
9679 * "setqflist()" function
9680 */
9681 static void
9682f_setqflist(typval_T *argvars, typval_T *rettv)
9683{
9684 set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv);
9685}
9686
9687/*
9688 * "setreg()" function
9689 */
9690 static void
9691f_setreg(typval_T *argvars, typval_T *rettv)
9692{
9693 int regname;
9694 char_u *strregname;
9695 char_u *stropt;
9696 char_u *strval;
9697 int append;
9698 char_u yank_type;
9699 long block_len;
9700
9701 block_len = -1;
9702 yank_type = MAUTO;
9703 append = FALSE;
9704
9705 strregname = get_tv_string_chk(argvars);
9706 rettv->vval.v_number = 1; /* FAIL is default */
9707
9708 if (strregname == NULL)
9709 return; /* type error; errmsg already given */
9710 regname = *strregname;
9711 if (regname == 0 || regname == '@')
9712 regname = '"';
9713
9714 if (argvars[2].v_type != VAR_UNKNOWN)
9715 {
9716 stropt = get_tv_string_chk(&argvars[2]);
9717 if (stropt == NULL)
9718 return; /* type error */
9719 for (; *stropt != NUL; ++stropt)
9720 switch (*stropt)
9721 {
9722 case 'a': case 'A': /* append */
9723 append = TRUE;
9724 break;
9725 case 'v': case 'c': /* character-wise selection */
9726 yank_type = MCHAR;
9727 break;
9728 case 'V': case 'l': /* line-wise selection */
9729 yank_type = MLINE;
9730 break;
9731 case 'b': case Ctrl_V: /* block-wise selection */
9732 yank_type = MBLOCK;
9733 if (VIM_ISDIGIT(stropt[1]))
9734 {
9735 ++stropt;
9736 block_len = getdigits(&stropt) - 1;
9737 --stropt;
9738 }
9739 break;
9740 }
9741 }
9742
9743 if (argvars[1].v_type == VAR_LIST)
9744 {
9745 char_u **lstval;
9746 char_u **allocval;
9747 char_u buf[NUMBUFLEN];
9748 char_u **curval;
9749 char_u **curallocval;
9750 list_T *ll = argvars[1].vval.v_list;
9751 listitem_T *li;
9752 int len;
9753
9754 /* If the list is NULL handle like an empty list. */
9755 len = ll == NULL ? 0 : ll->lv_len;
9756
9757 /* First half: use for pointers to result lines; second half: use for
9758 * pointers to allocated copies. */
9759 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
9760 if (lstval == NULL)
9761 return;
9762 curval = lstval;
9763 allocval = lstval + len + 2;
9764 curallocval = allocval;
9765
9766 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
9767 li = li->li_next)
9768 {
9769 strval = get_tv_string_buf_chk(&li->li_tv, buf);
9770 if (strval == NULL)
9771 goto free_lstval;
9772 if (strval == buf)
9773 {
9774 /* Need to make a copy, next get_tv_string_buf_chk() will
9775 * overwrite the string. */
9776 strval = vim_strsave(buf);
9777 if (strval == NULL)
9778 goto free_lstval;
9779 *curallocval++ = strval;
9780 }
9781 *curval++ = strval;
9782 }
9783 *curval++ = NULL;
9784
9785 write_reg_contents_lst(regname, lstval, -1,
9786 append, yank_type, block_len);
9787free_lstval:
9788 while (curallocval > allocval)
9789 vim_free(*--curallocval);
9790 vim_free(lstval);
9791 }
9792 else
9793 {
9794 strval = get_tv_string_chk(&argvars[1]);
9795 if (strval == NULL)
9796 return;
9797 write_reg_contents_ex(regname, strval, -1,
9798 append, yank_type, block_len);
9799 }
9800 rettv->vval.v_number = 0;
9801}
9802
9803/*
9804 * "settabvar()" function
9805 */
9806 static void
9807f_settabvar(typval_T *argvars, typval_T *rettv)
9808{
9809#ifdef FEAT_WINDOWS
9810 tabpage_T *save_curtab;
9811 tabpage_T *tp;
9812#endif
9813 char_u *varname, *tabvarname;
9814 typval_T *varp;
9815
9816 rettv->vval.v_number = 0;
9817
9818 if (check_restricted() || check_secure())
9819 return;
9820
9821#ifdef FEAT_WINDOWS
9822 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
9823#endif
9824 varname = get_tv_string_chk(&argvars[1]);
9825 varp = &argvars[2];
9826
9827 if (varname != NULL && varp != NULL
9828#ifdef FEAT_WINDOWS
9829 && tp != NULL
9830#endif
9831 )
9832 {
9833#ifdef FEAT_WINDOWS
9834 save_curtab = curtab;
9835 goto_tabpage_tp(tp, FALSE, FALSE);
9836#endif
9837
9838 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
9839 if (tabvarname != NULL)
9840 {
9841 STRCPY(tabvarname, "t:");
9842 STRCPY(tabvarname + 2, varname);
9843 set_var(tabvarname, varp, TRUE);
9844 vim_free(tabvarname);
9845 }
9846
9847#ifdef FEAT_WINDOWS
9848 /* Restore current tabpage */
9849 if (valid_tabpage(save_curtab))
9850 goto_tabpage_tp(save_curtab, FALSE, FALSE);
9851#endif
9852 }
9853}
9854
9855/*
9856 * "settabwinvar()" function
9857 */
9858 static void
9859f_settabwinvar(typval_T *argvars, typval_T *rettv)
9860{
9861 setwinvar(argvars, rettv, 1);
9862}
9863
9864/*
9865 * "setwinvar()" function
9866 */
9867 static void
9868f_setwinvar(typval_T *argvars, typval_T *rettv)
9869{
9870 setwinvar(argvars, rettv, 0);
9871}
9872
9873#ifdef FEAT_CRYPT
9874/*
9875 * "sha256({string})" function
9876 */
9877 static void
9878f_sha256(typval_T *argvars, typval_T *rettv)
9879{
9880 char_u *p;
9881
9882 p = get_tv_string(&argvars[0]);
9883 rettv->vval.v_string = vim_strsave(
9884 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
9885 rettv->v_type = VAR_STRING;
9886}
9887#endif /* FEAT_CRYPT */
9888
9889/*
9890 * "shellescape({string})" function
9891 */
9892 static void
9893f_shellescape(typval_T *argvars, typval_T *rettv)
9894{
9895 rettv->vval.v_string = vim_strsave_shellescape(
9896 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE);
9897 rettv->v_type = VAR_STRING;
9898}
9899
9900/*
9901 * shiftwidth() function
9902 */
9903 static void
9904f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
9905{
9906 rettv->vval.v_number = get_sw_value(curbuf);
9907}
9908
9909/*
9910 * "simplify()" function
9911 */
9912 static void
9913f_simplify(typval_T *argvars, typval_T *rettv)
9914{
9915 char_u *p;
9916
9917 p = get_tv_string(&argvars[0]);
9918 rettv->vval.v_string = vim_strsave(p);
9919 simplify_filename(rettv->vval.v_string); /* simplify in place */
9920 rettv->v_type = VAR_STRING;
9921}
9922
9923#ifdef FEAT_FLOAT
9924/*
9925 * "sin()" function
9926 */
9927 static void
9928f_sin(typval_T *argvars, typval_T *rettv)
9929{
9930 float_T f = 0.0;
9931
9932 rettv->v_type = VAR_FLOAT;
9933 if (get_float_arg(argvars, &f) == OK)
9934 rettv->vval.v_float = sin(f);
9935 else
9936 rettv->vval.v_float = 0.0;
9937}
9938
9939/*
9940 * "sinh()" function
9941 */
9942 static void
9943f_sinh(typval_T *argvars, typval_T *rettv)
9944{
9945 float_T f = 0.0;
9946
9947 rettv->v_type = VAR_FLOAT;
9948 if (get_float_arg(argvars, &f) == OK)
9949 rettv->vval.v_float = sinh(f);
9950 else
9951 rettv->vval.v_float = 0.0;
9952}
9953#endif
9954
9955static int
9956#ifdef __BORLANDC__
9957 _RTLENTRYF
9958#endif
9959 item_compare(const void *s1, const void *s2);
9960static int
9961#ifdef __BORLANDC__
9962 _RTLENTRYF
9963#endif
9964 item_compare2(const void *s1, const void *s2);
9965
9966/* struct used in the array that's given to qsort() */
9967typedef struct
9968{
9969 listitem_T *item;
9970 int idx;
9971} sortItem_T;
9972
9973/* struct storing information about current sort */
9974typedef struct
9975{
9976 int item_compare_ic;
9977 int item_compare_numeric;
9978 int item_compare_numbers;
9979#ifdef FEAT_FLOAT
9980 int item_compare_float;
9981#endif
9982 char_u *item_compare_func;
9983 partial_T *item_compare_partial;
9984 dict_T *item_compare_selfdict;
9985 int item_compare_func_err;
9986 int item_compare_keep_zero;
9987} sortinfo_T;
9988static sortinfo_T *sortinfo = NULL;
9989static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
9990#define ITEM_COMPARE_FAIL 999
9991
9992/*
9993 * Compare functions for f_sort() and f_uniq() below.
9994 */
9995 static int
9996#ifdef __BORLANDC__
9997_RTLENTRYF
9998#endif
9999item_compare(const void *s1, const void *s2)
10000{
10001 sortItem_T *si1, *si2;
10002 typval_T *tv1, *tv2;
10003 char_u *p1, *p2;
10004 char_u *tofree1 = NULL, *tofree2 = NULL;
10005 int res;
10006 char_u numbuf1[NUMBUFLEN];
10007 char_u numbuf2[NUMBUFLEN];
10008
10009 si1 = (sortItem_T *)s1;
10010 si2 = (sortItem_T *)s2;
10011 tv1 = &si1->item->li_tv;
10012 tv2 = &si2->item->li_tv;
10013
10014 if (sortinfo->item_compare_numbers)
10015 {
10016 varnumber_T v1 = get_tv_number(tv1);
10017 varnumber_T v2 = get_tv_number(tv2);
10018
10019 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10020 }
10021
10022#ifdef FEAT_FLOAT
10023 if (sortinfo->item_compare_float)
10024 {
10025 float_T v1 = get_tv_float(tv1);
10026 float_T v2 = get_tv_float(tv2);
10027
10028 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10029 }
10030#endif
10031
10032 /* tv2string() puts quotes around a string and allocates memory. Don't do
10033 * that for string variables. Use a single quote when comparing with a
10034 * non-string to do what the docs promise. */
10035 if (tv1->v_type == VAR_STRING)
10036 {
10037 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10038 p1 = (char_u *)"'";
10039 else
10040 p1 = tv1->vval.v_string;
10041 }
10042 else
10043 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10044 if (tv2->v_type == VAR_STRING)
10045 {
10046 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10047 p2 = (char_u *)"'";
10048 else
10049 p2 = tv2->vval.v_string;
10050 }
10051 else
10052 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10053 if (p1 == NULL)
10054 p1 = (char_u *)"";
10055 if (p2 == NULL)
10056 p2 = (char_u *)"";
10057 if (!sortinfo->item_compare_numeric)
10058 {
10059 if (sortinfo->item_compare_ic)
10060 res = STRICMP(p1, p2);
10061 else
10062 res = STRCMP(p1, p2);
10063 }
10064 else
10065 {
10066 double n1, n2;
10067 n1 = strtod((char *)p1, (char **)&p1);
10068 n2 = strtod((char *)p2, (char **)&p2);
10069 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10070 }
10071
10072 /* When the result would be zero, compare the item indexes. Makes the
10073 * sort stable. */
10074 if (res == 0 && !sortinfo->item_compare_keep_zero)
10075 res = si1->idx > si2->idx ? 1 : -1;
10076
10077 vim_free(tofree1);
10078 vim_free(tofree2);
10079 return res;
10080}
10081
10082 static int
10083#ifdef __BORLANDC__
10084_RTLENTRYF
10085#endif
10086item_compare2(const void *s1, const void *s2)
10087{
10088 sortItem_T *si1, *si2;
10089 int res;
10090 typval_T rettv;
10091 typval_T argv[3];
10092 int dummy;
10093 char_u *func_name;
10094 partial_T *partial = sortinfo->item_compare_partial;
10095
10096 /* shortcut after failure in previous call; compare all items equal */
10097 if (sortinfo->item_compare_func_err)
10098 return 0;
10099
10100 si1 = (sortItem_T *)s1;
10101 si2 = (sortItem_T *)s2;
10102
10103 if (partial == NULL)
10104 func_name = sortinfo->item_compare_func;
10105 else
10106 func_name = partial->pt_name;
10107
10108 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10109 * in the copy without changing the original list items. */
10110 copy_tv(&si1->item->li_tv, &argv[0]);
10111 copy_tv(&si2->item->li_tv, &argv[1]);
10112
10113 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10114 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010115 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010116 partial, sortinfo->item_compare_selfdict);
10117 clear_tv(&argv[0]);
10118 clear_tv(&argv[1]);
10119
10120 if (res == FAIL)
10121 res = ITEM_COMPARE_FAIL;
10122 else
10123 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10124 if (sortinfo->item_compare_func_err)
10125 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10126 clear_tv(&rettv);
10127
10128 /* When the result would be zero, compare the pointers themselves. Makes
10129 * the sort stable. */
10130 if (res == 0 && !sortinfo->item_compare_keep_zero)
10131 res = si1->idx > si2->idx ? 1 : -1;
10132
10133 return res;
10134}
10135
10136/*
10137 * "sort({list})" function
10138 */
10139 static void
10140do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10141{
10142 list_T *l;
10143 listitem_T *li;
10144 sortItem_T *ptrs;
10145 sortinfo_T *old_sortinfo;
10146 sortinfo_T info;
10147 long len;
10148 long i;
10149
10150 /* Pointer to current info struct used in compare function. Save and
10151 * restore the current one for nested calls. */
10152 old_sortinfo = sortinfo;
10153 sortinfo = &info;
10154
10155 if (argvars[0].v_type != VAR_LIST)
10156 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10157 else
10158 {
10159 l = argvars[0].vval.v_list;
10160 if (l == NULL || tv_check_lock(l->lv_lock,
10161 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10162 TRUE))
10163 goto theend;
10164 rettv->vval.v_list = l;
10165 rettv->v_type = VAR_LIST;
10166 ++l->lv_refcount;
10167
10168 len = list_len(l);
10169 if (len <= 1)
10170 goto theend; /* short list sorts pretty quickly */
10171
10172 info.item_compare_ic = FALSE;
10173 info.item_compare_numeric = FALSE;
10174 info.item_compare_numbers = FALSE;
10175#ifdef FEAT_FLOAT
10176 info.item_compare_float = FALSE;
10177#endif
10178 info.item_compare_func = NULL;
10179 info.item_compare_partial = NULL;
10180 info.item_compare_selfdict = NULL;
10181 if (argvars[1].v_type != VAR_UNKNOWN)
10182 {
10183 /* optional second argument: {func} */
10184 if (argvars[1].v_type == VAR_FUNC)
10185 info.item_compare_func = argvars[1].vval.v_string;
10186 else if (argvars[1].v_type == VAR_PARTIAL)
10187 info.item_compare_partial = argvars[1].vval.v_partial;
10188 else
10189 {
10190 int error = FALSE;
10191
10192 i = (long)get_tv_number_chk(&argvars[1], &error);
10193 if (error)
10194 goto theend; /* type error; errmsg already given */
10195 if (i == 1)
10196 info.item_compare_ic = TRUE;
10197 else if (argvars[1].v_type != VAR_NUMBER)
10198 info.item_compare_func = get_tv_string(&argvars[1]);
10199 else if (i != 0)
10200 {
10201 EMSG(_(e_invarg));
10202 goto theend;
10203 }
10204 if (info.item_compare_func != NULL)
10205 {
10206 if (*info.item_compare_func == NUL)
10207 {
10208 /* empty string means default sort */
10209 info.item_compare_func = NULL;
10210 }
10211 else if (STRCMP(info.item_compare_func, "n") == 0)
10212 {
10213 info.item_compare_func = NULL;
10214 info.item_compare_numeric = TRUE;
10215 }
10216 else if (STRCMP(info.item_compare_func, "N") == 0)
10217 {
10218 info.item_compare_func = NULL;
10219 info.item_compare_numbers = TRUE;
10220 }
10221#ifdef FEAT_FLOAT
10222 else if (STRCMP(info.item_compare_func, "f") == 0)
10223 {
10224 info.item_compare_func = NULL;
10225 info.item_compare_float = TRUE;
10226 }
10227#endif
10228 else if (STRCMP(info.item_compare_func, "i") == 0)
10229 {
10230 info.item_compare_func = NULL;
10231 info.item_compare_ic = TRUE;
10232 }
10233 }
10234 }
10235
10236 if (argvars[2].v_type != VAR_UNKNOWN)
10237 {
10238 /* optional third argument: {dict} */
10239 if (argvars[2].v_type != VAR_DICT)
10240 {
10241 EMSG(_(e_dictreq));
10242 goto theend;
10243 }
10244 info.item_compare_selfdict = argvars[2].vval.v_dict;
10245 }
10246 }
10247
10248 /* Make an array with each entry pointing to an item in the List. */
10249 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10250 if (ptrs == NULL)
10251 goto theend;
10252
10253 i = 0;
10254 if (sort)
10255 {
10256 /* sort(): ptrs will be the list to sort */
10257 for (li = l->lv_first; li != NULL; li = li->li_next)
10258 {
10259 ptrs[i].item = li;
10260 ptrs[i].idx = i;
10261 ++i;
10262 }
10263
10264 info.item_compare_func_err = FALSE;
10265 info.item_compare_keep_zero = FALSE;
10266 /* test the compare function */
10267 if ((info.item_compare_func != NULL
10268 || info.item_compare_partial != NULL)
10269 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10270 == ITEM_COMPARE_FAIL)
10271 EMSG(_("E702: Sort compare function failed"));
10272 else
10273 {
10274 /* Sort the array with item pointers. */
10275 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10276 info.item_compare_func == NULL
10277 && info.item_compare_partial == NULL
10278 ? item_compare : item_compare2);
10279
10280 if (!info.item_compare_func_err)
10281 {
10282 /* Clear the List and append the items in sorted order. */
10283 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10284 l->lv_len = 0;
10285 for (i = 0; i < len; ++i)
10286 list_append(l, ptrs[i].item);
10287 }
10288 }
10289 }
10290 else
10291 {
10292 int (*item_compare_func_ptr)(const void *, const void *);
10293
10294 /* f_uniq(): ptrs will be a stack of items to remove */
10295 info.item_compare_func_err = FALSE;
10296 info.item_compare_keep_zero = TRUE;
10297 item_compare_func_ptr = info.item_compare_func != NULL
10298 || info.item_compare_partial != NULL
10299 ? item_compare2 : item_compare;
10300
10301 for (li = l->lv_first; li != NULL && li->li_next != NULL;
10302 li = li->li_next)
10303 {
10304 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10305 == 0)
10306 ptrs[i++].item = li;
10307 if (info.item_compare_func_err)
10308 {
10309 EMSG(_("E882: Uniq compare function failed"));
10310 break;
10311 }
10312 }
10313
10314 if (!info.item_compare_func_err)
10315 {
10316 while (--i >= 0)
10317 {
10318 li = ptrs[i].item->li_next;
10319 ptrs[i].item->li_next = li->li_next;
10320 if (li->li_next != NULL)
10321 li->li_next->li_prev = ptrs[i].item;
10322 else
10323 l->lv_last = ptrs[i].item;
10324 list_fix_watch(l, li);
10325 listitem_free(li);
10326 l->lv_len--;
10327 }
10328 }
10329 }
10330
10331 vim_free(ptrs);
10332 }
10333theend:
10334 sortinfo = old_sortinfo;
10335}
10336
10337/*
10338 * "sort({list})" function
10339 */
10340 static void
10341f_sort(typval_T *argvars, typval_T *rettv)
10342{
10343 do_sort_uniq(argvars, rettv, TRUE);
10344}
10345
10346/*
10347 * "uniq({list})" function
10348 */
10349 static void
10350f_uniq(typval_T *argvars, typval_T *rettv)
10351{
10352 do_sort_uniq(argvars, rettv, FALSE);
10353}
10354
10355/*
10356 * "soundfold({word})" function
10357 */
10358 static void
10359f_soundfold(typval_T *argvars, typval_T *rettv)
10360{
10361 char_u *s;
10362
10363 rettv->v_type = VAR_STRING;
10364 s = get_tv_string(&argvars[0]);
10365#ifdef FEAT_SPELL
10366 rettv->vval.v_string = eval_soundfold(s);
10367#else
10368 rettv->vval.v_string = vim_strsave(s);
10369#endif
10370}
10371
10372/*
10373 * "spellbadword()" function
10374 */
10375 static void
10376f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10377{
10378 char_u *word = (char_u *)"";
10379 hlf_T attr = HLF_COUNT;
10380 int len = 0;
10381
10382 if (rettv_list_alloc(rettv) == FAIL)
10383 return;
10384
10385#ifdef FEAT_SPELL
10386 if (argvars[0].v_type == VAR_UNKNOWN)
10387 {
10388 /* Find the start and length of the badly spelled word. */
10389 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10390 if (len != 0)
10391 word = ml_get_cursor();
10392 }
10393 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10394 {
10395 char_u *str = get_tv_string_chk(&argvars[0]);
10396 int capcol = -1;
10397
10398 if (str != NULL)
10399 {
10400 /* Check the argument for spelling. */
10401 while (*str != NUL)
10402 {
10403 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10404 if (attr != HLF_COUNT)
10405 {
10406 word = str;
10407 break;
10408 }
10409 str += len;
10410 }
10411 }
10412 }
10413#endif
10414
10415 list_append_string(rettv->vval.v_list, word, len);
10416 list_append_string(rettv->vval.v_list, (char_u *)(
10417 attr == HLF_SPB ? "bad" :
10418 attr == HLF_SPR ? "rare" :
10419 attr == HLF_SPL ? "local" :
10420 attr == HLF_SPC ? "caps" :
10421 ""), -1);
10422}
10423
10424/*
10425 * "spellsuggest()" function
10426 */
10427 static void
10428f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10429{
10430#ifdef FEAT_SPELL
10431 char_u *str;
10432 int typeerr = FALSE;
10433 int maxcount;
10434 garray_T ga;
10435 int i;
10436 listitem_T *li;
10437 int need_capital = FALSE;
10438#endif
10439
10440 if (rettv_list_alloc(rettv) == FAIL)
10441 return;
10442
10443#ifdef FEAT_SPELL
10444 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10445 {
10446 str = get_tv_string(&argvars[0]);
10447 if (argvars[1].v_type != VAR_UNKNOWN)
10448 {
10449 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
10450 if (maxcount <= 0)
10451 return;
10452 if (argvars[2].v_type != VAR_UNKNOWN)
10453 {
10454 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
10455 if (typeerr)
10456 return;
10457 }
10458 }
10459 else
10460 maxcount = 25;
10461
10462 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10463
10464 for (i = 0; i < ga.ga_len; ++i)
10465 {
10466 str = ((char_u **)ga.ga_data)[i];
10467
10468 li = listitem_alloc();
10469 if (li == NULL)
10470 vim_free(str);
10471 else
10472 {
10473 li->li_tv.v_type = VAR_STRING;
10474 li->li_tv.v_lock = 0;
10475 li->li_tv.vval.v_string = str;
10476 list_append(rettv->vval.v_list, li);
10477 }
10478 }
10479 ga_clear(&ga);
10480 }
10481#endif
10482}
10483
10484 static void
10485f_split(typval_T *argvars, typval_T *rettv)
10486{
10487 char_u *str;
10488 char_u *end;
10489 char_u *pat = NULL;
10490 regmatch_T regmatch;
10491 char_u patbuf[NUMBUFLEN];
10492 char_u *save_cpo;
10493 int match;
10494 colnr_T col = 0;
10495 int keepempty = FALSE;
10496 int typeerr = FALSE;
10497
10498 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10499 save_cpo = p_cpo;
10500 p_cpo = (char_u *)"";
10501
10502 str = get_tv_string(&argvars[0]);
10503 if (argvars[1].v_type != VAR_UNKNOWN)
10504 {
10505 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
10506 if (pat == NULL)
10507 typeerr = TRUE;
10508 if (argvars[2].v_type != VAR_UNKNOWN)
10509 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
10510 }
10511 if (pat == NULL || *pat == NUL)
10512 pat = (char_u *)"[\\x01- ]\\+";
10513
10514 if (rettv_list_alloc(rettv) == FAIL)
10515 return;
10516 if (typeerr)
10517 return;
10518
10519 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10520 if (regmatch.regprog != NULL)
10521 {
10522 regmatch.rm_ic = FALSE;
10523 while (*str != NUL || keepempty)
10524 {
10525 if (*str == NUL)
10526 match = FALSE; /* empty item at the end */
10527 else
10528 match = vim_regexec_nl(&regmatch, str, col);
10529 if (match)
10530 end = regmatch.startp[0];
10531 else
10532 end = str + STRLEN(str);
10533 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10534 && *str != NUL && match && end < regmatch.endp[0]))
10535 {
10536 if (list_append_string(rettv->vval.v_list, str,
10537 (int)(end - str)) == FAIL)
10538 break;
10539 }
10540 if (!match)
10541 break;
10542 /* Advance to just after the match. */
10543 if (regmatch.endp[0] > str)
10544 col = 0;
10545 else
10546 {
10547 /* Don't get stuck at the same match. */
10548#ifdef FEAT_MBYTE
10549 col = (*mb_ptr2len)(regmatch.endp[0]);
10550#else
10551 col = 1;
10552#endif
10553 }
10554 str = regmatch.endp[0];
10555 }
10556
10557 vim_regfree(regmatch.regprog);
10558 }
10559
10560 p_cpo = save_cpo;
10561}
10562
10563#ifdef FEAT_FLOAT
10564/*
10565 * "sqrt()" function
10566 */
10567 static void
10568f_sqrt(typval_T *argvars, typval_T *rettv)
10569{
10570 float_T f = 0.0;
10571
10572 rettv->v_type = VAR_FLOAT;
10573 if (get_float_arg(argvars, &f) == OK)
10574 rettv->vval.v_float = sqrt(f);
10575 else
10576 rettv->vval.v_float = 0.0;
10577}
10578
10579/*
10580 * "str2float()" function
10581 */
10582 static void
10583f_str2float(typval_T *argvars, typval_T *rettv)
10584{
10585 char_u *p = skipwhite(get_tv_string(&argvars[0]));
10586
10587 if (*p == '+')
10588 p = skipwhite(p + 1);
10589 (void)string2float(p, &rettv->vval.v_float);
10590 rettv->v_type = VAR_FLOAT;
10591}
10592#endif
10593
10594/*
10595 * "str2nr()" function
10596 */
10597 static void
10598f_str2nr(typval_T *argvars, typval_T *rettv)
10599{
10600 int base = 10;
10601 char_u *p;
10602 varnumber_T n;
10603 int what;
10604
10605 if (argvars[1].v_type != VAR_UNKNOWN)
10606 {
10607 base = (int)get_tv_number(&argvars[1]);
10608 if (base != 2 && base != 8 && base != 10 && base != 16)
10609 {
10610 EMSG(_(e_invarg));
10611 return;
10612 }
10613 }
10614
10615 p = skipwhite(get_tv_string(&argvars[0]));
10616 if (*p == '+')
10617 p = skipwhite(p + 1);
10618 switch (base)
10619 {
10620 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10621 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10622 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10623 default: what = 0;
10624 }
10625 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
10626 rettv->vval.v_number = n;
10627}
10628
10629#ifdef HAVE_STRFTIME
10630/*
10631 * "strftime({format}[, {time}])" function
10632 */
10633 static void
10634f_strftime(typval_T *argvars, typval_T *rettv)
10635{
10636 char_u result_buf[256];
10637 struct tm *curtime;
10638 time_t seconds;
10639 char_u *p;
10640
10641 rettv->v_type = VAR_STRING;
10642
10643 p = get_tv_string(&argvars[0]);
10644 if (argvars[1].v_type == VAR_UNKNOWN)
10645 seconds = time(NULL);
10646 else
10647 seconds = (time_t)get_tv_number(&argvars[1]);
10648 curtime = localtime(&seconds);
10649 /* MSVC returns NULL for an invalid value of seconds. */
10650 if (curtime == NULL)
10651 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10652 else
10653 {
10654# ifdef FEAT_MBYTE
10655 vimconv_T conv;
10656 char_u *enc;
10657
10658 conv.vc_type = CONV_NONE;
10659 enc = enc_locale();
10660 convert_setup(&conv, p_enc, enc);
10661 if (conv.vc_type != CONV_NONE)
10662 p = string_convert(&conv, p, NULL);
10663# endif
10664 if (p != NULL)
10665 (void)strftime((char *)result_buf, sizeof(result_buf),
10666 (char *)p, curtime);
10667 else
10668 result_buf[0] = NUL;
10669
10670# ifdef FEAT_MBYTE
10671 if (conv.vc_type != CONV_NONE)
10672 vim_free(p);
10673 convert_setup(&conv, enc, p_enc);
10674 if (conv.vc_type != CONV_NONE)
10675 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10676 else
10677# endif
10678 rettv->vval.v_string = vim_strsave(result_buf);
10679
10680# ifdef FEAT_MBYTE
10681 /* Release conversion descriptors */
10682 convert_setup(&conv, NULL, NULL);
10683 vim_free(enc);
10684# endif
10685 }
10686}
10687#endif
10688
10689/*
10690 * "strgetchar()" function
10691 */
10692 static void
10693f_strgetchar(typval_T *argvars, typval_T *rettv)
10694{
10695 char_u *str;
10696 int len;
10697 int error = FALSE;
10698 int charidx;
10699
10700 rettv->vval.v_number = -1;
10701 str = get_tv_string_chk(&argvars[0]);
10702 if (str == NULL)
10703 return;
10704 len = (int)STRLEN(str);
10705 charidx = (int)get_tv_number_chk(&argvars[1], &error);
10706 if (error)
10707 return;
10708#ifdef FEAT_MBYTE
10709 {
10710 int byteidx = 0;
10711
10712 while (charidx >= 0 && byteidx < len)
10713 {
10714 if (charidx == 0)
10715 {
10716 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10717 break;
10718 }
10719 --charidx;
10720 byteidx += mb_cptr2len(str + byteidx);
10721 }
10722 }
10723#else
10724 if (charidx < len)
10725 rettv->vval.v_number = str[charidx];
10726#endif
10727}
10728
10729/*
10730 * "stridx()" function
10731 */
10732 static void
10733f_stridx(typval_T *argvars, typval_T *rettv)
10734{
10735 char_u buf[NUMBUFLEN];
10736 char_u *needle;
10737 char_u *haystack;
10738 char_u *save_haystack;
10739 char_u *pos;
10740 int start_idx;
10741
10742 needle = get_tv_string_chk(&argvars[1]);
10743 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
10744 rettv->vval.v_number = -1;
10745 if (needle == NULL || haystack == NULL)
10746 return; /* type error; errmsg already given */
10747
10748 if (argvars[2].v_type != VAR_UNKNOWN)
10749 {
10750 int error = FALSE;
10751
10752 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
10753 if (error || start_idx >= (int)STRLEN(haystack))
10754 return;
10755 if (start_idx >= 0)
10756 haystack += start_idx;
10757 }
10758
10759 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10760 if (pos != NULL)
10761 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10762}
10763
10764/*
10765 * "string()" function
10766 */
10767 static void
10768f_string(typval_T *argvars, typval_T *rettv)
10769{
10770 char_u *tofree;
10771 char_u numbuf[NUMBUFLEN];
10772
10773 rettv->v_type = VAR_STRING;
10774 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10775 get_copyID());
10776 /* Make a copy if we have a value but it's not in allocated memory. */
10777 if (rettv->vval.v_string != NULL && tofree == NULL)
10778 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10779}
10780
10781/*
10782 * "strlen()" function
10783 */
10784 static void
10785f_strlen(typval_T *argvars, typval_T *rettv)
10786{
10787 rettv->vval.v_number = (varnumber_T)(STRLEN(
10788 get_tv_string(&argvars[0])));
10789}
10790
10791/*
10792 * "strchars()" function
10793 */
10794 static void
10795f_strchars(typval_T *argvars, typval_T *rettv)
10796{
10797 char_u *s = get_tv_string(&argvars[0]);
10798 int skipcc = 0;
10799#ifdef FEAT_MBYTE
10800 varnumber_T len = 0;
10801 int (*func_mb_ptr2char_adv)(char_u **pp);
10802#endif
10803
10804 if (argvars[1].v_type != VAR_UNKNOWN)
10805 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
10806 if (skipcc < 0 || skipcc > 1)
10807 EMSG(_(e_invarg));
10808 else
10809 {
10810#ifdef FEAT_MBYTE
10811 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10812 while (*s != NUL)
10813 {
10814 func_mb_ptr2char_adv(&s);
10815 ++len;
10816 }
10817 rettv->vval.v_number = len;
10818#else
10819 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
10820#endif
10821 }
10822}
10823
10824/*
10825 * "strdisplaywidth()" function
10826 */
10827 static void
10828f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10829{
10830 char_u *s = get_tv_string(&argvars[0]);
10831 int col = 0;
10832
10833 if (argvars[1].v_type != VAR_UNKNOWN)
10834 col = (int)get_tv_number(&argvars[1]);
10835
10836 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10837}
10838
10839/*
10840 * "strwidth()" function
10841 */
10842 static void
10843f_strwidth(typval_T *argvars, typval_T *rettv)
10844{
10845 char_u *s = get_tv_string(&argvars[0]);
10846
10847 rettv->vval.v_number = (varnumber_T)(
10848#ifdef FEAT_MBYTE
10849 mb_string2cells(s, -1)
10850#else
10851 STRLEN(s)
10852#endif
10853 );
10854}
10855
10856/*
10857 * "strcharpart()" function
10858 */
10859 static void
10860f_strcharpart(typval_T *argvars, typval_T *rettv)
10861{
10862#ifdef FEAT_MBYTE
10863 char_u *p;
10864 int nchar;
10865 int nbyte = 0;
10866 int charlen;
10867 int len = 0;
10868 int slen;
10869 int error = FALSE;
10870
10871 p = get_tv_string(&argvars[0]);
10872 slen = (int)STRLEN(p);
10873
10874 nchar = (int)get_tv_number_chk(&argvars[1], &error);
10875 if (!error)
10876 {
10877 if (nchar > 0)
10878 while (nchar > 0 && nbyte < slen)
10879 {
10880 nbyte += mb_cptr2len(p + nbyte);
10881 --nchar;
10882 }
10883 else
10884 nbyte = nchar;
10885 if (argvars[2].v_type != VAR_UNKNOWN)
10886 {
10887 charlen = (int)get_tv_number(&argvars[2]);
10888 while (charlen > 0 && nbyte + len < slen)
10889 {
10890 int off = nbyte + len;
10891
10892 if (off < 0)
10893 len += 1;
10894 else
10895 len += mb_cptr2len(p + off);
10896 --charlen;
10897 }
10898 }
10899 else
10900 len = slen - nbyte; /* default: all bytes that are available. */
10901 }
10902
10903 /*
10904 * Only return the overlap between the specified part and the actual
10905 * string.
10906 */
10907 if (nbyte < 0)
10908 {
10909 len += nbyte;
10910 nbyte = 0;
10911 }
10912 else if (nbyte > slen)
10913 nbyte = slen;
10914 if (len < 0)
10915 len = 0;
10916 else if (nbyte + len > slen)
10917 len = slen - nbyte;
10918
10919 rettv->v_type = VAR_STRING;
10920 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
10921#else
10922 f_strpart(argvars, rettv);
10923#endif
10924}
10925
10926/*
10927 * "strpart()" function
10928 */
10929 static void
10930f_strpart(typval_T *argvars, typval_T *rettv)
10931{
10932 char_u *p;
10933 int n;
10934 int len;
10935 int slen;
10936 int error = FALSE;
10937
10938 p = get_tv_string(&argvars[0]);
10939 slen = (int)STRLEN(p);
10940
10941 n = (int)get_tv_number_chk(&argvars[1], &error);
10942 if (error)
10943 len = 0;
10944 else if (argvars[2].v_type != VAR_UNKNOWN)
10945 len = (int)get_tv_number(&argvars[2]);
10946 else
10947 len = slen - n; /* default len: all bytes that are available. */
10948
10949 /*
10950 * Only return the overlap between the specified part and the actual
10951 * string.
10952 */
10953 if (n < 0)
10954 {
10955 len += n;
10956 n = 0;
10957 }
10958 else if (n > slen)
10959 n = slen;
10960 if (len < 0)
10961 len = 0;
10962 else if (n + len > slen)
10963 len = slen - n;
10964
10965 rettv->v_type = VAR_STRING;
10966 rettv->vval.v_string = vim_strnsave(p + n, len);
10967}
10968
10969/*
10970 * "strridx()" function
10971 */
10972 static void
10973f_strridx(typval_T *argvars, typval_T *rettv)
10974{
10975 char_u buf[NUMBUFLEN];
10976 char_u *needle;
10977 char_u *haystack;
10978 char_u *rest;
10979 char_u *lastmatch = NULL;
10980 int haystack_len, end_idx;
10981
10982 needle = get_tv_string_chk(&argvars[1]);
10983 haystack = get_tv_string_buf_chk(&argvars[0], buf);
10984
10985 rettv->vval.v_number = -1;
10986 if (needle == NULL || haystack == NULL)
10987 return; /* type error; errmsg already given */
10988
10989 haystack_len = (int)STRLEN(haystack);
10990 if (argvars[2].v_type != VAR_UNKNOWN)
10991 {
10992 /* Third argument: upper limit for index */
10993 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
10994 if (end_idx < 0)
10995 return; /* can never find a match */
10996 }
10997 else
10998 end_idx = haystack_len;
10999
11000 if (*needle == NUL)
11001 {
11002 /* Empty string matches past the end. */
11003 lastmatch = haystack + end_idx;
11004 }
11005 else
11006 {
11007 for (rest = haystack; *rest != '\0'; ++rest)
11008 {
11009 rest = (char_u *)strstr((char *)rest, (char *)needle);
11010 if (rest == NULL || rest > haystack + end_idx)
11011 break;
11012 lastmatch = rest;
11013 }
11014 }
11015
11016 if (lastmatch == NULL)
11017 rettv->vval.v_number = -1;
11018 else
11019 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11020}
11021
11022/*
11023 * "strtrans()" function
11024 */
11025 static void
11026f_strtrans(typval_T *argvars, typval_T *rettv)
11027{
11028 rettv->v_type = VAR_STRING;
11029 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11030}
11031
11032/*
11033 * "submatch()" function
11034 */
11035 static void
11036f_submatch(typval_T *argvars, typval_T *rettv)
11037{
11038 int error = FALSE;
11039 int no;
11040 int retList = 0;
11041
11042 no = (int)get_tv_number_chk(&argvars[0], &error);
11043 if (error)
11044 return;
11045 error = FALSE;
11046 if (argvars[1].v_type != VAR_UNKNOWN)
11047 retList = (int)get_tv_number_chk(&argvars[1], &error);
11048 if (error)
11049 return;
11050
11051 if (retList == 0)
11052 {
11053 rettv->v_type = VAR_STRING;
11054 rettv->vval.v_string = reg_submatch(no);
11055 }
11056 else
11057 {
11058 rettv->v_type = VAR_LIST;
11059 rettv->vval.v_list = reg_submatch_list(no);
11060 }
11061}
11062
11063/*
11064 * "substitute()" function
11065 */
11066 static void
11067f_substitute(typval_T *argvars, typval_T *rettv)
11068{
11069 char_u patbuf[NUMBUFLEN];
11070 char_u subbuf[NUMBUFLEN];
11071 char_u flagsbuf[NUMBUFLEN];
11072
11073 char_u *str = get_tv_string_chk(&argvars[0]);
11074 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011075 char_u *sub = NULL;
11076 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011077 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11078
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011079 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11080 expr = &argvars[2];
11081 else
11082 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11083
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011084 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011085 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11086 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011087 rettv->vval.v_string = NULL;
11088 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011089 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011090}
11091
11092/*
11093 * "synID(lnum, col, trans)" function
11094 */
11095 static void
11096f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11097{
11098 int id = 0;
11099#ifdef FEAT_SYN_HL
11100 linenr_T lnum;
11101 colnr_T col;
11102 int trans;
11103 int transerr = FALSE;
11104
11105 lnum = get_tv_lnum(argvars); /* -1 on type error */
11106 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11107 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11108
11109 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11110 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11111 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11112#endif
11113
11114 rettv->vval.v_number = id;
11115}
11116
11117/*
11118 * "synIDattr(id, what [, mode])" function
11119 */
11120 static void
11121f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11122{
11123 char_u *p = NULL;
11124#ifdef FEAT_SYN_HL
11125 int id;
11126 char_u *what;
11127 char_u *mode;
11128 char_u modebuf[NUMBUFLEN];
11129 int modec;
11130
11131 id = (int)get_tv_number(&argvars[0]);
11132 what = get_tv_string(&argvars[1]);
11133 if (argvars[2].v_type != VAR_UNKNOWN)
11134 {
11135 mode = get_tv_string_buf(&argvars[2], modebuf);
11136 modec = TOLOWER_ASC(mode[0]);
11137 if (modec != 't' && modec != 'c' && modec != 'g')
11138 modec = 0; /* replace invalid with current */
11139 }
11140 else
11141 {
11142#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11143 if (USE_24BIT)
11144 modec = 'g';
11145 else
11146#endif
11147 if (t_colors > 1)
11148 modec = 'c';
11149 else
11150 modec = 't';
11151 }
11152
11153
11154 switch (TOLOWER_ASC(what[0]))
11155 {
11156 case 'b':
11157 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11158 p = highlight_color(id, what, modec);
11159 else /* bold */
11160 p = highlight_has_attr(id, HL_BOLD, modec);
11161 break;
11162
11163 case 'f': /* fg[#] or font */
11164 p = highlight_color(id, what, modec);
11165 break;
11166
11167 case 'i':
11168 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11169 p = highlight_has_attr(id, HL_INVERSE, modec);
11170 else /* italic */
11171 p = highlight_has_attr(id, HL_ITALIC, modec);
11172 break;
11173
11174 case 'n': /* name */
11175 p = get_highlight_name(NULL, id - 1);
11176 break;
11177
11178 case 'r': /* reverse */
11179 p = highlight_has_attr(id, HL_INVERSE, modec);
11180 break;
11181
11182 case 's':
11183 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11184 p = highlight_color(id, what, modec);
11185 else /* standout */
11186 p = highlight_has_attr(id, HL_STANDOUT, modec);
11187 break;
11188
11189 case 'u':
11190 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11191 /* underline */
11192 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11193 else
11194 /* undercurl */
11195 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11196 break;
11197 }
11198
11199 if (p != NULL)
11200 p = vim_strsave(p);
11201#endif
11202 rettv->v_type = VAR_STRING;
11203 rettv->vval.v_string = p;
11204}
11205
11206/*
11207 * "synIDtrans(id)" function
11208 */
11209 static void
11210f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11211{
11212 int id;
11213
11214#ifdef FEAT_SYN_HL
11215 id = (int)get_tv_number(&argvars[0]);
11216
11217 if (id > 0)
11218 id = syn_get_final_id(id);
11219 else
11220#endif
11221 id = 0;
11222
11223 rettv->vval.v_number = id;
11224}
11225
11226/*
11227 * "synconcealed(lnum, col)" function
11228 */
11229 static void
11230f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11231{
11232#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11233 linenr_T lnum;
11234 colnr_T col;
11235 int syntax_flags = 0;
11236 int cchar;
11237 int matchid = 0;
11238 char_u str[NUMBUFLEN];
11239#endif
11240
11241 rettv->v_type = VAR_LIST;
11242 rettv->vval.v_list = NULL;
11243
11244#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11245 lnum = get_tv_lnum(argvars); /* -1 on type error */
11246 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11247
11248 vim_memset(str, NUL, sizeof(str));
11249
11250 if (rettv_list_alloc(rettv) != FAIL)
11251 {
11252 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11253 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11254 && curwin->w_p_cole > 0)
11255 {
11256 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11257 syntax_flags = get_syntax_info(&matchid);
11258
11259 /* get the conceal character */
11260 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11261 {
11262 cchar = syn_get_sub_char();
11263 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL)
11264 cchar = lcs_conceal;
11265 if (cchar != NUL)
11266 {
11267# ifdef FEAT_MBYTE
11268 if (has_mbyte)
11269 (*mb_char2bytes)(cchar, str);
11270 else
11271# endif
11272 str[0] = cchar;
11273 }
11274 }
11275 }
11276
11277 list_append_number(rettv->vval.v_list,
11278 (syntax_flags & HL_CONCEAL) != 0);
11279 /* -1 to auto-determine strlen */
11280 list_append_string(rettv->vval.v_list, str, -1);
11281 list_append_number(rettv->vval.v_list, matchid);
11282 }
11283#endif
11284}
11285
11286/*
11287 * "synstack(lnum, col)" function
11288 */
11289 static void
11290f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11291{
11292#ifdef FEAT_SYN_HL
11293 linenr_T lnum;
11294 colnr_T col;
11295 int i;
11296 int id;
11297#endif
11298
11299 rettv->v_type = VAR_LIST;
11300 rettv->vval.v_list = NULL;
11301
11302#ifdef FEAT_SYN_HL
11303 lnum = get_tv_lnum(argvars); /* -1 on type error */
11304 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11305
11306 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11307 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11308 && rettv_list_alloc(rettv) != FAIL)
11309 {
11310 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11311 for (i = 0; ; ++i)
11312 {
11313 id = syn_get_stack_item(i);
11314 if (id < 0)
11315 break;
11316 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11317 break;
11318 }
11319 }
11320#endif
11321}
11322
11323 static void
11324get_cmd_output_as_rettv(
11325 typval_T *argvars,
11326 typval_T *rettv,
11327 int retlist)
11328{
11329 char_u *res = NULL;
11330 char_u *p;
11331 char_u *infile = NULL;
11332 char_u buf[NUMBUFLEN];
11333 int err = FALSE;
11334 FILE *fd;
11335 list_T *list = NULL;
11336 int flags = SHELL_SILENT;
11337
11338 rettv->v_type = VAR_STRING;
11339 rettv->vval.v_string = NULL;
11340 if (check_restricted() || check_secure())
11341 goto errret;
11342
11343 if (argvars[1].v_type != VAR_UNKNOWN)
11344 {
11345 /*
11346 * Write the string to a temp file, to be used for input of the shell
11347 * command.
11348 */
11349 if ((infile = vim_tempname('i', TRUE)) == NULL)
11350 {
11351 EMSG(_(e_notmp));
11352 goto errret;
11353 }
11354
11355 fd = mch_fopen((char *)infile, WRITEBIN);
11356 if (fd == NULL)
11357 {
11358 EMSG2(_(e_notopen), infile);
11359 goto errret;
11360 }
11361 if (argvars[1].v_type == VAR_LIST)
11362 {
11363 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11364 err = TRUE;
11365 }
11366 else
11367 {
11368 size_t len;
11369
11370 p = get_tv_string_buf_chk(&argvars[1], buf);
11371 if (p == NULL)
11372 {
11373 fclose(fd);
11374 goto errret; /* type error; errmsg already given */
11375 }
11376 len = STRLEN(p);
11377 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11378 err = TRUE;
11379 }
11380 if (fclose(fd) != 0)
11381 err = TRUE;
11382 if (err)
11383 {
11384 EMSG(_("E677: Error writing temp file"));
11385 goto errret;
11386 }
11387 }
11388
11389 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11390 * echoes typeahead, that messes up the display. */
11391 if (!msg_silent)
11392 flags += SHELL_COOKED;
11393
11394 if (retlist)
11395 {
11396 int len;
11397 listitem_T *li;
11398 char_u *s = NULL;
11399 char_u *start;
11400 char_u *end;
11401 int i;
11402
11403 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
11404 if (res == NULL)
11405 goto errret;
11406
11407 list = list_alloc();
11408 if (list == NULL)
11409 goto errret;
11410
11411 for (i = 0; i < len; ++i)
11412 {
11413 start = res + i;
11414 while (i < len && res[i] != NL)
11415 ++i;
11416 end = res + i;
11417
11418 s = alloc((unsigned)(end - start + 1));
11419 if (s == NULL)
11420 goto errret;
11421
11422 for (p = s; start < end; ++p, ++start)
11423 *p = *start == NUL ? NL : *start;
11424 *p = NUL;
11425
11426 li = listitem_alloc();
11427 if (li == NULL)
11428 {
11429 vim_free(s);
11430 goto errret;
11431 }
11432 li->li_tv.v_type = VAR_STRING;
11433 li->li_tv.v_lock = 0;
11434 li->li_tv.vval.v_string = s;
11435 list_append(list, li);
11436 }
11437
11438 ++list->lv_refcount;
11439 rettv->v_type = VAR_LIST;
11440 rettv->vval.v_list = list;
11441 list = NULL;
11442 }
11443 else
11444 {
11445 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
11446#ifdef USE_CR
11447 /* translate <CR> into <NL> */
11448 if (res != NULL)
11449 {
11450 char_u *s;
11451
11452 for (s = res; *s; ++s)
11453 {
11454 if (*s == CAR)
11455 *s = NL;
11456 }
11457 }
11458#else
11459# ifdef USE_CRNL
11460 /* translate <CR><NL> into <NL> */
11461 if (res != NULL)
11462 {
11463 char_u *s, *d;
11464
11465 d = res;
11466 for (s = res; *s; ++s)
11467 {
11468 if (s[0] == CAR && s[1] == NL)
11469 ++s;
11470 *d++ = *s;
11471 }
11472 *d = NUL;
11473 }
11474# endif
11475#endif
11476 rettv->vval.v_string = res;
11477 res = NULL;
11478 }
11479
11480errret:
11481 if (infile != NULL)
11482 {
11483 mch_remove(infile);
11484 vim_free(infile);
11485 }
11486 if (res != NULL)
11487 vim_free(res);
11488 if (list != NULL)
11489 list_free(list);
11490}
11491
11492/*
11493 * "system()" function
11494 */
11495 static void
11496f_system(typval_T *argvars, typval_T *rettv)
11497{
11498 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11499}
11500
11501/*
11502 * "systemlist()" function
11503 */
11504 static void
11505f_systemlist(typval_T *argvars, typval_T *rettv)
11506{
11507 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11508}
11509
11510/*
11511 * "tabpagebuflist()" function
11512 */
11513 static void
11514f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11515{
11516#ifdef FEAT_WINDOWS
11517 tabpage_T *tp;
11518 win_T *wp = NULL;
11519
11520 if (argvars[0].v_type == VAR_UNKNOWN)
11521 wp = firstwin;
11522 else
11523 {
11524 tp = find_tabpage((int)get_tv_number(&argvars[0]));
11525 if (tp != NULL)
11526 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11527 }
11528 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11529 {
11530 for (; wp != NULL; wp = wp->w_next)
11531 if (list_append_number(rettv->vval.v_list,
11532 wp->w_buffer->b_fnum) == FAIL)
11533 break;
11534 }
11535#endif
11536}
11537
11538
11539/*
11540 * "tabpagenr()" function
11541 */
11542 static void
11543f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11544{
11545 int nr = 1;
11546#ifdef FEAT_WINDOWS
11547 char_u *arg;
11548
11549 if (argvars[0].v_type != VAR_UNKNOWN)
11550 {
11551 arg = get_tv_string_chk(&argvars[0]);
11552 nr = 0;
11553 if (arg != NULL)
11554 {
11555 if (STRCMP(arg, "$") == 0)
11556 nr = tabpage_index(NULL) - 1;
11557 else
11558 EMSG2(_(e_invexpr2), arg);
11559 }
11560 }
11561 else
11562 nr = tabpage_index(curtab);
11563#endif
11564 rettv->vval.v_number = nr;
11565}
11566
11567
11568#ifdef FEAT_WINDOWS
11569static int get_winnr(tabpage_T *tp, typval_T *argvar);
11570
11571/*
11572 * Common code for tabpagewinnr() and winnr().
11573 */
11574 static int
11575get_winnr(tabpage_T *tp, typval_T *argvar)
11576{
11577 win_T *twin;
11578 int nr = 1;
11579 win_T *wp;
11580 char_u *arg;
11581
11582 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11583 if (argvar->v_type != VAR_UNKNOWN)
11584 {
11585 arg = get_tv_string_chk(argvar);
11586 if (arg == NULL)
11587 nr = 0; /* type error; errmsg already given */
11588 else if (STRCMP(arg, "$") == 0)
11589 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11590 else if (STRCMP(arg, "#") == 0)
11591 {
11592 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11593 if (twin == NULL)
11594 nr = 0;
11595 }
11596 else
11597 {
11598 EMSG2(_(e_invexpr2), arg);
11599 nr = 0;
11600 }
11601 }
11602
11603 if (nr > 0)
11604 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11605 wp != twin; wp = wp->w_next)
11606 {
11607 if (wp == NULL)
11608 {
11609 /* didn't find it in this tabpage */
11610 nr = 0;
11611 break;
11612 }
11613 ++nr;
11614 }
11615 return nr;
11616}
11617#endif
11618
11619/*
11620 * "tabpagewinnr()" function
11621 */
11622 static void
11623f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11624{
11625 int nr = 1;
11626#ifdef FEAT_WINDOWS
11627 tabpage_T *tp;
11628
11629 tp = find_tabpage((int)get_tv_number(&argvars[0]));
11630 if (tp == NULL)
11631 nr = 0;
11632 else
11633 nr = get_winnr(tp, &argvars[1]);
11634#endif
11635 rettv->vval.v_number = nr;
11636}
11637
11638
11639/*
11640 * "tagfiles()" function
11641 */
11642 static void
11643f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11644{
11645 char_u *fname;
11646 tagname_T tn;
11647 int first;
11648
11649 if (rettv_list_alloc(rettv) == FAIL)
11650 return;
11651 fname = alloc(MAXPATHL);
11652 if (fname == NULL)
11653 return;
11654
11655 for (first = TRUE; ; first = FALSE)
11656 if (get_tagfname(&tn, first, fname) == FAIL
11657 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11658 break;
11659 tagname_free(&tn);
11660 vim_free(fname);
11661}
11662
11663/*
11664 * "taglist()" function
11665 */
11666 static void
11667f_taglist(typval_T *argvars, typval_T *rettv)
11668{
11669 char_u *tag_pattern;
11670
11671 tag_pattern = get_tv_string(&argvars[0]);
11672
11673 rettv->vval.v_number = FALSE;
11674 if (*tag_pattern == NUL)
11675 return;
11676
11677 if (rettv_list_alloc(rettv) == OK)
11678 (void)get_tags(rettv->vval.v_list, tag_pattern);
11679}
11680
11681/*
11682 * "tempname()" function
11683 */
11684 static void
11685f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11686{
11687 static int x = 'A';
11688
11689 rettv->v_type = VAR_STRING;
11690 rettv->vval.v_string = vim_tempname(x, FALSE);
11691
11692 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11693 * names. Skip 'I' and 'O', they are used for shell redirection. */
11694 do
11695 {
11696 if (x == 'Z')
11697 x = '0';
11698 else if (x == '9')
11699 x = 'A';
11700 else
11701 {
11702#ifdef EBCDIC
11703 if (x == 'I')
11704 x = 'J';
11705 else if (x == 'R')
11706 x = 'S';
11707 else
11708#endif
11709 ++x;
11710 }
11711 } while (x == 'I' || x == 'O');
11712}
11713
11714#ifdef FEAT_FLOAT
11715/*
11716 * "tan()" function
11717 */
11718 static void
11719f_tan(typval_T *argvars, typval_T *rettv)
11720{
11721 float_T f = 0.0;
11722
11723 rettv->v_type = VAR_FLOAT;
11724 if (get_float_arg(argvars, &f) == OK)
11725 rettv->vval.v_float = tan(f);
11726 else
11727 rettv->vval.v_float = 0.0;
11728}
11729
11730/*
11731 * "tanh()" function
11732 */
11733 static void
11734f_tanh(typval_T *argvars, typval_T *rettv)
11735{
11736 float_T f = 0.0;
11737
11738 rettv->v_type = VAR_FLOAT;
11739 if (get_float_arg(argvars, &f) == OK)
11740 rettv->vval.v_float = tanh(f);
11741 else
11742 rettv->vval.v_float = 0.0;
11743}
11744#endif
11745
11746/*
11747 * "test_alloc_fail(id, countdown, repeat)" function
11748 */
11749 static void
11750f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
11751{
11752 if (argvars[0].v_type != VAR_NUMBER
11753 || argvars[0].vval.v_number <= 0
11754 || argvars[1].v_type != VAR_NUMBER
11755 || argvars[1].vval.v_number < 0
11756 || argvars[2].v_type != VAR_NUMBER)
11757 EMSG(_(e_invarg));
11758 else
11759 {
11760 alloc_fail_id = argvars[0].vval.v_number;
11761 if (alloc_fail_id >= aid_last)
11762 EMSG(_(e_invarg));
11763 alloc_fail_countdown = argvars[1].vval.v_number;
11764 alloc_fail_repeat = argvars[2].vval.v_number;
11765 did_outofmem_msg = FALSE;
11766 }
11767}
11768
11769/*
11770 * "test_autochdir()"
11771 */
11772 static void
11773f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11774{
11775#if defined(FEAT_AUTOCHDIR)
11776 test_autochdir = TRUE;
11777#endif
11778}
11779
11780/*
11781 * "test_disable_char_avail({expr})" function
11782 */
11783 static void
11784f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED)
11785{
11786 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]);
11787}
11788
11789/*
11790 * "test_garbagecollect_now()" function
11791 */
11792 static void
11793f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11794{
11795 /* This is dangerous, any Lists and Dicts used internally may be freed
11796 * while still in use. */
11797 garbage_collect(TRUE);
11798}
11799
11800#ifdef FEAT_JOB_CHANNEL
11801 static void
11802f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
11803{
11804 rettv->v_type = VAR_CHANNEL;
11805 rettv->vval.v_channel = NULL;
11806}
11807#endif
11808
11809 static void
11810f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
11811{
11812 rettv->v_type = VAR_DICT;
11813 rettv->vval.v_dict = NULL;
11814}
11815
11816#ifdef FEAT_JOB_CHANNEL
11817 static void
11818f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
11819{
11820 rettv->v_type = VAR_JOB;
11821 rettv->vval.v_job = NULL;
11822}
11823#endif
11824
11825 static void
11826f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
11827{
11828 rettv->v_type = VAR_LIST;
11829 rettv->vval.v_list = NULL;
11830}
11831
11832 static void
11833f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
11834{
11835 rettv->v_type = VAR_PARTIAL;
11836 rettv->vval.v_partial = NULL;
11837}
11838
11839 static void
11840f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
11841{
11842 rettv->v_type = VAR_STRING;
11843 rettv->vval.v_string = NULL;
11844}
11845
11846 static void
11847f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
11848{
11849 time_for_testing = (time_t)get_tv_number(&argvars[0]);
11850}
11851
11852#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
11853/*
11854 * Get a callback from "arg". It can be a Funcref or a function name.
11855 * When "arg" is zero return an empty string.
11856 * Return NULL for an invalid argument.
11857 */
11858 char_u *
11859get_callback(typval_T *arg, partial_T **pp)
11860{
11861 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11862 {
11863 *pp = arg->vval.v_partial;
11864 ++(*pp)->pt_refcount;
11865 return (*pp)->pt_name;
11866 }
11867 *pp = NULL;
11868 if (arg->v_type == VAR_FUNC)
11869 {
11870 func_ref(arg->vval.v_string);
11871 return arg->vval.v_string;
11872 }
11873 if (arg->v_type == VAR_STRING)
11874 return arg->vval.v_string;
11875 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11876 return (char_u *)"";
11877 EMSG(_("E921: Invalid callback argument"));
11878 return NULL;
11879}
11880
11881/*
11882 * Unref/free "callback" and "partial" retured by get_callback().
11883 */
11884 void
11885free_callback(char_u *callback, partial_T *partial)
11886{
11887 if (partial != NULL)
11888 partial_unref(partial);
11889 else if (callback != NULL)
11890 {
11891 func_unref(callback);
11892 vim_free(callback);
11893 }
11894}
11895#endif
11896
11897#ifdef FEAT_TIMERS
11898/*
11899 * "timer_start(time, callback [, options])" function
11900 */
11901 static void
11902f_timer_start(typval_T *argvars, typval_T *rettv)
11903{
11904 long msec = (long)get_tv_number(&argvars[0]);
11905 timer_T *timer;
11906 int repeat = 0;
11907 char_u *callback;
11908 dict_T *dict;
11909
11910 if (check_secure())
11911 return;
11912 if (argvars[2].v_type != VAR_UNKNOWN)
11913 {
11914 if (argvars[2].v_type != VAR_DICT
11915 || (dict = argvars[2].vval.v_dict) == NULL)
11916 {
11917 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
11918 return;
11919 }
11920 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
11921 repeat = get_dict_number(dict, (char_u *)"repeat");
11922 }
11923
11924 timer = create_timer(msec, repeat);
11925 callback = get_callback(&argvars[1], &timer->tr_partial);
11926 if (callback == NULL)
11927 {
11928 stop_timer(timer);
11929 rettv->vval.v_number = -1;
11930 }
11931 else
11932 {
11933 timer->tr_callback = vim_strsave(callback);
11934 rettv->vval.v_number = timer->tr_id;
11935 }
11936}
11937
11938/*
11939 * "timer_stop(timer)" function
11940 */
11941 static void
11942f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
11943{
11944 timer_T *timer;
11945
11946 if (argvars[0].v_type != VAR_NUMBER)
11947 {
11948 EMSG(_(e_number_exp));
11949 return;
11950 }
11951 timer = find_timer((int)get_tv_number(&argvars[0]));
11952 if (timer != NULL)
11953 stop_timer(timer);
11954}
11955#endif
11956
11957/*
11958 * "tolower(string)" function
11959 */
11960 static void
11961f_tolower(typval_T *argvars, typval_T *rettv)
11962{
11963 char_u *p;
11964
11965 p = vim_strsave(get_tv_string(&argvars[0]));
11966 rettv->v_type = VAR_STRING;
11967 rettv->vval.v_string = p;
11968
11969 if (p != NULL)
11970 while (*p != NUL)
11971 {
11972#ifdef FEAT_MBYTE
11973 int l;
11974
11975 if (enc_utf8)
11976 {
11977 int c, lc;
11978
11979 c = utf_ptr2char(p);
11980 lc = utf_tolower(c);
11981 l = utf_ptr2len(p);
11982 /* TODO: reallocate string when byte count changes. */
11983 if (utf_char2len(lc) == l)
11984 utf_char2bytes(lc, p);
11985 p += l;
11986 }
11987 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
11988 p += l; /* skip multi-byte character */
11989 else
11990#endif
11991 {
11992 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
11993 ++p;
11994 }
11995 }
11996}
11997
11998/*
11999 * "toupper(string)" function
12000 */
12001 static void
12002f_toupper(typval_T *argvars, typval_T *rettv)
12003{
12004 rettv->v_type = VAR_STRING;
12005 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12006}
12007
12008/*
12009 * "tr(string, fromstr, tostr)" function
12010 */
12011 static void
12012f_tr(typval_T *argvars, typval_T *rettv)
12013{
12014 char_u *in_str;
12015 char_u *fromstr;
12016 char_u *tostr;
12017 char_u *p;
12018#ifdef FEAT_MBYTE
12019 int inlen;
12020 int fromlen;
12021 int tolen;
12022 int idx;
12023 char_u *cpstr;
12024 int cplen;
12025 int first = TRUE;
12026#endif
12027 char_u buf[NUMBUFLEN];
12028 char_u buf2[NUMBUFLEN];
12029 garray_T ga;
12030
12031 in_str = get_tv_string(&argvars[0]);
12032 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12033 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12034
12035 /* Default return value: empty string. */
12036 rettv->v_type = VAR_STRING;
12037 rettv->vval.v_string = NULL;
12038 if (fromstr == NULL || tostr == NULL)
12039 return; /* type error; errmsg already given */
12040 ga_init2(&ga, (int)sizeof(char), 80);
12041
12042#ifdef FEAT_MBYTE
12043 if (!has_mbyte)
12044#endif
12045 /* not multi-byte: fromstr and tostr must be the same length */
12046 if (STRLEN(fromstr) != STRLEN(tostr))
12047 {
12048#ifdef FEAT_MBYTE
12049error:
12050#endif
12051 EMSG2(_(e_invarg2), fromstr);
12052 ga_clear(&ga);
12053 return;
12054 }
12055
12056 /* fromstr and tostr have to contain the same number of chars */
12057 while (*in_str != NUL)
12058 {
12059#ifdef FEAT_MBYTE
12060 if (has_mbyte)
12061 {
12062 inlen = (*mb_ptr2len)(in_str);
12063 cpstr = in_str;
12064 cplen = inlen;
12065 idx = 0;
12066 for (p = fromstr; *p != NUL; p += fromlen)
12067 {
12068 fromlen = (*mb_ptr2len)(p);
12069 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12070 {
12071 for (p = tostr; *p != NUL; p += tolen)
12072 {
12073 tolen = (*mb_ptr2len)(p);
12074 if (idx-- == 0)
12075 {
12076 cplen = tolen;
12077 cpstr = p;
12078 break;
12079 }
12080 }
12081 if (*p == NUL) /* tostr is shorter than fromstr */
12082 goto error;
12083 break;
12084 }
12085 ++idx;
12086 }
12087
12088 if (first && cpstr == in_str)
12089 {
12090 /* Check that fromstr and tostr have the same number of
12091 * (multi-byte) characters. Done only once when a character
12092 * of in_str doesn't appear in fromstr. */
12093 first = FALSE;
12094 for (p = tostr; *p != NUL; p += tolen)
12095 {
12096 tolen = (*mb_ptr2len)(p);
12097 --idx;
12098 }
12099 if (idx != 0)
12100 goto error;
12101 }
12102
12103 (void)ga_grow(&ga, cplen);
12104 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12105 ga.ga_len += cplen;
12106
12107 in_str += inlen;
12108 }
12109 else
12110#endif
12111 {
12112 /* When not using multi-byte chars we can do it faster. */
12113 p = vim_strchr(fromstr, *in_str);
12114 if (p != NULL)
12115 ga_append(&ga, tostr[p - fromstr]);
12116 else
12117 ga_append(&ga, *in_str);
12118 ++in_str;
12119 }
12120 }
12121
12122 /* add a terminating NUL */
12123 (void)ga_grow(&ga, 1);
12124 ga_append(&ga, NUL);
12125
12126 rettv->vval.v_string = ga.ga_data;
12127}
12128
12129#ifdef FEAT_FLOAT
12130/*
12131 * "trunc({float})" function
12132 */
12133 static void
12134f_trunc(typval_T *argvars, typval_T *rettv)
12135{
12136 float_T f = 0.0;
12137
12138 rettv->v_type = VAR_FLOAT;
12139 if (get_float_arg(argvars, &f) == OK)
12140 /* trunc() is not in C90, use floor() or ceil() instead. */
12141 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12142 else
12143 rettv->vval.v_float = 0.0;
12144}
12145#endif
12146
12147/*
12148 * "type(expr)" function
12149 */
12150 static void
12151f_type(typval_T *argvars, typval_T *rettv)
12152{
12153 int n = -1;
12154
12155 switch (argvars[0].v_type)
12156 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012157 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12158 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012159 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012160 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12161 case VAR_LIST: n = VAR_TYPE_LIST; break;
12162 case VAR_DICT: n = VAR_TYPE_DICT; break;
12163 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012164 case VAR_SPECIAL:
12165 if (argvars[0].vval.v_number == VVAL_FALSE
12166 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012167 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012168 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012169 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012170 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012171 case VAR_JOB: n = VAR_TYPE_JOB; break;
12172 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012173 case VAR_UNKNOWN:
12174 EMSG2(_(e_intern2), "f_type(UNKNOWN)");
12175 n = -1;
12176 break;
12177 }
12178 rettv->vval.v_number = n;
12179}
12180
12181/*
12182 * "undofile(name)" function
12183 */
12184 static void
12185f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12186{
12187 rettv->v_type = VAR_STRING;
12188#ifdef FEAT_PERSISTENT_UNDO
12189 {
12190 char_u *fname = get_tv_string(&argvars[0]);
12191
12192 if (*fname == NUL)
12193 {
12194 /* If there is no file name there will be no undo file. */
12195 rettv->vval.v_string = NULL;
12196 }
12197 else
12198 {
12199 char_u *ffname = FullName_save(fname, FALSE);
12200
12201 if (ffname != NULL)
12202 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12203 vim_free(ffname);
12204 }
12205 }
12206#else
12207 rettv->vval.v_string = NULL;
12208#endif
12209}
12210
12211/*
12212 * "undotree()" function
12213 */
12214 static void
12215f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12216{
12217 if (rettv_dict_alloc(rettv) == OK)
12218 {
12219 dict_T *dict = rettv->vval.v_dict;
12220 list_T *list;
12221
12222 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12223 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12224 dict_add_nr_str(dict, "save_last",
12225 (long)curbuf->b_u_save_nr_last, NULL);
12226 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12227 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12228 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12229
12230 list = list_alloc();
12231 if (list != NULL)
12232 {
12233 u_eval_tree(curbuf->b_u_oldhead, list);
12234 dict_add_list(dict, "entries", list);
12235 }
12236 }
12237}
12238
12239/*
12240 * "values(dict)" function
12241 */
12242 static void
12243f_values(typval_T *argvars, typval_T *rettv)
12244{
12245 dict_list(argvars, rettv, 1);
12246}
12247
12248/*
12249 * "virtcol(string)" function
12250 */
12251 static void
12252f_virtcol(typval_T *argvars, typval_T *rettv)
12253{
12254 colnr_T vcol = 0;
12255 pos_T *fp;
12256 int fnum = curbuf->b_fnum;
12257
12258 fp = var2fpos(&argvars[0], FALSE, &fnum);
12259 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12260 && fnum == curbuf->b_fnum)
12261 {
12262 getvvcol(curwin, fp, NULL, NULL, &vcol);
12263 ++vcol;
12264 }
12265
12266 rettv->vval.v_number = vcol;
12267}
12268
12269/*
12270 * "visualmode()" function
12271 */
12272 static void
12273f_visualmode(typval_T *argvars, typval_T *rettv)
12274{
12275 char_u str[2];
12276
12277 rettv->v_type = VAR_STRING;
12278 str[0] = curbuf->b_visual_mode_eval;
12279 str[1] = NUL;
12280 rettv->vval.v_string = vim_strsave(str);
12281
12282 /* A non-zero number or non-empty string argument: reset mode. */
12283 if (non_zero_arg(&argvars[0]))
12284 curbuf->b_visual_mode_eval = NUL;
12285}
12286
12287/*
12288 * "wildmenumode()" function
12289 */
12290 static void
12291f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12292{
12293#ifdef FEAT_WILDMENU
12294 if (wild_menu_showing)
12295 rettv->vval.v_number = 1;
12296#endif
12297}
12298
12299/*
12300 * "winbufnr(nr)" function
12301 */
12302 static void
12303f_winbufnr(typval_T *argvars, typval_T *rettv)
12304{
12305 win_T *wp;
12306
12307 wp = find_win_by_nr(&argvars[0], NULL);
12308 if (wp == NULL)
12309 rettv->vval.v_number = -1;
12310 else
12311 rettv->vval.v_number = wp->w_buffer->b_fnum;
12312}
12313
12314/*
12315 * "wincol()" function
12316 */
12317 static void
12318f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12319{
12320 validate_cursor();
12321 rettv->vval.v_number = curwin->w_wcol + 1;
12322}
12323
12324/*
12325 * "winheight(nr)" function
12326 */
12327 static void
12328f_winheight(typval_T *argvars, typval_T *rettv)
12329{
12330 win_T *wp;
12331
12332 wp = find_win_by_nr(&argvars[0], NULL);
12333 if (wp == NULL)
12334 rettv->vval.v_number = -1;
12335 else
12336 rettv->vval.v_number = wp->w_height;
12337}
12338
12339/*
12340 * "winline()" function
12341 */
12342 static void
12343f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12344{
12345 validate_cursor();
12346 rettv->vval.v_number = curwin->w_wrow + 1;
12347}
12348
12349/*
12350 * "winnr()" function
12351 */
12352 static void
12353f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12354{
12355 int nr = 1;
12356
12357#ifdef FEAT_WINDOWS
12358 nr = get_winnr(curtab, &argvars[0]);
12359#endif
12360 rettv->vval.v_number = nr;
12361}
12362
12363/*
12364 * "winrestcmd()" function
12365 */
12366 static void
12367f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12368{
12369#ifdef FEAT_WINDOWS
12370 win_T *wp;
12371 int winnr = 1;
12372 garray_T ga;
12373 char_u buf[50];
12374
12375 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012376 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012377 {
12378 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12379 ga_concat(&ga, buf);
12380 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12381 ga_concat(&ga, buf);
12382 ++winnr;
12383 }
12384 ga_append(&ga, NUL);
12385
12386 rettv->vval.v_string = ga.ga_data;
12387#else
12388 rettv->vval.v_string = NULL;
12389#endif
12390 rettv->v_type = VAR_STRING;
12391}
12392
12393/*
12394 * "winrestview()" function
12395 */
12396 static void
12397f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12398{
12399 dict_T *dict;
12400
12401 if (argvars[0].v_type != VAR_DICT
12402 || (dict = argvars[0].vval.v_dict) == NULL)
12403 EMSG(_(e_invarg));
12404 else
12405 {
12406 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
12407 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
12408 if (dict_find(dict, (char_u *)"col", -1) != NULL)
12409 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
12410#ifdef FEAT_VIRTUALEDIT
12411 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
12412 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
12413#endif
12414 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12415 {
12416 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
12417 curwin->w_set_curswant = FALSE;
12418 }
12419
12420 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
12421 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
12422#ifdef FEAT_DIFF
12423 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
12424 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
12425#endif
12426 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
12427 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
12428 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
12429 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
12430
12431 check_cursor();
12432 win_new_height(curwin, curwin->w_height);
12433# ifdef FEAT_WINDOWS
12434 win_new_width(curwin, W_WIDTH(curwin));
12435# endif
12436 changed_window_setting();
12437
12438 if (curwin->w_topline <= 0)
12439 curwin->w_topline = 1;
12440 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12441 curwin->w_topline = curbuf->b_ml.ml_line_count;
12442#ifdef FEAT_DIFF
12443 check_topfill(curwin, TRUE);
12444#endif
12445 }
12446}
12447
12448/*
12449 * "winsaveview()" function
12450 */
12451 static void
12452f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12453{
12454 dict_T *dict;
12455
12456 if (rettv_dict_alloc(rettv) == FAIL)
12457 return;
12458 dict = rettv->vval.v_dict;
12459
12460 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
12461 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
12462#ifdef FEAT_VIRTUALEDIT
12463 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
12464#endif
12465 update_curswant();
12466 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
12467
12468 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
12469#ifdef FEAT_DIFF
12470 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
12471#endif
12472 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
12473 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
12474}
12475
12476/*
12477 * "winwidth(nr)" function
12478 */
12479 static void
12480f_winwidth(typval_T *argvars, typval_T *rettv)
12481{
12482 win_T *wp;
12483
12484 wp = find_win_by_nr(&argvars[0], NULL);
12485 if (wp == NULL)
12486 rettv->vval.v_number = -1;
12487 else
12488#ifdef FEAT_WINDOWS
12489 rettv->vval.v_number = wp->w_width;
12490#else
12491 rettv->vval.v_number = Columns;
12492#endif
12493}
12494
12495/*
12496 * "wordcount()" function
12497 */
12498 static void
12499f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12500{
12501 if (rettv_dict_alloc(rettv) == FAIL)
12502 return;
12503 cursor_pos_info(rettv->vval.v_dict);
12504}
12505
12506/*
12507 * "writefile()" function
12508 */
12509 static void
12510f_writefile(typval_T *argvars, typval_T *rettv)
12511{
12512 int binary = FALSE;
12513 int append = FALSE;
12514 char_u *fname;
12515 FILE *fd;
12516 int ret = 0;
12517
12518 if (check_restricted() || check_secure())
12519 return;
12520
12521 if (argvars[0].v_type != VAR_LIST)
12522 {
12523 EMSG2(_(e_listarg), "writefile()");
12524 return;
12525 }
12526 if (argvars[0].vval.v_list == NULL)
12527 return;
12528
12529 if (argvars[2].v_type != VAR_UNKNOWN)
12530 {
12531 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL)
12532 binary = TRUE;
12533 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL)
12534 append = TRUE;
12535 }
12536
12537 /* Always open the file in binary mode, library functions have a mind of
12538 * their own about CR-LF conversion. */
12539 fname = get_tv_string(&argvars[1]);
12540 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12541 append ? APPENDBIN : WRITEBIN)) == NULL)
12542 {
12543 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
12544 ret = -1;
12545 }
12546 else
12547 {
12548 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL)
12549 ret = -1;
12550 fclose(fd);
12551 }
12552
12553 rettv->vval.v_number = ret;
12554}
12555
12556/*
12557 * "xor(expr, expr)" function
12558 */
12559 static void
12560f_xor(typval_T *argvars, typval_T *rettv)
12561{
12562 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
12563 ^ get_tv_number_chk(&argvars[1], NULL);
12564}
12565
12566
12567#endif /* FEAT_EVAL */