blob: 9905d0ba7406d66e996b760016919c8777df7f51 [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;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004167 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4168 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169
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 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004197 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004198
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
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005208 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209#ifdef FEAT_LANGMAP
5210 "langmap",
5211#endif
5212#ifdef FEAT_LIBCALL
5213 "libcall",
5214#endif
5215#ifdef FEAT_LINEBREAK
5216 "linebreak",
5217#endif
5218#ifdef FEAT_LISP
5219 "lispindent",
5220#endif
5221#ifdef FEAT_LISTCMDS
5222 "listcmds",
5223#endif
5224#ifdef FEAT_LOCALMAP
5225 "localmap",
5226#endif
5227#ifdef FEAT_LUA
5228# ifndef DYNAMIC_LUA
5229 "lua",
5230# endif
5231#endif
5232#ifdef FEAT_MENU
5233 "menu",
5234#endif
5235#ifdef FEAT_SESSION
5236 "mksession",
5237#endif
5238#ifdef FEAT_MODIFY_FNAME
5239 "modify_fname",
5240#endif
5241#ifdef FEAT_MOUSE
5242 "mouse",
5243#endif
5244#ifdef FEAT_MOUSESHAPE
5245 "mouseshape",
5246#endif
5247#if defined(UNIX) || defined(VMS)
5248# ifdef FEAT_MOUSE_DEC
5249 "mouse_dec",
5250# endif
5251# ifdef FEAT_MOUSE_GPM
5252 "mouse_gpm",
5253# endif
5254# ifdef FEAT_MOUSE_JSB
5255 "mouse_jsbterm",
5256# endif
5257# ifdef FEAT_MOUSE_NET
5258 "mouse_netterm",
5259# endif
5260# ifdef FEAT_MOUSE_PTERM
5261 "mouse_pterm",
5262# endif
5263# ifdef FEAT_MOUSE_SGR
5264 "mouse_sgr",
5265# endif
5266# ifdef FEAT_SYSMOUSE
5267 "mouse_sysmouse",
5268# endif
5269# ifdef FEAT_MOUSE_URXVT
5270 "mouse_urxvt",
5271# endif
5272# ifdef FEAT_MOUSE_XTERM
5273 "mouse_xterm",
5274# endif
5275#endif
5276#ifdef FEAT_MBYTE
5277 "multi_byte",
5278#endif
5279#ifdef FEAT_MBYTE_IME
5280 "multi_byte_ime",
5281#endif
5282#ifdef FEAT_MULTI_LANG
5283 "multi_lang",
5284#endif
5285#ifdef FEAT_MZSCHEME
5286#ifndef DYNAMIC_MZSCHEME
5287 "mzscheme",
5288#endif
5289#endif
5290#ifdef FEAT_NUM64
5291 "num64",
5292#endif
5293#ifdef FEAT_OLE
5294 "ole",
5295#endif
5296 "packages",
5297#ifdef FEAT_PATH_EXTRA
5298 "path_extra",
5299#endif
5300#ifdef FEAT_PERL
5301#ifndef DYNAMIC_PERL
5302 "perl",
5303#endif
5304#endif
5305#ifdef FEAT_PERSISTENT_UNDO
5306 "persistent_undo",
5307#endif
5308#ifdef FEAT_PYTHON
5309#ifndef DYNAMIC_PYTHON
5310 "python",
5311#endif
5312#endif
5313#ifdef FEAT_PYTHON3
5314#ifndef DYNAMIC_PYTHON3
5315 "python3",
5316#endif
5317#endif
5318#ifdef FEAT_POSTSCRIPT
5319 "postscript",
5320#endif
5321#ifdef FEAT_PRINTER
5322 "printer",
5323#endif
5324#ifdef FEAT_PROFILE
5325 "profile",
5326#endif
5327#ifdef FEAT_RELTIME
5328 "reltime",
5329#endif
5330#ifdef FEAT_QUICKFIX
5331 "quickfix",
5332#endif
5333#ifdef FEAT_RIGHTLEFT
5334 "rightleft",
5335#endif
5336#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5337 "ruby",
5338#endif
5339#ifdef FEAT_SCROLLBIND
5340 "scrollbind",
5341#endif
5342#ifdef FEAT_CMDL_INFO
5343 "showcmd",
5344 "cmdline_info",
5345#endif
5346#ifdef FEAT_SIGNS
5347 "signs",
5348#endif
5349#ifdef FEAT_SMARTINDENT
5350 "smartindent",
5351#endif
5352#ifdef STARTUPTIME
5353 "startuptime",
5354#endif
5355#ifdef FEAT_STL_OPT
5356 "statusline",
5357#endif
5358#ifdef FEAT_SUN_WORKSHOP
5359 "sun_workshop",
5360#endif
5361#ifdef FEAT_NETBEANS_INTG
5362 "netbeans_intg",
5363#endif
5364#ifdef FEAT_SPELL
5365 "spell",
5366#endif
5367#ifdef FEAT_SYN_HL
5368 "syntax",
5369#endif
5370#if defined(USE_SYSTEM) || !defined(UNIX)
5371 "system",
5372#endif
5373#ifdef FEAT_TAG_BINS
5374 "tag_binary",
5375#endif
5376#ifdef FEAT_TAG_OLDSTATIC
5377 "tag_old_static",
5378#endif
5379#ifdef FEAT_TAG_ANYWHITE
5380 "tag_any_white",
5381#endif
5382#ifdef FEAT_TCL
5383# ifndef DYNAMIC_TCL
5384 "tcl",
5385# endif
5386#endif
5387#ifdef FEAT_TERMGUICOLORS
5388 "termguicolors",
5389#endif
5390#ifdef TERMINFO
5391 "terminfo",
5392#endif
5393#ifdef FEAT_TERMRESPONSE
5394 "termresponse",
5395#endif
5396#ifdef FEAT_TEXTOBJ
5397 "textobjects",
5398#endif
5399#ifdef HAVE_TGETENT
5400 "tgetent",
5401#endif
5402#ifdef FEAT_TIMERS
5403 "timers",
5404#endif
5405#ifdef FEAT_TITLE
5406 "title",
5407#endif
5408#ifdef FEAT_TOOLBAR
5409 "toolbar",
5410#endif
5411#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5412 "unnamedplus",
5413#endif
5414#ifdef FEAT_USR_CMDS
5415 "user-commands", /* was accidentally included in 5.4 */
5416 "user_commands",
5417#endif
5418#ifdef FEAT_VIMINFO
5419 "viminfo",
5420#endif
5421#ifdef FEAT_WINDOWS
5422 "vertsplit",
5423#endif
5424#ifdef FEAT_VIRTUALEDIT
5425 "virtualedit",
5426#endif
5427 "visual",
5428#ifdef FEAT_VISUALEXTRA
5429 "visualextra",
5430#endif
5431#ifdef FEAT_VREPLACE
5432 "vreplace",
5433#endif
5434#ifdef FEAT_WILDIGN
5435 "wildignore",
5436#endif
5437#ifdef FEAT_WILDMENU
5438 "wildmenu",
5439#endif
5440#ifdef FEAT_WINDOWS
5441 "windows",
5442#endif
5443#ifdef FEAT_WAK
5444 "winaltkeys",
5445#endif
5446#ifdef FEAT_WRITEBACKUP
5447 "writebackup",
5448#endif
5449#ifdef FEAT_XIM
5450 "xim",
5451#endif
5452#ifdef FEAT_XFONTSET
5453 "xfontset",
5454#endif
5455#ifdef FEAT_XPM_W32
5456 "xpm",
5457 "xpm_w32", /* for backward compatibility */
5458#else
5459# if defined(HAVE_XPM)
5460 "xpm",
5461# endif
5462#endif
5463#ifdef USE_XSMP
5464 "xsmp",
5465#endif
5466#ifdef USE_XSMP_INTERACT
5467 "xsmp_interact",
5468#endif
5469#ifdef FEAT_XCLIPBOARD
5470 "xterm_clipboard",
5471#endif
5472#ifdef FEAT_XTERM_SAVE
5473 "xterm_save",
5474#endif
5475#if defined(UNIX) && defined(FEAT_X11)
5476 "X11",
5477#endif
5478 NULL
5479 };
5480
5481 name = get_tv_string(&argvars[0]);
5482 for (i = 0; has_list[i] != NULL; ++i)
5483 if (STRICMP(name, has_list[i]) == 0)
5484 {
5485 n = TRUE;
5486 break;
5487 }
5488
5489 if (n == FALSE)
5490 {
5491 if (STRNICMP(name, "patch", 5) == 0)
5492 {
5493 if (name[5] == '-'
5494 && STRLEN(name) >= 11
5495 && vim_isdigit(name[6])
5496 && vim_isdigit(name[8])
5497 && vim_isdigit(name[10]))
5498 {
5499 int major = atoi((char *)name + 6);
5500 int minor = atoi((char *)name + 8);
5501
5502 /* Expect "patch-9.9.01234". */
5503 n = (major < VIM_VERSION_MAJOR
5504 || (major == VIM_VERSION_MAJOR
5505 && (minor < VIM_VERSION_MINOR
5506 || (minor == VIM_VERSION_MINOR
5507 && has_patch(atoi((char *)name + 10))))));
5508 }
5509 else
5510 n = has_patch(atoi((char *)name + 5));
5511 }
5512 else if (STRICMP(name, "vim_starting") == 0)
5513 n = (starting != 0);
5514#ifdef FEAT_MBYTE
5515 else if (STRICMP(name, "multi_byte_encoding") == 0)
5516 n = has_mbyte;
5517#endif
5518#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
5519 else if (STRICMP(name, "balloon_multiline") == 0)
5520 n = multiline_balloon_available();
5521#endif
5522#ifdef DYNAMIC_TCL
5523 else if (STRICMP(name, "tcl") == 0)
5524 n = tcl_enabled(FALSE);
5525#endif
5526#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5527 else if (STRICMP(name, "iconv") == 0)
5528 n = iconv_enabled(FALSE);
5529#endif
5530#ifdef DYNAMIC_LUA
5531 else if (STRICMP(name, "lua") == 0)
5532 n = lua_enabled(FALSE);
5533#endif
5534#ifdef DYNAMIC_MZSCHEME
5535 else if (STRICMP(name, "mzscheme") == 0)
5536 n = mzscheme_enabled(FALSE);
5537#endif
5538#ifdef DYNAMIC_RUBY
5539 else if (STRICMP(name, "ruby") == 0)
5540 n = ruby_enabled(FALSE);
5541#endif
5542#ifdef FEAT_PYTHON
5543#ifdef DYNAMIC_PYTHON
5544 else if (STRICMP(name, "python") == 0)
5545 n = python_enabled(FALSE);
5546#endif
5547#endif
5548#ifdef FEAT_PYTHON3
5549#ifdef DYNAMIC_PYTHON3
5550 else if (STRICMP(name, "python3") == 0)
5551 n = python3_enabled(FALSE);
5552#endif
5553#endif
5554#ifdef DYNAMIC_PERL
5555 else if (STRICMP(name, "perl") == 0)
5556 n = perl_enabled(FALSE);
5557#endif
5558#ifdef FEAT_GUI
5559 else if (STRICMP(name, "gui_running") == 0)
5560 n = (gui.in_use || gui.starting);
5561# ifdef FEAT_GUI_W32
5562 else if (STRICMP(name, "gui_win32s") == 0)
5563 n = gui_is_win32s();
5564# endif
5565# ifdef FEAT_BROWSE
5566 else if (STRICMP(name, "browse") == 0)
5567 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5568# endif
5569#endif
5570#ifdef FEAT_SYN_HL
5571 else if (STRICMP(name, "syntax_items") == 0)
5572 n = syntax_present(curwin);
5573#endif
5574#if defined(WIN3264)
5575 else if (STRICMP(name, "win95") == 0)
5576 n = mch_windows95();
5577#endif
5578#ifdef FEAT_NETBEANS_INTG
5579 else if (STRICMP(name, "netbeans_enabled") == 0)
5580 n = netbeans_active();
5581#endif
5582 }
5583
5584 rettv->vval.v_number = n;
5585}
5586
5587/*
5588 * "has_key()" function
5589 */
5590 static void
5591f_has_key(typval_T *argvars, typval_T *rettv)
5592{
5593 if (argvars[0].v_type != VAR_DICT)
5594 {
5595 EMSG(_(e_dictreq));
5596 return;
5597 }
5598 if (argvars[0].vval.v_dict == NULL)
5599 return;
5600
5601 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
5602 get_tv_string(&argvars[1]), -1) != NULL;
5603}
5604
5605/*
5606 * "haslocaldir()" function
5607 */
5608 static void
5609f_haslocaldir(typval_T *argvars, typval_T *rettv)
5610{
5611 win_T *wp = NULL;
5612
5613 wp = find_tabwin(&argvars[0], &argvars[1]);
5614 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
5615}
5616
5617/*
5618 * "hasmapto()" function
5619 */
5620 static void
5621f_hasmapto(typval_T *argvars, typval_T *rettv)
5622{
5623 char_u *name;
5624 char_u *mode;
5625 char_u buf[NUMBUFLEN];
5626 int abbr = FALSE;
5627
5628 name = get_tv_string(&argvars[0]);
5629 if (argvars[1].v_type == VAR_UNKNOWN)
5630 mode = (char_u *)"nvo";
5631 else
5632 {
5633 mode = get_tv_string_buf(&argvars[1], buf);
5634 if (argvars[2].v_type != VAR_UNKNOWN)
5635 abbr = (int)get_tv_number(&argvars[2]);
5636 }
5637
5638 if (map_to_exists(name, mode, abbr))
5639 rettv->vval.v_number = TRUE;
5640 else
5641 rettv->vval.v_number = FALSE;
5642}
5643
5644/*
5645 * "histadd()" function
5646 */
5647 static void
5648f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
5649{
5650#ifdef FEAT_CMDHIST
5651 int histype;
5652 char_u *str;
5653 char_u buf[NUMBUFLEN];
5654#endif
5655
5656 rettv->vval.v_number = FALSE;
5657 if (check_restricted() || check_secure())
5658 return;
5659#ifdef FEAT_CMDHIST
5660 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5661 histype = str != NULL ? get_histtype(str) : -1;
5662 if (histype >= 0)
5663 {
5664 str = get_tv_string_buf(&argvars[1], buf);
5665 if (*str != NUL)
5666 {
5667 init_history();
5668 add_to_history(histype, str, FALSE, NUL);
5669 rettv->vval.v_number = TRUE;
5670 return;
5671 }
5672 }
5673#endif
5674}
5675
5676/*
5677 * "histdel()" function
5678 */
5679 static void
5680f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5681{
5682#ifdef FEAT_CMDHIST
5683 int n;
5684 char_u buf[NUMBUFLEN];
5685 char_u *str;
5686
5687 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5688 if (str == NULL)
5689 n = 0;
5690 else if (argvars[1].v_type == VAR_UNKNOWN)
5691 /* only one argument: clear entire history */
5692 n = clr_history(get_histtype(str));
5693 else if (argvars[1].v_type == VAR_NUMBER)
5694 /* index given: remove that entry */
5695 n = del_history_idx(get_histtype(str),
5696 (int)get_tv_number(&argvars[1]));
5697 else
5698 /* string given: remove all matching entries */
5699 n = del_history_entry(get_histtype(str),
5700 get_tv_string_buf(&argvars[1], buf));
5701 rettv->vval.v_number = n;
5702#endif
5703}
5704
5705/*
5706 * "histget()" function
5707 */
5708 static void
5709f_histget(typval_T *argvars UNUSED, typval_T *rettv)
5710{
5711#ifdef FEAT_CMDHIST
5712 int type;
5713 int idx;
5714 char_u *str;
5715
5716 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5717 if (str == NULL)
5718 rettv->vval.v_string = NULL;
5719 else
5720 {
5721 type = get_histtype(str);
5722 if (argvars[1].v_type == VAR_UNKNOWN)
5723 idx = get_history_idx(type);
5724 else
5725 idx = (int)get_tv_number_chk(&argvars[1], NULL);
5726 /* -1 on type error */
5727 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
5728 }
5729#else
5730 rettv->vval.v_string = NULL;
5731#endif
5732 rettv->v_type = VAR_STRING;
5733}
5734
5735/*
5736 * "histnr()" function
5737 */
5738 static void
5739f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
5740{
5741 int i;
5742
5743#ifdef FEAT_CMDHIST
5744 char_u *history = get_tv_string_chk(&argvars[0]);
5745
5746 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
5747 if (i >= HIST_CMD && i < HIST_COUNT)
5748 i = get_history_idx(i);
5749 else
5750#endif
5751 i = -1;
5752 rettv->vval.v_number = i;
5753}
5754
5755/*
5756 * "highlightID(name)" function
5757 */
5758 static void
5759f_hlID(typval_T *argvars, typval_T *rettv)
5760{
5761 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
5762}
5763
5764/*
5765 * "highlight_exists()" function
5766 */
5767 static void
5768f_hlexists(typval_T *argvars, typval_T *rettv)
5769{
5770 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
5771}
5772
5773/*
5774 * "hostname()" function
5775 */
5776 static void
5777f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5778{
5779 char_u hostname[256];
5780
5781 mch_get_host_name(hostname, 256);
5782 rettv->v_type = VAR_STRING;
5783 rettv->vval.v_string = vim_strsave(hostname);
5784}
5785
5786/*
5787 * iconv() function
5788 */
5789 static void
5790f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5791{
5792#ifdef FEAT_MBYTE
5793 char_u buf1[NUMBUFLEN];
5794 char_u buf2[NUMBUFLEN];
5795 char_u *from, *to, *str;
5796 vimconv_T vimconv;
5797#endif
5798
5799 rettv->v_type = VAR_STRING;
5800 rettv->vval.v_string = NULL;
5801
5802#ifdef FEAT_MBYTE
5803 str = get_tv_string(&argvars[0]);
5804 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
5805 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
5806 vimconv.vc_type = CONV_NONE;
5807 convert_setup(&vimconv, from, to);
5808
5809 /* If the encodings are equal, no conversion needed. */
5810 if (vimconv.vc_type == CONV_NONE)
5811 rettv->vval.v_string = vim_strsave(str);
5812 else
5813 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5814
5815 convert_setup(&vimconv, NULL, NULL);
5816 vim_free(from);
5817 vim_free(to);
5818#endif
5819}
5820
5821/*
5822 * "indent()" function
5823 */
5824 static void
5825f_indent(typval_T *argvars, typval_T *rettv)
5826{
5827 linenr_T lnum;
5828
5829 lnum = get_tv_lnum(argvars);
5830 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5831 rettv->vval.v_number = get_indent_lnum(lnum);
5832 else
5833 rettv->vval.v_number = -1;
5834}
5835
5836/*
5837 * "index()" function
5838 */
5839 static void
5840f_index(typval_T *argvars, typval_T *rettv)
5841{
5842 list_T *l;
5843 listitem_T *item;
5844 long idx = 0;
5845 int ic = FALSE;
5846
5847 rettv->vval.v_number = -1;
5848 if (argvars[0].v_type != VAR_LIST)
5849 {
5850 EMSG(_(e_listreq));
5851 return;
5852 }
5853 l = argvars[0].vval.v_list;
5854 if (l != NULL)
5855 {
5856 item = l->lv_first;
5857 if (argvars[2].v_type != VAR_UNKNOWN)
5858 {
5859 int error = FALSE;
5860
5861 /* Start at specified item. Use the cached index that list_find()
5862 * sets, so that a negative number also works. */
5863 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
5864 idx = l->lv_idx;
5865 if (argvars[3].v_type != VAR_UNKNOWN)
5866 ic = (int)get_tv_number_chk(&argvars[3], &error);
5867 if (error)
5868 item = NULL;
5869 }
5870
5871 for ( ; item != NULL; item = item->li_next, ++idx)
5872 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5873 {
5874 rettv->vval.v_number = idx;
5875 break;
5876 }
5877 }
5878}
5879
5880static int inputsecret_flag = 0;
5881
5882/*
5883 * "input()" function
5884 * Also handles inputsecret() when inputsecret is set.
5885 */
5886 static void
5887f_input(typval_T *argvars, typval_T *rettv)
5888{
5889 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5890}
5891
5892/*
5893 * "inputdialog()" function
5894 */
5895 static void
5896f_inputdialog(typval_T *argvars, typval_T *rettv)
5897{
5898#if defined(FEAT_GUI_TEXTDIALOG)
5899 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5900 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5901 {
5902 char_u *message;
5903 char_u buf[NUMBUFLEN];
5904 char_u *defstr = (char_u *)"";
5905
5906 message = get_tv_string_chk(&argvars[0]);
5907 if (argvars[1].v_type != VAR_UNKNOWN
5908 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
5909 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5910 else
5911 IObuff[0] = NUL;
5912 if (message != NULL && defstr != NULL
5913 && do_dialog(VIM_QUESTION, NULL, message,
5914 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5915 rettv->vval.v_string = vim_strsave(IObuff);
5916 else
5917 {
5918 if (message != NULL && defstr != NULL
5919 && argvars[1].v_type != VAR_UNKNOWN
5920 && argvars[2].v_type != VAR_UNKNOWN)
5921 rettv->vval.v_string = vim_strsave(
5922 get_tv_string_buf(&argvars[2], buf));
5923 else
5924 rettv->vval.v_string = NULL;
5925 }
5926 rettv->v_type = VAR_STRING;
5927 }
5928 else
5929#endif
5930 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5931}
5932
5933/*
5934 * "inputlist()" function
5935 */
5936 static void
5937f_inputlist(typval_T *argvars, typval_T *rettv)
5938{
5939 listitem_T *li;
5940 int selected;
5941 int mouse_used;
5942
5943#ifdef NO_CONSOLE_INPUT
5944 /* While starting up, there is no place to enter text. */
5945 if (no_console_input())
5946 return;
5947#endif
5948 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5949 {
5950 EMSG2(_(e_listarg), "inputlist()");
5951 return;
5952 }
5953
5954 msg_start();
5955 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
5956 lines_left = Rows; /* avoid more prompt */
5957 msg_scroll = TRUE;
5958 msg_clr_eos();
5959
5960 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
5961 {
5962 msg_puts(get_tv_string(&li->li_tv));
5963 msg_putchar('\n');
5964 }
5965
5966 /* Ask for choice. */
5967 selected = prompt_for_number(&mouse_used);
5968 if (mouse_used)
5969 selected -= lines_left;
5970
5971 rettv->vval.v_number = selected;
5972}
5973
5974
5975static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5976
5977/*
5978 * "inputrestore()" function
5979 */
5980 static void
5981f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5982{
5983 if (ga_userinput.ga_len > 0)
5984 {
5985 --ga_userinput.ga_len;
5986 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5987 + ga_userinput.ga_len);
5988 /* default return is zero == OK */
5989 }
5990 else if (p_verbose > 1)
5991 {
5992 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
5993 rettv->vval.v_number = 1; /* Failed */
5994 }
5995}
5996
5997/*
5998 * "inputsave()" function
5999 */
6000 static void
6001f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6002{
6003 /* Add an entry to the stack of typeahead storage. */
6004 if (ga_grow(&ga_userinput, 1) == OK)
6005 {
6006 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6007 + ga_userinput.ga_len);
6008 ++ga_userinput.ga_len;
6009 /* default return is zero == OK */
6010 }
6011 else
6012 rettv->vval.v_number = 1; /* Failed */
6013}
6014
6015/*
6016 * "inputsecret()" function
6017 */
6018 static void
6019f_inputsecret(typval_T *argvars, typval_T *rettv)
6020{
6021 ++cmdline_star;
6022 ++inputsecret_flag;
6023 f_input(argvars, rettv);
6024 --cmdline_star;
6025 --inputsecret_flag;
6026}
6027
6028/*
6029 * "insert()" function
6030 */
6031 static void
6032f_insert(typval_T *argvars, typval_T *rettv)
6033{
6034 long before = 0;
6035 listitem_T *item;
6036 list_T *l;
6037 int error = FALSE;
6038
6039 if (argvars[0].v_type != VAR_LIST)
6040 EMSG2(_(e_listarg), "insert()");
6041 else if ((l = argvars[0].vval.v_list) != NULL
6042 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6043 {
6044 if (argvars[2].v_type != VAR_UNKNOWN)
6045 before = (long)get_tv_number_chk(&argvars[2], &error);
6046 if (error)
6047 return; /* type error; errmsg already given */
6048
6049 if (before == l->lv_len)
6050 item = NULL;
6051 else
6052 {
6053 item = list_find(l, before);
6054 if (item == NULL)
6055 {
6056 EMSGN(_(e_listidx), before);
6057 l = NULL;
6058 }
6059 }
6060 if (l != NULL)
6061 {
6062 list_insert_tv(l, &argvars[1], item);
6063 copy_tv(&argvars[0], rettv);
6064 }
6065 }
6066}
6067
6068/*
6069 * "invert(expr)" function
6070 */
6071 static void
6072f_invert(typval_T *argvars, typval_T *rettv)
6073{
6074 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6075}
6076
6077/*
6078 * "isdirectory()" function
6079 */
6080 static void
6081f_isdirectory(typval_T *argvars, typval_T *rettv)
6082{
6083 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6084}
6085
6086/*
6087 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6088 * or it refers to a List or Dictionary that is locked.
6089 */
6090 static int
6091tv_islocked(typval_T *tv)
6092{
6093 return (tv->v_lock & VAR_LOCKED)
6094 || (tv->v_type == VAR_LIST
6095 && tv->vval.v_list != NULL
6096 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6097 || (tv->v_type == VAR_DICT
6098 && tv->vval.v_dict != NULL
6099 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6100}
6101
6102/*
6103 * "islocked()" function
6104 */
6105 static void
6106f_islocked(typval_T *argvars, typval_T *rettv)
6107{
6108 lval_T lv;
6109 char_u *end;
6110 dictitem_T *di;
6111
6112 rettv->vval.v_number = -1;
6113 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
6114 GLV_NO_AUTOLOAD, FNE_CHECK_START);
6115 if (end != NULL && lv.ll_name != NULL)
6116 {
6117 if (*end != NUL)
6118 EMSG(_(e_trailing));
6119 else
6120 {
6121 if (lv.ll_tv == NULL)
6122 {
6123 if (check_changedtick(lv.ll_name))
6124 rettv->vval.v_number = 1; /* always locked */
6125 else
6126 {
6127 di = find_var(lv.ll_name, NULL, TRUE);
6128 if (di != NULL)
6129 {
6130 /* Consider a variable locked when:
6131 * 1. the variable itself is locked
6132 * 2. the value of the variable is locked.
6133 * 3. the List or Dict value is locked.
6134 */
6135 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6136 || tv_islocked(&di->di_tv));
6137 }
6138 }
6139 }
6140 else if (lv.ll_range)
6141 EMSG(_("E786: Range not allowed"));
6142 else if (lv.ll_newkey != NULL)
6143 EMSG2(_(e_dictkey), lv.ll_newkey);
6144 else if (lv.ll_list != NULL)
6145 /* List item. */
6146 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6147 else
6148 /* Dictionary item. */
6149 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6150 }
6151 }
6152
6153 clear_lval(&lv);
6154}
6155
6156#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6157/*
6158 * "isnan()" function
6159 */
6160 static void
6161f_isnan(typval_T *argvars, typval_T *rettv)
6162{
6163 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6164 && isnan(argvars[0].vval.v_float);
6165}
6166#endif
6167
6168/*
6169 * "items(dict)" function
6170 */
6171 static void
6172f_items(typval_T *argvars, typval_T *rettv)
6173{
6174 dict_list(argvars, rettv, 2);
6175}
6176
6177#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6178/*
6179 * Get the job from the argument.
6180 * Returns NULL if the job is invalid.
6181 */
6182 static job_T *
6183get_job_arg(typval_T *tv)
6184{
6185 job_T *job;
6186
6187 if (tv->v_type != VAR_JOB)
6188 {
6189 EMSG2(_(e_invarg2), get_tv_string(tv));
6190 return NULL;
6191 }
6192 job = tv->vval.v_job;
6193
6194 if (job == NULL)
6195 EMSG(_("E916: not a valid job"));
6196 return job;
6197}
6198
6199/*
6200 * "job_getchannel()" function
6201 */
6202 static void
6203f_job_getchannel(typval_T *argvars, typval_T *rettv)
6204{
6205 job_T *job = get_job_arg(&argvars[0]);
6206
6207 if (job != NULL)
6208 {
6209 rettv->v_type = VAR_CHANNEL;
6210 rettv->vval.v_channel = job->jv_channel;
6211 if (job->jv_channel != NULL)
6212 ++job->jv_channel->ch_refcount;
6213 }
6214}
6215
6216/*
6217 * "job_info()" function
6218 */
6219 static void
6220f_job_info(typval_T *argvars, typval_T *rettv)
6221{
6222 job_T *job = get_job_arg(&argvars[0]);
6223
6224 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6225 job_info(job, rettv->vval.v_dict);
6226}
6227
6228/*
6229 * "job_setoptions()" function
6230 */
6231 static void
6232f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6233{
6234 job_T *job = get_job_arg(&argvars[0]);
6235 jobopt_T opt;
6236
6237 if (job == NULL)
6238 return;
6239 clear_job_options(&opt);
6240 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK)
6241 job_set_options(job, &opt);
6242 free_job_options(&opt);
6243}
6244
6245/*
6246 * "job_start()" function
6247 */
6248 static void
6249f_job_start(typval_T *argvars, typval_T *rettv)
6250{
6251 rettv->v_type = VAR_JOB;
6252 if (check_restricted() || check_secure())
6253 return;
6254 rettv->vval.v_job = job_start(argvars);
6255}
6256
6257/*
6258 * "job_status()" function
6259 */
6260 static void
6261f_job_status(typval_T *argvars, typval_T *rettv)
6262{
6263 job_T *job = get_job_arg(&argvars[0]);
6264
6265 if (job != NULL)
6266 {
6267 rettv->v_type = VAR_STRING;
6268 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6269 }
6270}
6271
6272/*
6273 * "job_stop()" function
6274 */
6275 static void
6276f_job_stop(typval_T *argvars, typval_T *rettv)
6277{
6278 job_T *job = get_job_arg(&argvars[0]);
6279
6280 if (job != NULL)
6281 rettv->vval.v_number = job_stop(job, argvars);
6282}
6283#endif
6284
6285/*
6286 * "join()" function
6287 */
6288 static void
6289f_join(typval_T *argvars, typval_T *rettv)
6290{
6291 garray_T ga;
6292 char_u *sep;
6293
6294 if (argvars[0].v_type != VAR_LIST)
6295 {
6296 EMSG(_(e_listreq));
6297 return;
6298 }
6299 if (argvars[0].vval.v_list == NULL)
6300 return;
6301 if (argvars[1].v_type == VAR_UNKNOWN)
6302 sep = (char_u *)" ";
6303 else
6304 sep = get_tv_string_chk(&argvars[1]);
6305
6306 rettv->v_type = VAR_STRING;
6307
6308 if (sep != NULL)
6309 {
6310 ga_init2(&ga, (int)sizeof(char), 80);
6311 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6312 ga_append(&ga, NUL);
6313 rettv->vval.v_string = (char_u *)ga.ga_data;
6314 }
6315 else
6316 rettv->vval.v_string = NULL;
6317}
6318
6319/*
6320 * "js_decode()" function
6321 */
6322 static void
6323f_js_decode(typval_T *argvars, typval_T *rettv)
6324{
6325 js_read_T reader;
6326
6327 reader.js_buf = get_tv_string(&argvars[0]);
6328 reader.js_fill = NULL;
6329 reader.js_used = 0;
6330 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6331 EMSG(_(e_invarg));
6332}
6333
6334/*
6335 * "js_encode()" function
6336 */
6337 static void
6338f_js_encode(typval_T *argvars, typval_T *rettv)
6339{
6340 rettv->v_type = VAR_STRING;
6341 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6342}
6343
6344/*
6345 * "json_decode()" function
6346 */
6347 static void
6348f_json_decode(typval_T *argvars, typval_T *rettv)
6349{
6350 js_read_T reader;
6351
6352 reader.js_buf = get_tv_string(&argvars[0]);
6353 reader.js_fill = NULL;
6354 reader.js_used = 0;
6355 if (json_decode_all(&reader, rettv, 0) != OK)
6356 EMSG(_(e_invarg));
6357}
6358
6359/*
6360 * "json_encode()" function
6361 */
6362 static void
6363f_json_encode(typval_T *argvars, typval_T *rettv)
6364{
6365 rettv->v_type = VAR_STRING;
6366 rettv->vval.v_string = json_encode(&argvars[0], 0);
6367}
6368
6369/*
6370 * "keys()" function
6371 */
6372 static void
6373f_keys(typval_T *argvars, typval_T *rettv)
6374{
6375 dict_list(argvars, rettv, 0);
6376}
6377
6378/*
6379 * "last_buffer_nr()" function.
6380 */
6381 static void
6382f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6383{
6384 int n = 0;
6385 buf_T *buf;
6386
Bram Moolenaar29323592016-07-24 22:04:11 +02006387 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006388 if (n < buf->b_fnum)
6389 n = buf->b_fnum;
6390
6391 rettv->vval.v_number = n;
6392}
6393
6394/*
6395 * "len()" function
6396 */
6397 static void
6398f_len(typval_T *argvars, typval_T *rettv)
6399{
6400 switch (argvars[0].v_type)
6401 {
6402 case VAR_STRING:
6403 case VAR_NUMBER:
6404 rettv->vval.v_number = (varnumber_T)STRLEN(
6405 get_tv_string(&argvars[0]));
6406 break;
6407 case VAR_LIST:
6408 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6409 break;
6410 case VAR_DICT:
6411 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6412 break;
6413 case VAR_UNKNOWN:
6414 case VAR_SPECIAL:
6415 case VAR_FLOAT:
6416 case VAR_FUNC:
6417 case VAR_PARTIAL:
6418 case VAR_JOB:
6419 case VAR_CHANNEL:
6420 EMSG(_("E701: Invalid type for len()"));
6421 break;
6422 }
6423}
6424
6425static void libcall_common(typval_T *argvars, typval_T *rettv, int type);
6426
6427 static void
6428libcall_common(typval_T *argvars, typval_T *rettv, int type)
6429{
6430#ifdef FEAT_LIBCALL
6431 char_u *string_in;
6432 char_u **string_result;
6433 int nr_result;
6434#endif
6435
6436 rettv->v_type = type;
6437 if (type != VAR_NUMBER)
6438 rettv->vval.v_string = NULL;
6439
6440 if (check_restricted() || check_secure())
6441 return;
6442
6443#ifdef FEAT_LIBCALL
6444 /* The first two args must be strings, otherwise its meaningless */
6445 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6446 {
6447 string_in = NULL;
6448 if (argvars[2].v_type == VAR_STRING)
6449 string_in = argvars[2].vval.v_string;
6450 if (type == VAR_NUMBER)
6451 string_result = NULL;
6452 else
6453 string_result = &rettv->vval.v_string;
6454 if (mch_libcall(argvars[0].vval.v_string,
6455 argvars[1].vval.v_string,
6456 string_in,
6457 argvars[2].vval.v_number,
6458 string_result,
6459 &nr_result) == OK
6460 && type == VAR_NUMBER)
6461 rettv->vval.v_number = nr_result;
6462 }
6463#endif
6464}
6465
6466/*
6467 * "libcall()" function
6468 */
6469 static void
6470f_libcall(typval_T *argvars, typval_T *rettv)
6471{
6472 libcall_common(argvars, rettv, VAR_STRING);
6473}
6474
6475/*
6476 * "libcallnr()" function
6477 */
6478 static void
6479f_libcallnr(typval_T *argvars, typval_T *rettv)
6480{
6481 libcall_common(argvars, rettv, VAR_NUMBER);
6482}
6483
6484/*
6485 * "line(string)" function
6486 */
6487 static void
6488f_line(typval_T *argvars, typval_T *rettv)
6489{
6490 linenr_T lnum = 0;
6491 pos_T *fp;
6492 int fnum;
6493
6494 fp = var2fpos(&argvars[0], TRUE, &fnum);
6495 if (fp != NULL)
6496 lnum = fp->lnum;
6497 rettv->vval.v_number = lnum;
6498}
6499
6500/*
6501 * "line2byte(lnum)" function
6502 */
6503 static void
6504f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6505{
6506#ifndef FEAT_BYTEOFF
6507 rettv->vval.v_number = -1;
6508#else
6509 linenr_T lnum;
6510
6511 lnum = get_tv_lnum(argvars);
6512 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6513 rettv->vval.v_number = -1;
6514 else
6515 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6516 if (rettv->vval.v_number >= 0)
6517 ++rettv->vval.v_number;
6518#endif
6519}
6520
6521/*
6522 * "lispindent(lnum)" function
6523 */
6524 static void
6525f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
6526{
6527#ifdef FEAT_LISP
6528 pos_T pos;
6529 linenr_T lnum;
6530
6531 pos = curwin->w_cursor;
6532 lnum = get_tv_lnum(argvars);
6533 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6534 {
6535 curwin->w_cursor.lnum = lnum;
6536 rettv->vval.v_number = get_lisp_indent();
6537 curwin->w_cursor = pos;
6538 }
6539 else
6540#endif
6541 rettv->vval.v_number = -1;
6542}
6543
6544/*
6545 * "localtime()" function
6546 */
6547 static void
6548f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
6549{
6550 rettv->vval.v_number = (varnumber_T)time(NULL);
6551}
6552
6553static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
6554
6555 static void
6556get_maparg(typval_T *argvars, typval_T *rettv, int exact)
6557{
6558 char_u *keys;
6559 char_u *which;
6560 char_u buf[NUMBUFLEN];
6561 char_u *keys_buf = NULL;
6562 char_u *rhs;
6563 int mode;
6564 int abbr = FALSE;
6565 int get_dict = FALSE;
6566 mapblock_T *mp;
6567 int buffer_local;
6568
6569 /* return empty string for failure */
6570 rettv->v_type = VAR_STRING;
6571 rettv->vval.v_string = NULL;
6572
6573 keys = get_tv_string(&argvars[0]);
6574 if (*keys == NUL)
6575 return;
6576
6577 if (argvars[1].v_type != VAR_UNKNOWN)
6578 {
6579 which = get_tv_string_buf_chk(&argvars[1], buf);
6580 if (argvars[2].v_type != VAR_UNKNOWN)
6581 {
6582 abbr = (int)get_tv_number(&argvars[2]);
6583 if (argvars[3].v_type != VAR_UNKNOWN)
6584 get_dict = (int)get_tv_number(&argvars[3]);
6585 }
6586 }
6587 else
6588 which = (char_u *)"";
6589 if (which == NULL)
6590 return;
6591
6592 mode = get_map_mode(&which, 0);
6593
6594 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
6595 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
6596 vim_free(keys_buf);
6597
6598 if (!get_dict)
6599 {
6600 /* Return a string. */
6601 if (rhs != NULL)
6602 rettv->vval.v_string = str2special_save(rhs, FALSE);
6603
6604 }
6605 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
6606 {
6607 /* Return a dictionary. */
6608 char_u *lhs = str2special_save(mp->m_keys, TRUE);
6609 char_u *mapmode = map_mode_to_chars(mp->m_mode);
6610 dict_T *dict = rettv->vval.v_dict;
6611
6612 dict_add_nr_str(dict, "lhs", 0L, lhs);
6613 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
6614 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
6615 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
6616 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
6617 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
6618 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
6619 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
6620 dict_add_nr_str(dict, "mode", 0L, mapmode);
6621
6622 vim_free(lhs);
6623 vim_free(mapmode);
6624 }
6625}
6626
6627#ifdef FEAT_FLOAT
6628/*
6629 * "log()" function
6630 */
6631 static void
6632f_log(typval_T *argvars, typval_T *rettv)
6633{
6634 float_T f = 0.0;
6635
6636 rettv->v_type = VAR_FLOAT;
6637 if (get_float_arg(argvars, &f) == OK)
6638 rettv->vval.v_float = log(f);
6639 else
6640 rettv->vval.v_float = 0.0;
6641}
6642
6643/*
6644 * "log10()" function
6645 */
6646 static void
6647f_log10(typval_T *argvars, typval_T *rettv)
6648{
6649 float_T f = 0.0;
6650
6651 rettv->v_type = VAR_FLOAT;
6652 if (get_float_arg(argvars, &f) == OK)
6653 rettv->vval.v_float = log10(f);
6654 else
6655 rettv->vval.v_float = 0.0;
6656}
6657#endif
6658
6659#ifdef FEAT_LUA
6660/*
6661 * "luaeval()" function
6662 */
6663 static void
6664f_luaeval(typval_T *argvars, typval_T *rettv)
6665{
6666 char_u *str;
6667 char_u buf[NUMBUFLEN];
6668
6669 str = get_tv_string_buf(&argvars[0], buf);
6670 do_luaeval(str, argvars + 1, rettv);
6671}
6672#endif
6673
6674/*
6675 * "map()" function
6676 */
6677 static void
6678f_map(typval_T *argvars, typval_T *rettv)
6679{
6680 filter_map(argvars, rettv, TRUE);
6681}
6682
6683/*
6684 * "maparg()" function
6685 */
6686 static void
6687f_maparg(typval_T *argvars, typval_T *rettv)
6688{
6689 get_maparg(argvars, rettv, TRUE);
6690}
6691
6692/*
6693 * "mapcheck()" function
6694 */
6695 static void
6696f_mapcheck(typval_T *argvars, typval_T *rettv)
6697{
6698 get_maparg(argvars, rettv, FALSE);
6699}
6700
6701static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
6702
6703 static void
6704find_some_match(typval_T *argvars, typval_T *rettv, int type)
6705{
6706 char_u *str = NULL;
6707 long len = 0;
6708 char_u *expr = NULL;
6709 char_u *pat;
6710 regmatch_T regmatch;
6711 char_u patbuf[NUMBUFLEN];
6712 char_u strbuf[NUMBUFLEN];
6713 char_u *save_cpo;
6714 long start = 0;
6715 long nth = 1;
6716 colnr_T startcol = 0;
6717 int match = 0;
6718 list_T *l = NULL;
6719 listitem_T *li = NULL;
6720 long idx = 0;
6721 char_u *tofree = NULL;
6722
6723 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6724 save_cpo = p_cpo;
6725 p_cpo = (char_u *)"";
6726
6727 rettv->vval.v_number = -1;
6728 if (type == 3 || type == 4)
6729 {
6730 /* type 3: return empty list when there are no matches.
6731 * type 4: return ["", -1, -1, -1] */
6732 if (rettv_list_alloc(rettv) == FAIL)
6733 goto theend;
6734 if (type == 4
6735 && (list_append_string(rettv->vval.v_list,
6736 (char_u *)"", 0) == FAIL
6737 || list_append_number(rettv->vval.v_list,
6738 (varnumber_T)-1) == FAIL
6739 || list_append_number(rettv->vval.v_list,
6740 (varnumber_T)-1) == FAIL
6741 || list_append_number(rettv->vval.v_list,
6742 (varnumber_T)-1) == FAIL))
6743 {
6744 list_free(rettv->vval.v_list);
6745 rettv->vval.v_list = NULL;
6746 goto theend;
6747 }
6748 }
6749 else if (type == 2)
6750 {
6751 rettv->v_type = VAR_STRING;
6752 rettv->vval.v_string = NULL;
6753 }
6754
6755 if (argvars[0].v_type == VAR_LIST)
6756 {
6757 if ((l = argvars[0].vval.v_list) == NULL)
6758 goto theend;
6759 li = l->lv_first;
6760 }
6761 else
6762 {
6763 expr = str = get_tv_string(&argvars[0]);
6764 len = (long)STRLEN(str);
6765 }
6766
6767 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
6768 if (pat == NULL)
6769 goto theend;
6770
6771 if (argvars[2].v_type != VAR_UNKNOWN)
6772 {
6773 int error = FALSE;
6774
6775 start = (long)get_tv_number_chk(&argvars[2], &error);
6776 if (error)
6777 goto theend;
6778 if (l != NULL)
6779 {
6780 li = list_find(l, start);
6781 if (li == NULL)
6782 goto theend;
6783 idx = l->lv_idx; /* use the cached index */
6784 }
6785 else
6786 {
6787 if (start < 0)
6788 start = 0;
6789 if (start > len)
6790 goto theend;
6791 /* When "count" argument is there ignore matches before "start",
6792 * otherwise skip part of the string. Differs when pattern is "^"
6793 * or "\<". */
6794 if (argvars[3].v_type != VAR_UNKNOWN)
6795 startcol = start;
6796 else
6797 {
6798 str += start;
6799 len -= start;
6800 }
6801 }
6802
6803 if (argvars[3].v_type != VAR_UNKNOWN)
6804 nth = (long)get_tv_number_chk(&argvars[3], &error);
6805 if (error)
6806 goto theend;
6807 }
6808
6809 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6810 if (regmatch.regprog != NULL)
6811 {
6812 regmatch.rm_ic = p_ic;
6813
6814 for (;;)
6815 {
6816 if (l != NULL)
6817 {
6818 if (li == NULL)
6819 {
6820 match = FALSE;
6821 break;
6822 }
6823 vim_free(tofree);
6824 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6825 if (str == NULL)
6826 break;
6827 }
6828
6829 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6830
6831 if (match && --nth <= 0)
6832 break;
6833 if (l == NULL && !match)
6834 break;
6835
6836 /* Advance to just after the match. */
6837 if (l != NULL)
6838 {
6839 li = li->li_next;
6840 ++idx;
6841 }
6842 else
6843 {
6844#ifdef FEAT_MBYTE
6845 startcol = (colnr_T)(regmatch.startp[0]
6846 + (*mb_ptr2len)(regmatch.startp[0]) - str);
6847#else
6848 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
6849#endif
6850 if (startcol > (colnr_T)len
6851 || str + startcol <= regmatch.startp[0])
6852 {
6853 match = FALSE;
6854 break;
6855 }
6856 }
6857 }
6858
6859 if (match)
6860 {
6861 if (type == 4)
6862 {
6863 listitem_T *li1 = rettv->vval.v_list->lv_first;
6864 listitem_T *li2 = li1->li_next;
6865 listitem_T *li3 = li2->li_next;
6866 listitem_T *li4 = li3->li_next;
6867
6868 vim_free(li1->li_tv.vval.v_string);
6869 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
6870 (int)(regmatch.endp[0] - regmatch.startp[0]));
6871 li3->li_tv.vval.v_number =
6872 (varnumber_T)(regmatch.startp[0] - expr);
6873 li4->li_tv.vval.v_number =
6874 (varnumber_T)(regmatch.endp[0] - expr);
6875 if (l != NULL)
6876 li2->li_tv.vval.v_number = (varnumber_T)idx;
6877 }
6878 else if (type == 3)
6879 {
6880 int i;
6881
6882 /* return list with matched string and submatches */
6883 for (i = 0; i < NSUBEXP; ++i)
6884 {
6885 if (regmatch.endp[i] == NULL)
6886 {
6887 if (list_append_string(rettv->vval.v_list,
6888 (char_u *)"", 0) == FAIL)
6889 break;
6890 }
6891 else if (list_append_string(rettv->vval.v_list,
6892 regmatch.startp[i],
6893 (int)(regmatch.endp[i] - regmatch.startp[i]))
6894 == FAIL)
6895 break;
6896 }
6897 }
6898 else if (type == 2)
6899 {
6900 /* return matched string */
6901 if (l != NULL)
6902 copy_tv(&li->li_tv, rettv);
6903 else
6904 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
6905 (int)(regmatch.endp[0] - regmatch.startp[0]));
6906 }
6907 else if (l != NULL)
6908 rettv->vval.v_number = idx;
6909 else
6910 {
6911 if (type != 0)
6912 rettv->vval.v_number =
6913 (varnumber_T)(regmatch.startp[0] - str);
6914 else
6915 rettv->vval.v_number =
6916 (varnumber_T)(regmatch.endp[0] - str);
6917 rettv->vval.v_number += (varnumber_T)(str - expr);
6918 }
6919 }
6920 vim_regfree(regmatch.regprog);
6921 }
6922
6923 if (type == 4 && l == NULL)
6924 /* matchstrpos() without a list: drop the second item. */
6925 listitem_remove(rettv->vval.v_list,
6926 rettv->vval.v_list->lv_first->li_next);
6927
6928theend:
6929 vim_free(tofree);
6930 p_cpo = save_cpo;
6931}
6932
6933/*
6934 * "match()" function
6935 */
6936 static void
6937f_match(typval_T *argvars, typval_T *rettv)
6938{
6939 find_some_match(argvars, rettv, 1);
6940}
6941
6942/*
6943 * "matchadd()" function
6944 */
6945 static void
6946f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6947{
6948#ifdef FEAT_SEARCH_EXTRA
6949 char_u buf[NUMBUFLEN];
6950 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
6951 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
6952 int prio = 10; /* default priority */
6953 int id = -1;
6954 int error = FALSE;
6955 char_u *conceal_char = NULL;
6956
6957 rettv->vval.v_number = -1;
6958
6959 if (grp == NULL || pat == NULL)
6960 return;
6961 if (argvars[2].v_type != VAR_UNKNOWN)
6962 {
6963 prio = (int)get_tv_number_chk(&argvars[2], &error);
6964 if (argvars[3].v_type != VAR_UNKNOWN)
6965 {
6966 id = (int)get_tv_number_chk(&argvars[3], &error);
6967 if (argvars[4].v_type != VAR_UNKNOWN)
6968 {
6969 if (argvars[4].v_type != VAR_DICT)
6970 {
6971 EMSG(_(e_dictreq));
6972 return;
6973 }
6974 if (dict_find(argvars[4].vval.v_dict,
6975 (char_u *)"conceal", -1) != NULL)
6976 conceal_char = get_dict_string(argvars[4].vval.v_dict,
6977 (char_u *)"conceal", FALSE);
6978 }
6979 }
6980 }
6981 if (error == TRUE)
6982 return;
6983 if (id >= 1 && id <= 3)
6984 {
6985 EMSGN("E798: ID is reserved for \":match\": %ld", id);
6986 return;
6987 }
6988
6989 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
6990 conceal_char);
6991#endif
6992}
6993
6994/*
6995 * "matchaddpos()" function
6996 */
6997 static void
6998f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6999{
7000#ifdef FEAT_SEARCH_EXTRA
7001 char_u buf[NUMBUFLEN];
7002 char_u *group;
7003 int prio = 10;
7004 int id = -1;
7005 int error = FALSE;
7006 list_T *l;
7007 char_u *conceal_char = NULL;
7008
7009 rettv->vval.v_number = -1;
7010
7011 group = get_tv_string_buf_chk(&argvars[0], buf);
7012 if (group == NULL)
7013 return;
7014
7015 if (argvars[1].v_type != VAR_LIST)
7016 {
7017 EMSG2(_(e_listarg), "matchaddpos()");
7018 return;
7019 }
7020 l = argvars[1].vval.v_list;
7021 if (l == NULL)
7022 return;
7023
7024 if (argvars[2].v_type != VAR_UNKNOWN)
7025 {
7026 prio = (int)get_tv_number_chk(&argvars[2], &error);
7027 if (argvars[3].v_type != VAR_UNKNOWN)
7028 {
7029 id = (int)get_tv_number_chk(&argvars[3], &error);
7030 if (argvars[4].v_type != VAR_UNKNOWN)
7031 {
7032 if (argvars[4].v_type != VAR_DICT)
7033 {
7034 EMSG(_(e_dictreq));
7035 return;
7036 }
7037 if (dict_find(argvars[4].vval.v_dict,
7038 (char_u *)"conceal", -1) != NULL)
7039 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7040 (char_u *)"conceal", FALSE);
7041 }
7042 }
7043 }
7044 if (error == TRUE)
7045 return;
7046
7047 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7048 if (id == 1 || id == 2)
7049 {
7050 EMSGN("E798: ID is reserved for \":match\": %ld", id);
7051 return;
7052 }
7053
7054 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7055 conceal_char);
7056#endif
7057}
7058
7059/*
7060 * "matcharg()" function
7061 */
7062 static void
7063f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7064{
7065 if (rettv_list_alloc(rettv) == OK)
7066 {
7067#ifdef FEAT_SEARCH_EXTRA
7068 int id = (int)get_tv_number(&argvars[0]);
7069 matchitem_T *m;
7070
7071 if (id >= 1 && id <= 3)
7072 {
7073 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7074 {
7075 list_append_string(rettv->vval.v_list,
7076 syn_id2name(m->hlg_id), -1);
7077 list_append_string(rettv->vval.v_list, m->pattern, -1);
7078 }
7079 else
7080 {
7081 list_append_string(rettv->vval.v_list, NULL, -1);
7082 list_append_string(rettv->vval.v_list, NULL, -1);
7083 }
7084 }
7085#endif
7086 }
7087}
7088
7089/*
7090 * "matchdelete()" function
7091 */
7092 static void
7093f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7094{
7095#ifdef FEAT_SEARCH_EXTRA
7096 rettv->vval.v_number = match_delete(curwin,
7097 (int)get_tv_number(&argvars[0]), TRUE);
7098#endif
7099}
7100
7101/*
7102 * "matchend()" function
7103 */
7104 static void
7105f_matchend(typval_T *argvars, typval_T *rettv)
7106{
7107 find_some_match(argvars, rettv, 0);
7108}
7109
7110/*
7111 * "matchlist()" function
7112 */
7113 static void
7114f_matchlist(typval_T *argvars, typval_T *rettv)
7115{
7116 find_some_match(argvars, rettv, 3);
7117}
7118
7119/*
7120 * "matchstr()" function
7121 */
7122 static void
7123f_matchstr(typval_T *argvars, typval_T *rettv)
7124{
7125 find_some_match(argvars, rettv, 2);
7126}
7127
7128/*
7129 * "matchstrpos()" function
7130 */
7131 static void
7132f_matchstrpos(typval_T *argvars, typval_T *rettv)
7133{
7134 find_some_match(argvars, rettv, 4);
7135}
7136
7137static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7138
7139 static void
7140max_min(typval_T *argvars, typval_T *rettv, int domax)
7141{
7142 varnumber_T n = 0;
7143 varnumber_T i;
7144 int error = FALSE;
7145
7146 if (argvars[0].v_type == VAR_LIST)
7147 {
7148 list_T *l;
7149 listitem_T *li;
7150
7151 l = argvars[0].vval.v_list;
7152 if (l != NULL)
7153 {
7154 li = l->lv_first;
7155 if (li != NULL)
7156 {
7157 n = get_tv_number_chk(&li->li_tv, &error);
7158 for (;;)
7159 {
7160 li = li->li_next;
7161 if (li == NULL)
7162 break;
7163 i = get_tv_number_chk(&li->li_tv, &error);
7164 if (domax ? i > n : i < n)
7165 n = i;
7166 }
7167 }
7168 }
7169 }
7170 else if (argvars[0].v_type == VAR_DICT)
7171 {
7172 dict_T *d;
7173 int first = TRUE;
7174 hashitem_T *hi;
7175 int todo;
7176
7177 d = argvars[0].vval.v_dict;
7178 if (d != NULL)
7179 {
7180 todo = (int)d->dv_hashtab.ht_used;
7181 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7182 {
7183 if (!HASHITEM_EMPTY(hi))
7184 {
7185 --todo;
7186 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7187 if (first)
7188 {
7189 n = i;
7190 first = FALSE;
7191 }
7192 else if (domax ? i > n : i < n)
7193 n = i;
7194 }
7195 }
7196 }
7197 }
7198 else
7199 EMSG(_(e_listdictarg));
7200 rettv->vval.v_number = error ? 0 : n;
7201}
7202
7203/*
7204 * "max()" function
7205 */
7206 static void
7207f_max(typval_T *argvars, typval_T *rettv)
7208{
7209 max_min(argvars, rettv, TRUE);
7210}
7211
7212/*
7213 * "min()" function
7214 */
7215 static void
7216f_min(typval_T *argvars, typval_T *rettv)
7217{
7218 max_min(argvars, rettv, FALSE);
7219}
7220
7221static int mkdir_recurse(char_u *dir, int prot);
7222
7223/*
7224 * Create the directory in which "dir" is located, and higher levels when
7225 * needed.
7226 */
7227 static int
7228mkdir_recurse(char_u *dir, int prot)
7229{
7230 char_u *p;
7231 char_u *updir;
7232 int r = FAIL;
7233
7234 /* Get end of directory name in "dir".
7235 * We're done when it's "/" or "c:/". */
7236 p = gettail_sep(dir);
7237 if (p <= get_past_head(dir))
7238 return OK;
7239
7240 /* If the directory exists we're done. Otherwise: create it.*/
7241 updir = vim_strnsave(dir, (int)(p - dir));
7242 if (updir == NULL)
7243 return FAIL;
7244 if (mch_isdir(updir))
7245 r = OK;
7246 else if (mkdir_recurse(updir, prot) == OK)
7247 r = vim_mkdir_emsg(updir, prot);
7248 vim_free(updir);
7249 return r;
7250}
7251
7252#ifdef vim_mkdir
7253/*
7254 * "mkdir()" function
7255 */
7256 static void
7257f_mkdir(typval_T *argvars, typval_T *rettv)
7258{
7259 char_u *dir;
7260 char_u buf[NUMBUFLEN];
7261 int prot = 0755;
7262
7263 rettv->vval.v_number = FAIL;
7264 if (check_restricted() || check_secure())
7265 return;
7266
7267 dir = get_tv_string_buf(&argvars[0], buf);
7268 if (*dir == NUL)
7269 rettv->vval.v_number = FAIL;
7270 else
7271 {
7272 if (*gettail(dir) == NUL)
7273 /* remove trailing slashes */
7274 *gettail_sep(dir) = NUL;
7275
7276 if (argvars[1].v_type != VAR_UNKNOWN)
7277 {
7278 if (argvars[2].v_type != VAR_UNKNOWN)
7279 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7280 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7281 mkdir_recurse(dir, prot);
7282 }
7283 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7284 }
7285}
7286#endif
7287
7288/*
7289 * "mode()" function
7290 */
7291 static void
7292f_mode(typval_T *argvars, typval_T *rettv)
7293{
7294 char_u buf[3];
7295
7296 buf[1] = NUL;
7297 buf[2] = NUL;
7298
7299 if (time_for_testing == 93784)
7300 {
7301 /* Testing the two-character code. */
7302 buf[0] = 'x';
7303 buf[1] = '!';
7304 }
7305 else if (VIsual_active)
7306 {
7307 if (VIsual_select)
7308 buf[0] = VIsual_mode + 's' - 'v';
7309 else
7310 buf[0] = VIsual_mode;
7311 }
7312 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7313 || State == CONFIRM)
7314 {
7315 buf[0] = 'r';
7316 if (State == ASKMORE)
7317 buf[1] = 'm';
7318 else if (State == CONFIRM)
7319 buf[1] = '?';
7320 }
7321 else if (State == EXTERNCMD)
7322 buf[0] = '!';
7323 else if (State & INSERT)
7324 {
7325#ifdef FEAT_VREPLACE
7326 if (State & VREPLACE_FLAG)
7327 {
7328 buf[0] = 'R';
7329 buf[1] = 'v';
7330 }
7331 else
7332#endif
7333 if (State & REPLACE_FLAG)
7334 buf[0] = 'R';
7335 else
7336 buf[0] = 'i';
7337 }
7338 else if (State & CMDLINE)
7339 {
7340 buf[0] = 'c';
7341 if (exmode_active)
7342 buf[1] = 'v';
7343 }
7344 else if (exmode_active)
7345 {
7346 buf[0] = 'c';
7347 buf[1] = 'e';
7348 }
7349 else
7350 {
7351 buf[0] = 'n';
7352 if (finish_op)
7353 buf[1] = 'o';
7354 }
7355
7356 /* Clear out the minor mode when the argument is not a non-zero number or
7357 * non-empty string. */
7358 if (!non_zero_arg(&argvars[0]))
7359 buf[1] = NUL;
7360
7361 rettv->vval.v_string = vim_strsave(buf);
7362 rettv->v_type = VAR_STRING;
7363}
7364
7365#if defined(FEAT_MZSCHEME) || defined(PROTO)
7366/*
7367 * "mzeval()" function
7368 */
7369 static void
7370f_mzeval(typval_T *argvars, typval_T *rettv)
7371{
7372 char_u *str;
7373 char_u buf[NUMBUFLEN];
7374
7375 str = get_tv_string_buf(&argvars[0], buf);
7376 do_mzeval(str, rettv);
7377}
7378
7379 void
7380mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7381{
7382 typval_T argvars[3];
7383
7384 argvars[0].v_type = VAR_STRING;
7385 argvars[0].vval.v_string = name;
7386 copy_tv(args, &argvars[1]);
7387 argvars[2].v_type = VAR_UNKNOWN;
7388 f_call(argvars, rettv);
7389 clear_tv(&argvars[1]);
7390}
7391#endif
7392
7393/*
7394 * "nextnonblank()" function
7395 */
7396 static void
7397f_nextnonblank(typval_T *argvars, typval_T *rettv)
7398{
7399 linenr_T lnum;
7400
7401 for (lnum = get_tv_lnum(argvars); ; ++lnum)
7402 {
7403 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7404 {
7405 lnum = 0;
7406 break;
7407 }
7408 if (*skipwhite(ml_get(lnum)) != NUL)
7409 break;
7410 }
7411 rettv->vval.v_number = lnum;
7412}
7413
7414/*
7415 * "nr2char()" function
7416 */
7417 static void
7418f_nr2char(typval_T *argvars, typval_T *rettv)
7419{
7420 char_u buf[NUMBUFLEN];
7421
7422#ifdef FEAT_MBYTE
7423 if (has_mbyte)
7424 {
7425 int utf8 = 0;
7426
7427 if (argvars[1].v_type != VAR_UNKNOWN)
7428 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7429 if (utf8)
7430 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7431 else
7432 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7433 }
7434 else
7435#endif
7436 {
7437 buf[0] = (char_u)get_tv_number(&argvars[0]);
7438 buf[1] = NUL;
7439 }
7440 rettv->v_type = VAR_STRING;
7441 rettv->vval.v_string = vim_strsave(buf);
7442}
7443
7444/*
7445 * "or(expr, expr)" function
7446 */
7447 static void
7448f_or(typval_T *argvars, typval_T *rettv)
7449{
7450 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
7451 | get_tv_number_chk(&argvars[1], NULL);
7452}
7453
7454/*
7455 * "pathshorten()" function
7456 */
7457 static void
7458f_pathshorten(typval_T *argvars, typval_T *rettv)
7459{
7460 char_u *p;
7461
7462 rettv->v_type = VAR_STRING;
7463 p = get_tv_string_chk(&argvars[0]);
7464 if (p == NULL)
7465 rettv->vval.v_string = NULL;
7466 else
7467 {
7468 p = vim_strsave(p);
7469 rettv->vval.v_string = p;
7470 if (p != NULL)
7471 shorten_dir(p);
7472 }
7473}
7474
7475#ifdef FEAT_PERL
7476/*
7477 * "perleval()" function
7478 */
7479 static void
7480f_perleval(typval_T *argvars, typval_T *rettv)
7481{
7482 char_u *str;
7483 char_u buf[NUMBUFLEN];
7484
7485 str = get_tv_string_buf(&argvars[0], buf);
7486 do_perleval(str, rettv);
7487}
7488#endif
7489
7490#ifdef FEAT_FLOAT
7491/*
7492 * "pow()" function
7493 */
7494 static void
7495f_pow(typval_T *argvars, typval_T *rettv)
7496{
7497 float_T fx = 0.0, fy = 0.0;
7498
7499 rettv->v_type = VAR_FLOAT;
7500 if (get_float_arg(argvars, &fx) == OK
7501 && get_float_arg(&argvars[1], &fy) == OK)
7502 rettv->vval.v_float = pow(fx, fy);
7503 else
7504 rettv->vval.v_float = 0.0;
7505}
7506#endif
7507
7508/*
7509 * "prevnonblank()" function
7510 */
7511 static void
7512f_prevnonblank(typval_T *argvars, typval_T *rettv)
7513{
7514 linenr_T lnum;
7515
7516 lnum = get_tv_lnum(argvars);
7517 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7518 lnum = 0;
7519 else
7520 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7521 --lnum;
7522 rettv->vval.v_number = lnum;
7523}
7524
7525/* This dummy va_list is here because:
7526 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7527 * - locally in the function results in a "used before set" warning
7528 * - using va_start() to initialize it gives "function with fixed args" error */
7529static va_list ap;
7530
7531/*
7532 * "printf()" function
7533 */
7534 static void
7535f_printf(typval_T *argvars, typval_T *rettv)
7536{
7537 char_u buf[NUMBUFLEN];
7538 int len;
7539 char_u *s;
7540 int saved_did_emsg = did_emsg;
7541 char *fmt;
7542
7543 rettv->v_type = VAR_STRING;
7544 rettv->vval.v_string = NULL;
7545
7546 /* Get the required length, allocate the buffer and do it for real. */
7547 did_emsg = FALSE;
7548 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
7549 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
7550 if (!did_emsg)
7551 {
7552 s = alloc(len + 1);
7553 if (s != NULL)
7554 {
7555 rettv->vval.v_string = s;
7556 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
7557 }
7558 }
7559 did_emsg |= saved_did_emsg;
7560}
7561
7562/*
7563 * "pumvisible()" function
7564 */
7565 static void
7566f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7567{
7568#ifdef FEAT_INS_EXPAND
7569 if (pum_visible())
7570 rettv->vval.v_number = 1;
7571#endif
7572}
7573
7574#ifdef FEAT_PYTHON3
7575/*
7576 * "py3eval()" function
7577 */
7578 static void
7579f_py3eval(typval_T *argvars, typval_T *rettv)
7580{
7581 char_u *str;
7582 char_u buf[NUMBUFLEN];
7583
7584 str = get_tv_string_buf(&argvars[0], buf);
7585 do_py3eval(str, rettv);
7586}
7587#endif
7588
7589#ifdef FEAT_PYTHON
7590/*
7591 * "pyeval()" function
7592 */
7593 static void
7594f_pyeval(typval_T *argvars, typval_T *rettv)
7595{
7596 char_u *str;
7597 char_u buf[NUMBUFLEN];
7598
7599 str = get_tv_string_buf(&argvars[0], buf);
7600 do_pyeval(str, rettv);
7601}
7602#endif
7603
7604/*
7605 * "range()" function
7606 */
7607 static void
7608f_range(typval_T *argvars, typval_T *rettv)
7609{
7610 varnumber_T start;
7611 varnumber_T end;
7612 varnumber_T stride = 1;
7613 varnumber_T i;
7614 int error = FALSE;
7615
7616 start = get_tv_number_chk(&argvars[0], &error);
7617 if (argvars[1].v_type == VAR_UNKNOWN)
7618 {
7619 end = start - 1;
7620 start = 0;
7621 }
7622 else
7623 {
7624 end = get_tv_number_chk(&argvars[1], &error);
7625 if (argvars[2].v_type != VAR_UNKNOWN)
7626 stride = get_tv_number_chk(&argvars[2], &error);
7627 }
7628
7629 if (error)
7630 return; /* type error; errmsg already given */
7631 if (stride == 0)
7632 EMSG(_("E726: Stride is zero"));
7633 else if (stride > 0 ? end + 1 < start : end - 1 > start)
7634 EMSG(_("E727: Start past end"));
7635 else
7636 {
7637 if (rettv_list_alloc(rettv) == OK)
7638 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7639 if (list_append_number(rettv->vval.v_list,
7640 (varnumber_T)i) == FAIL)
7641 break;
7642 }
7643}
7644
7645/*
7646 * "readfile()" function
7647 */
7648 static void
7649f_readfile(typval_T *argvars, typval_T *rettv)
7650{
7651 int binary = FALSE;
7652 int failed = FALSE;
7653 char_u *fname;
7654 FILE *fd;
7655 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
7656 int io_size = sizeof(buf);
7657 int readlen; /* size of last fread() */
7658 char_u *prev = NULL; /* previously read bytes, if any */
7659 long prevlen = 0; /* length of data in prev */
7660 long prevsize = 0; /* size of prev buffer */
7661 long maxline = MAXLNUM;
7662 long cnt = 0;
7663 char_u *p; /* position in buf */
7664 char_u *start; /* start of current line */
7665
7666 if (argvars[1].v_type != VAR_UNKNOWN)
7667 {
7668 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
7669 binary = TRUE;
7670 if (argvars[2].v_type != VAR_UNKNOWN)
7671 maxline = (long)get_tv_number(&argvars[2]);
7672 }
7673
7674 if (rettv_list_alloc(rettv) == FAIL)
7675 return;
7676
7677 /* Always open the file in binary mode, library functions have a mind of
7678 * their own about CR-LF conversion. */
7679 fname = get_tv_string(&argvars[0]);
7680 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
7681 {
7682 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
7683 return;
7684 }
7685
7686 while (cnt < maxline || maxline < 0)
7687 {
7688 readlen = (int)fread(buf, 1, io_size, fd);
7689
7690 /* This for loop processes what was read, but is also entered at end
7691 * of file so that either:
7692 * - an incomplete line gets written
7693 * - a "binary" file gets an empty line at the end if it ends in a
7694 * newline. */
7695 for (p = buf, start = buf;
7696 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
7697 ++p)
7698 {
7699 if (*p == '\n' || readlen <= 0)
7700 {
7701 listitem_T *li;
7702 char_u *s = NULL;
7703 long_u len = p - start;
7704
7705 /* Finished a line. Remove CRs before NL. */
7706 if (readlen > 0 && !binary)
7707 {
7708 while (len > 0 && start[len - 1] == '\r')
7709 --len;
7710 /* removal may cross back to the "prev" string */
7711 if (len == 0)
7712 while (prevlen > 0 && prev[prevlen - 1] == '\r')
7713 --prevlen;
7714 }
7715 if (prevlen == 0)
7716 s = vim_strnsave(start, (int)len);
7717 else
7718 {
7719 /* Change "prev" buffer to be the right size. This way
7720 * the bytes are only copied once, and very long lines are
7721 * allocated only once. */
7722 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
7723 {
7724 mch_memmove(s + prevlen, start, len);
7725 s[prevlen + len] = NUL;
7726 prev = NULL; /* the list will own the string */
7727 prevlen = prevsize = 0;
7728 }
7729 }
7730 if (s == NULL)
7731 {
7732 do_outofmem_msg((long_u) prevlen + len + 1);
7733 failed = TRUE;
7734 break;
7735 }
7736
7737 if ((li = listitem_alloc()) == NULL)
7738 {
7739 vim_free(s);
7740 failed = TRUE;
7741 break;
7742 }
7743 li->li_tv.v_type = VAR_STRING;
7744 li->li_tv.v_lock = 0;
7745 li->li_tv.vval.v_string = s;
7746 list_append(rettv->vval.v_list, li);
7747
7748 start = p + 1; /* step over newline */
7749 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
7750 break;
7751 }
7752 else if (*p == NUL)
7753 *p = '\n';
7754#ifdef FEAT_MBYTE
7755 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
7756 * when finding the BF and check the previous two bytes. */
7757 else if (*p == 0xbf && enc_utf8 && !binary)
7758 {
7759 /* Find the two bytes before the 0xbf. If p is at buf, or buf
7760 * + 1, these may be in the "prev" string. */
7761 char_u back1 = p >= buf + 1 ? p[-1]
7762 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
7763 char_u back2 = p >= buf + 2 ? p[-2]
7764 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
7765 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
7766
7767 if (back2 == 0xef && back1 == 0xbb)
7768 {
7769 char_u *dest = p - 2;
7770
7771 /* Usually a BOM is at the beginning of a file, and so at
7772 * the beginning of a line; then we can just step over it.
7773 */
7774 if (start == dest)
7775 start = p + 1;
7776 else
7777 {
7778 /* have to shuffle buf to close gap */
7779 int adjust_prevlen = 0;
7780
7781 if (dest < buf)
7782 {
7783 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
7784 dest = buf;
7785 }
7786 if (readlen > p - buf + 1)
7787 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
7788 readlen -= 3 - adjust_prevlen;
7789 prevlen -= adjust_prevlen;
7790 p = dest - 1;
7791 }
7792 }
7793 }
7794#endif
7795 } /* for */
7796
7797 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
7798 break;
7799 if (start < p)
7800 {
7801 /* There's part of a line in buf, store it in "prev". */
7802 if (p - start + prevlen >= prevsize)
7803 {
7804 /* need bigger "prev" buffer */
7805 char_u *newprev;
7806
7807 /* A common use case is ordinary text files and "prev" gets a
7808 * fragment of a line, so the first allocation is made
7809 * small, to avoid repeatedly 'allocing' large and
7810 * 'reallocing' small. */
7811 if (prevsize == 0)
7812 prevsize = (long)(p - start);
7813 else
7814 {
7815 long grow50pc = (prevsize * 3) / 2;
7816 long growmin = (long)((p - start) * 2 + prevlen);
7817 prevsize = grow50pc > growmin ? grow50pc : growmin;
7818 }
7819 newprev = prev == NULL ? alloc(prevsize)
7820 : vim_realloc(prev, prevsize);
7821 if (newprev == NULL)
7822 {
7823 do_outofmem_msg((long_u)prevsize);
7824 failed = TRUE;
7825 break;
7826 }
7827 prev = newprev;
7828 }
7829 /* Add the line part to end of "prev". */
7830 mch_memmove(prev + prevlen, start, p - start);
7831 prevlen += (long)(p - start);
7832 }
7833 } /* while */
7834
7835 /*
7836 * For a negative line count use only the lines at the end of the file,
7837 * free the rest.
7838 */
7839 if (!failed && maxline < 0)
7840 while (cnt > -maxline)
7841 {
7842 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
7843 --cnt;
7844 }
7845
7846 if (failed)
7847 {
7848 list_free(rettv->vval.v_list);
7849 /* readfile doc says an empty list is returned on error */
7850 rettv->vval.v_list = list_alloc();
7851 }
7852
7853 vim_free(prev);
7854 fclose(fd);
7855}
7856
7857#if defined(FEAT_RELTIME)
7858static int list2proftime(typval_T *arg, proftime_T *tm);
7859
7860/*
7861 * Convert a List to proftime_T.
7862 * Return FAIL when there is something wrong.
7863 */
7864 static int
7865list2proftime(typval_T *arg, proftime_T *tm)
7866{
7867 long n1, n2;
7868 int error = FALSE;
7869
7870 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
7871 || arg->vval.v_list->lv_len != 2)
7872 return FAIL;
7873 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
7874 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
7875# ifdef WIN3264
7876 tm->HighPart = n1;
7877 tm->LowPart = n2;
7878# else
7879 tm->tv_sec = n1;
7880 tm->tv_usec = n2;
7881# endif
7882 return error ? FAIL : OK;
7883}
7884#endif /* FEAT_RELTIME */
7885
7886/*
7887 * "reltime()" function
7888 */
7889 static void
7890f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7891{
7892#ifdef FEAT_RELTIME
7893 proftime_T res;
7894 proftime_T start;
7895
7896 if (argvars[0].v_type == VAR_UNKNOWN)
7897 {
7898 /* No arguments: get current time. */
7899 profile_start(&res);
7900 }
7901 else if (argvars[1].v_type == VAR_UNKNOWN)
7902 {
7903 if (list2proftime(&argvars[0], &res) == FAIL)
7904 return;
7905 profile_end(&res);
7906 }
7907 else
7908 {
7909 /* Two arguments: compute the difference. */
7910 if (list2proftime(&argvars[0], &start) == FAIL
7911 || list2proftime(&argvars[1], &res) == FAIL)
7912 return;
7913 profile_sub(&res, &start);
7914 }
7915
7916 if (rettv_list_alloc(rettv) == OK)
7917 {
7918 long n1, n2;
7919
7920# ifdef WIN3264
7921 n1 = res.HighPart;
7922 n2 = res.LowPart;
7923# else
7924 n1 = res.tv_sec;
7925 n2 = res.tv_usec;
7926# endif
7927 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
7928 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
7929 }
7930#endif
7931}
7932
7933#ifdef FEAT_FLOAT
7934/*
7935 * "reltimefloat()" function
7936 */
7937 static void
7938f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
7939{
7940# ifdef FEAT_RELTIME
7941 proftime_T tm;
7942# endif
7943
7944 rettv->v_type = VAR_FLOAT;
7945 rettv->vval.v_float = 0;
7946# ifdef FEAT_RELTIME
7947 if (list2proftime(&argvars[0], &tm) == OK)
7948 rettv->vval.v_float = profile_float(&tm);
7949# endif
7950}
7951#endif
7952
7953/*
7954 * "reltimestr()" function
7955 */
7956 static void
7957f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
7958{
7959#ifdef FEAT_RELTIME
7960 proftime_T tm;
7961#endif
7962
7963 rettv->v_type = VAR_STRING;
7964 rettv->vval.v_string = NULL;
7965#ifdef FEAT_RELTIME
7966 if (list2proftime(&argvars[0], &tm) == OK)
7967 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
7968#endif
7969}
7970
7971#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
7972static void make_connection(void);
7973static int check_connection(void);
7974
7975 static void
7976make_connection(void)
7977{
7978 if (X_DISPLAY == NULL
7979# ifdef FEAT_GUI
7980 && !gui.in_use
7981# endif
7982 )
7983 {
7984 x_force_connect = TRUE;
7985 setup_term_clip();
7986 x_force_connect = FALSE;
7987 }
7988}
7989
7990 static int
7991check_connection(void)
7992{
7993 make_connection();
7994 if (X_DISPLAY == NULL)
7995 {
7996 EMSG(_("E240: No connection to Vim server"));
7997 return FAIL;
7998 }
7999 return OK;
8000}
8001#endif
8002
8003#ifdef FEAT_CLIENTSERVER
8004 static void
8005remote_common(typval_T *argvars, typval_T *rettv, int expr)
8006{
8007 char_u *server_name;
8008 char_u *keys;
8009 char_u *r = NULL;
8010 char_u buf[NUMBUFLEN];
8011# ifdef WIN32
8012 HWND w;
8013# else
8014 Window w;
8015# endif
8016
8017 if (check_restricted() || check_secure())
8018 return;
8019
8020# ifdef FEAT_X11
8021 if (check_connection() == FAIL)
8022 return;
8023# endif
8024
8025 server_name = get_tv_string_chk(&argvars[0]);
8026 if (server_name == NULL)
8027 return; /* type error; errmsg already given */
8028 keys = get_tv_string_buf(&argvars[1], buf);
8029# ifdef WIN32
8030 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
8031# else
8032 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
8033 < 0)
8034# endif
8035 {
8036 if (r != NULL)
8037 EMSG(r); /* sending worked but evaluation failed */
8038 else
8039 EMSG2(_("E241: Unable to send to %s"), server_name);
8040 return;
8041 }
8042
8043 rettv->vval.v_string = r;
8044
8045 if (argvars[2].v_type != VAR_UNKNOWN)
8046 {
8047 dictitem_T v;
8048 char_u str[30];
8049 char_u *idvar;
8050
8051 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8052 v.di_tv.v_type = VAR_STRING;
8053 v.di_tv.vval.v_string = vim_strsave(str);
8054 idvar = get_tv_string_chk(&argvars[2]);
8055 if (idvar != NULL)
8056 set_var(idvar, &v.di_tv, FALSE);
8057 vim_free(v.di_tv.vval.v_string);
8058 }
8059}
8060#endif
8061
8062/*
8063 * "remote_expr()" function
8064 */
8065 static void
8066f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8067{
8068 rettv->v_type = VAR_STRING;
8069 rettv->vval.v_string = NULL;
8070#ifdef FEAT_CLIENTSERVER
8071 remote_common(argvars, rettv, TRUE);
8072#endif
8073}
8074
8075/*
8076 * "remote_foreground()" function
8077 */
8078 static void
8079f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8080{
8081#ifdef FEAT_CLIENTSERVER
8082# ifdef WIN32
8083 /* On Win32 it's done in this application. */
8084 {
8085 char_u *server_name = get_tv_string_chk(&argvars[0]);
8086
8087 if (server_name != NULL)
8088 serverForeground(server_name);
8089 }
8090# else
8091 /* Send a foreground() expression to the server. */
8092 argvars[1].v_type = VAR_STRING;
8093 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8094 argvars[2].v_type = VAR_UNKNOWN;
8095 remote_common(argvars, rettv, TRUE);
8096 vim_free(argvars[1].vval.v_string);
8097# endif
8098#endif
8099}
8100
8101 static void
8102f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8103{
8104#ifdef FEAT_CLIENTSERVER
8105 dictitem_T v;
8106 char_u *s = NULL;
8107# ifdef WIN32
8108 long_u n = 0;
8109# endif
8110 char_u *serverid;
8111
8112 if (check_restricted() || check_secure())
8113 {
8114 rettv->vval.v_number = -1;
8115 return;
8116 }
8117 serverid = get_tv_string_chk(&argvars[0]);
8118 if (serverid == NULL)
8119 {
8120 rettv->vval.v_number = -1;
8121 return; /* type error; errmsg already given */
8122 }
8123# ifdef WIN32
8124 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8125 if (n == 0)
8126 rettv->vval.v_number = -1;
8127 else
8128 {
8129 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
8130 rettv->vval.v_number = (s != NULL);
8131 }
8132# else
8133 if (check_connection() == FAIL)
8134 return;
8135
8136 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8137 serverStrToWin(serverid), &s);
8138# endif
8139
8140 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8141 {
8142 char_u *retvar;
8143
8144 v.di_tv.v_type = VAR_STRING;
8145 v.di_tv.vval.v_string = vim_strsave(s);
8146 retvar = get_tv_string_chk(&argvars[1]);
8147 if (retvar != NULL)
8148 set_var(retvar, &v.di_tv, FALSE);
8149 vim_free(v.di_tv.vval.v_string);
8150 }
8151#else
8152 rettv->vval.v_number = -1;
8153#endif
8154}
8155
8156 static void
8157f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8158{
8159 char_u *r = NULL;
8160
8161#ifdef FEAT_CLIENTSERVER
8162 char_u *serverid = get_tv_string_chk(&argvars[0]);
8163
8164 if (serverid != NULL && !check_restricted() && !check_secure())
8165 {
8166# ifdef WIN32
8167 /* The server's HWND is encoded in the 'id' parameter */
8168 long_u n = 0;
8169
8170 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8171 if (n != 0)
8172 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
8173 if (r == NULL)
8174# else
8175 if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
8176 serverStrToWin(serverid), &r, FALSE) < 0)
8177# endif
8178 EMSG(_("E277: Unable to read a server reply"));
8179 }
8180#endif
8181 rettv->v_type = VAR_STRING;
8182 rettv->vval.v_string = r;
8183}
8184
8185/*
8186 * "remote_send()" function
8187 */
8188 static void
8189f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8190{
8191 rettv->v_type = VAR_STRING;
8192 rettv->vval.v_string = NULL;
8193#ifdef FEAT_CLIENTSERVER
8194 remote_common(argvars, rettv, FALSE);
8195#endif
8196}
8197
8198/*
8199 * "remove()" function
8200 */
8201 static void
8202f_remove(typval_T *argvars, typval_T *rettv)
8203{
8204 list_T *l;
8205 listitem_T *item, *item2;
8206 listitem_T *li;
8207 long idx;
8208 long end;
8209 char_u *key;
8210 dict_T *d;
8211 dictitem_T *di;
8212 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8213
8214 if (argvars[0].v_type == VAR_DICT)
8215 {
8216 if (argvars[2].v_type != VAR_UNKNOWN)
8217 EMSG2(_(e_toomanyarg), "remove()");
8218 else if ((d = argvars[0].vval.v_dict) != NULL
8219 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8220 {
8221 key = get_tv_string_chk(&argvars[1]);
8222 if (key != NULL)
8223 {
8224 di = dict_find(d, key, -1);
8225 if (di == NULL)
8226 EMSG2(_(e_dictkey), key);
8227 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8228 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8229 {
8230 *rettv = di->di_tv;
8231 init_tv(&di->di_tv);
8232 dictitem_remove(d, di);
8233 }
8234 }
8235 }
8236 }
8237 else if (argvars[0].v_type != VAR_LIST)
8238 EMSG2(_(e_listdictarg), "remove()");
8239 else if ((l = argvars[0].vval.v_list) != NULL
8240 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8241 {
8242 int error = FALSE;
8243
8244 idx = (long)get_tv_number_chk(&argvars[1], &error);
8245 if (error)
8246 ; /* type error: do nothing, errmsg already given */
8247 else if ((item = list_find(l, idx)) == NULL)
8248 EMSGN(_(e_listidx), idx);
8249 else
8250 {
8251 if (argvars[2].v_type == VAR_UNKNOWN)
8252 {
8253 /* Remove one item, return its value. */
8254 vimlist_remove(l, item, item);
8255 *rettv = item->li_tv;
8256 vim_free(item);
8257 }
8258 else
8259 {
8260 /* Remove range of items, return list with values. */
8261 end = (long)get_tv_number_chk(&argvars[2], &error);
8262 if (error)
8263 ; /* type error: do nothing */
8264 else if ((item2 = list_find(l, end)) == NULL)
8265 EMSGN(_(e_listidx), end);
8266 else
8267 {
8268 int cnt = 0;
8269
8270 for (li = item; li != NULL; li = li->li_next)
8271 {
8272 ++cnt;
8273 if (li == item2)
8274 break;
8275 }
8276 if (li == NULL) /* didn't find "item2" after "item" */
8277 EMSG(_(e_invrange));
8278 else
8279 {
8280 vimlist_remove(l, item, item2);
8281 if (rettv_list_alloc(rettv) == OK)
8282 {
8283 l = rettv->vval.v_list;
8284 l->lv_first = item;
8285 l->lv_last = item2;
8286 item->li_prev = NULL;
8287 item2->li_next = NULL;
8288 l->lv_len = cnt;
8289 }
8290 }
8291 }
8292 }
8293 }
8294 }
8295}
8296
8297/*
8298 * "rename({from}, {to})" function
8299 */
8300 static void
8301f_rename(typval_T *argvars, typval_T *rettv)
8302{
8303 char_u buf[NUMBUFLEN];
8304
8305 if (check_restricted() || check_secure())
8306 rettv->vval.v_number = -1;
8307 else
8308 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8309 get_tv_string_buf(&argvars[1], buf));
8310}
8311
8312/*
8313 * "repeat()" function
8314 */
8315 static void
8316f_repeat(typval_T *argvars, typval_T *rettv)
8317{
8318 char_u *p;
8319 int n;
8320 int slen;
8321 int len;
8322 char_u *r;
8323 int i;
8324
8325 n = (int)get_tv_number(&argvars[1]);
8326 if (argvars[0].v_type == VAR_LIST)
8327 {
8328 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8329 while (n-- > 0)
8330 if (list_extend(rettv->vval.v_list,
8331 argvars[0].vval.v_list, NULL) == FAIL)
8332 break;
8333 }
8334 else
8335 {
8336 p = get_tv_string(&argvars[0]);
8337 rettv->v_type = VAR_STRING;
8338 rettv->vval.v_string = NULL;
8339
8340 slen = (int)STRLEN(p);
8341 len = slen * n;
8342 if (len <= 0)
8343 return;
8344
8345 r = alloc(len + 1);
8346 if (r != NULL)
8347 {
8348 for (i = 0; i < n; i++)
8349 mch_memmove(r + i * slen, p, (size_t)slen);
8350 r[len] = NUL;
8351 }
8352
8353 rettv->vval.v_string = r;
8354 }
8355}
8356
8357/*
8358 * "resolve()" function
8359 */
8360 static void
8361f_resolve(typval_T *argvars, typval_T *rettv)
8362{
8363 char_u *p;
8364#ifdef HAVE_READLINK
8365 char_u *buf = NULL;
8366#endif
8367
8368 p = get_tv_string(&argvars[0]);
8369#ifdef FEAT_SHORTCUT
8370 {
8371 char_u *v = NULL;
8372
8373 v = mch_resolve_shortcut(p);
8374 if (v != NULL)
8375 rettv->vval.v_string = v;
8376 else
8377 rettv->vval.v_string = vim_strsave(p);
8378 }
8379#else
8380# ifdef HAVE_READLINK
8381 {
8382 char_u *cpy;
8383 int len;
8384 char_u *remain = NULL;
8385 char_u *q;
8386 int is_relative_to_current = FALSE;
8387 int has_trailing_pathsep = FALSE;
8388 int limit = 100;
8389
8390 p = vim_strsave(p);
8391
8392 if (p[0] == '.' && (vim_ispathsep(p[1])
8393 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8394 is_relative_to_current = TRUE;
8395
8396 len = STRLEN(p);
8397 if (len > 0 && after_pathsep(p, p + len))
8398 {
8399 has_trailing_pathsep = TRUE;
8400 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8401 }
8402
8403 q = getnextcomp(p);
8404 if (*q != NUL)
8405 {
8406 /* Separate the first path component in "p", and keep the
8407 * remainder (beginning with the path separator). */
8408 remain = vim_strsave(q - 1);
8409 q[-1] = NUL;
8410 }
8411
8412 buf = alloc(MAXPATHL + 1);
8413 if (buf == NULL)
8414 goto fail;
8415
8416 for (;;)
8417 {
8418 for (;;)
8419 {
8420 len = readlink((char *)p, (char *)buf, MAXPATHL);
8421 if (len <= 0)
8422 break;
8423 buf[len] = NUL;
8424
8425 if (limit-- == 0)
8426 {
8427 vim_free(p);
8428 vim_free(remain);
8429 EMSG(_("E655: Too many symbolic links (cycle?)"));
8430 rettv->vval.v_string = NULL;
8431 goto fail;
8432 }
8433
8434 /* Ensure that the result will have a trailing path separator
8435 * if the argument has one. */
8436 if (remain == NULL && has_trailing_pathsep)
8437 add_pathsep(buf);
8438
8439 /* Separate the first path component in the link value and
8440 * concatenate the remainders. */
8441 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8442 if (*q != NUL)
8443 {
8444 if (remain == NULL)
8445 remain = vim_strsave(q - 1);
8446 else
8447 {
8448 cpy = concat_str(q - 1, remain);
8449 if (cpy != NULL)
8450 {
8451 vim_free(remain);
8452 remain = cpy;
8453 }
8454 }
8455 q[-1] = NUL;
8456 }
8457
8458 q = gettail(p);
8459 if (q > p && *q == NUL)
8460 {
8461 /* Ignore trailing path separator. */
8462 q[-1] = NUL;
8463 q = gettail(p);
8464 }
8465 if (q > p && !mch_isFullName(buf))
8466 {
8467 /* symlink is relative to directory of argument */
8468 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
8469 if (cpy != NULL)
8470 {
8471 STRCPY(cpy, p);
8472 STRCPY(gettail(cpy), buf);
8473 vim_free(p);
8474 p = cpy;
8475 }
8476 }
8477 else
8478 {
8479 vim_free(p);
8480 p = vim_strsave(buf);
8481 }
8482 }
8483
8484 if (remain == NULL)
8485 break;
8486
8487 /* Append the first path component of "remain" to "p". */
8488 q = getnextcomp(remain + 1);
8489 len = q - remain - (*q != NUL);
8490 cpy = vim_strnsave(p, STRLEN(p) + len);
8491 if (cpy != NULL)
8492 {
8493 STRNCAT(cpy, remain, len);
8494 vim_free(p);
8495 p = cpy;
8496 }
8497 /* Shorten "remain". */
8498 if (*q != NUL)
8499 STRMOVE(remain, q - 1);
8500 else
8501 {
8502 vim_free(remain);
8503 remain = NULL;
8504 }
8505 }
8506
8507 /* If the result is a relative path name, make it explicitly relative to
8508 * the current directory if and only if the argument had this form. */
8509 if (!vim_ispathsep(*p))
8510 {
8511 if (is_relative_to_current
8512 && *p != NUL
8513 && !(p[0] == '.'
8514 && (p[1] == NUL
8515 || vim_ispathsep(p[1])
8516 || (p[1] == '.'
8517 && (p[2] == NUL
8518 || vim_ispathsep(p[2]))))))
8519 {
8520 /* Prepend "./". */
8521 cpy = concat_str((char_u *)"./", p);
8522 if (cpy != NULL)
8523 {
8524 vim_free(p);
8525 p = cpy;
8526 }
8527 }
8528 else if (!is_relative_to_current)
8529 {
8530 /* Strip leading "./". */
8531 q = p;
8532 while (q[0] == '.' && vim_ispathsep(q[1]))
8533 q += 2;
8534 if (q > p)
8535 STRMOVE(p, p + 2);
8536 }
8537 }
8538
8539 /* Ensure that the result will have no trailing path separator
8540 * if the argument had none. But keep "/" or "//". */
8541 if (!has_trailing_pathsep)
8542 {
8543 q = p + STRLEN(p);
8544 if (after_pathsep(p, q))
8545 *gettail_sep(p) = NUL;
8546 }
8547
8548 rettv->vval.v_string = p;
8549 }
8550# else
8551 rettv->vval.v_string = vim_strsave(p);
8552# endif
8553#endif
8554
8555 simplify_filename(rettv->vval.v_string);
8556
8557#ifdef HAVE_READLINK
8558fail:
8559 vim_free(buf);
8560#endif
8561 rettv->v_type = VAR_STRING;
8562}
8563
8564/*
8565 * "reverse({list})" function
8566 */
8567 static void
8568f_reverse(typval_T *argvars, typval_T *rettv)
8569{
8570 list_T *l;
8571 listitem_T *li, *ni;
8572
8573 if (argvars[0].v_type != VAR_LIST)
8574 EMSG2(_(e_listarg), "reverse()");
8575 else if ((l = argvars[0].vval.v_list) != NULL
8576 && !tv_check_lock(l->lv_lock,
8577 (char_u *)N_("reverse() argument"), TRUE))
8578 {
8579 li = l->lv_last;
8580 l->lv_first = l->lv_last = NULL;
8581 l->lv_len = 0;
8582 while (li != NULL)
8583 {
8584 ni = li->li_prev;
8585 list_append(l, li);
8586 li = ni;
8587 }
8588 rettv->vval.v_list = l;
8589 rettv->v_type = VAR_LIST;
8590 ++l->lv_refcount;
8591 l->lv_idx = l->lv_len - l->lv_idx - 1;
8592 }
8593}
8594
8595#define SP_NOMOVE 0x01 /* don't move cursor */
8596#define SP_REPEAT 0x02 /* repeat to find outer pair */
8597#define SP_RETCOUNT 0x04 /* return matchcount */
8598#define SP_SETPCMARK 0x08 /* set previous context mark */
8599#define SP_START 0x10 /* accept match at start position */
8600#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
8601#define SP_END 0x40 /* leave cursor at end of match */
8602#define SP_COLUMN 0x80 /* start at cursor column */
8603
8604static int get_search_arg(typval_T *varp, int *flagsp);
8605
8606/*
8607 * Get flags for a search function.
8608 * Possibly sets "p_ws".
8609 * Returns BACKWARD, FORWARD or zero (for an error).
8610 */
8611 static int
8612get_search_arg(typval_T *varp, int *flagsp)
8613{
8614 int dir = FORWARD;
8615 char_u *flags;
8616 char_u nbuf[NUMBUFLEN];
8617 int mask;
8618
8619 if (varp->v_type != VAR_UNKNOWN)
8620 {
8621 flags = get_tv_string_buf_chk(varp, nbuf);
8622 if (flags == NULL)
8623 return 0; /* type error; errmsg already given */
8624 while (*flags != NUL)
8625 {
8626 switch (*flags)
8627 {
8628 case 'b': dir = BACKWARD; break;
8629 case 'w': p_ws = TRUE; break;
8630 case 'W': p_ws = FALSE; break;
8631 default: mask = 0;
8632 if (flagsp != NULL)
8633 switch (*flags)
8634 {
8635 case 'c': mask = SP_START; break;
8636 case 'e': mask = SP_END; break;
8637 case 'm': mask = SP_RETCOUNT; break;
8638 case 'n': mask = SP_NOMOVE; break;
8639 case 'p': mask = SP_SUBPAT; break;
8640 case 'r': mask = SP_REPEAT; break;
8641 case 's': mask = SP_SETPCMARK; break;
8642 case 'z': mask = SP_COLUMN; break;
8643 }
8644 if (mask == 0)
8645 {
8646 EMSG2(_(e_invarg2), flags);
8647 dir = 0;
8648 }
8649 else
8650 *flagsp |= mask;
8651 }
8652 if (dir == 0)
8653 break;
8654 ++flags;
8655 }
8656 }
8657 return dir;
8658}
8659
8660/*
8661 * Shared by search() and searchpos() functions.
8662 */
8663 static int
8664search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8665{
8666 int flags;
8667 char_u *pat;
8668 pos_T pos;
8669 pos_T save_cursor;
8670 int save_p_ws = p_ws;
8671 int dir;
8672 int retval = 0; /* default: FAIL */
8673 long lnum_stop = 0;
8674 proftime_T tm;
8675#ifdef FEAT_RELTIME
8676 long time_limit = 0;
8677#endif
8678 int options = SEARCH_KEEP;
8679 int subpatnum;
8680
8681 pat = get_tv_string(&argvars[0]);
8682 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
8683 if (dir == 0)
8684 goto theend;
8685 flags = *flagsp;
8686 if (flags & SP_START)
8687 options |= SEARCH_START;
8688 if (flags & SP_END)
8689 options |= SEARCH_END;
8690 if (flags & SP_COLUMN)
8691 options |= SEARCH_COL;
8692
8693 /* Optional arguments: line number to stop searching and timeout. */
8694 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
8695 {
8696 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
8697 if (lnum_stop < 0)
8698 goto theend;
8699#ifdef FEAT_RELTIME
8700 if (argvars[3].v_type != VAR_UNKNOWN)
8701 {
8702 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
8703 if (time_limit < 0)
8704 goto theend;
8705 }
8706#endif
8707 }
8708
8709#ifdef FEAT_RELTIME
8710 /* Set the time limit, if there is one. */
8711 profile_setlimit(time_limit, &tm);
8712#endif
8713
8714 /*
8715 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
8716 * Check to make sure only those flags are set.
8717 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
8718 * flags cannot be set. Check for that condition also.
8719 */
8720 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
8721 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8722 {
8723 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
8724 goto theend;
8725 }
8726
8727 pos = save_cursor = curwin->w_cursor;
8728 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
8729 options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
8730 if (subpatnum != FAIL)
8731 {
8732 if (flags & SP_SUBPAT)
8733 retval = subpatnum;
8734 else
8735 retval = pos.lnum;
8736 if (flags & SP_SETPCMARK)
8737 setpcmark();
8738 curwin->w_cursor = pos;
8739 if (match_pos != NULL)
8740 {
8741 /* Store the match cursor position */
8742 match_pos->lnum = pos.lnum;
8743 match_pos->col = pos.col + 1;
8744 }
8745 /* "/$" will put the cursor after the end of the line, may need to
8746 * correct that here */
8747 check_cursor();
8748 }
8749
8750 /* If 'n' flag is used: restore cursor position. */
8751 if (flags & SP_NOMOVE)
8752 curwin->w_cursor = save_cursor;
8753 else
8754 curwin->w_set_curswant = TRUE;
8755theend:
8756 p_ws = save_p_ws;
8757
8758 return retval;
8759}
8760
8761#ifdef FEAT_FLOAT
8762
8763/*
8764 * round() is not in C90, use ceil() or floor() instead.
8765 */
8766 float_T
8767vim_round(float_T f)
8768{
8769 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
8770}
8771
8772/*
8773 * "round({float})" function
8774 */
8775 static void
8776f_round(typval_T *argvars, typval_T *rettv)
8777{
8778 float_T f = 0.0;
8779
8780 rettv->v_type = VAR_FLOAT;
8781 if (get_float_arg(argvars, &f) == OK)
8782 rettv->vval.v_float = vim_round(f);
8783 else
8784 rettv->vval.v_float = 0.0;
8785}
8786#endif
8787
8788/*
8789 * "screenattr()" function
8790 */
8791 static void
8792f_screenattr(typval_T *argvars, typval_T *rettv)
8793{
8794 int row;
8795 int col;
8796 int c;
8797
8798 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
8799 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
8800 if (row < 0 || row >= screen_Rows
8801 || col < 0 || col >= screen_Columns)
8802 c = -1;
8803 else
8804 c = ScreenAttrs[LineOffset[row] + col];
8805 rettv->vval.v_number = c;
8806}
8807
8808/*
8809 * "screenchar()" function
8810 */
8811 static void
8812f_screenchar(typval_T *argvars, typval_T *rettv)
8813{
8814 int row;
8815 int col;
8816 int off;
8817 int c;
8818
8819 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
8820 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
8821 if (row < 0 || row >= screen_Rows
8822 || col < 0 || col >= screen_Columns)
8823 c = -1;
8824 else
8825 {
8826 off = LineOffset[row] + col;
8827#ifdef FEAT_MBYTE
8828 if (enc_utf8 && ScreenLinesUC[off] != 0)
8829 c = ScreenLinesUC[off];
8830 else
8831#endif
8832 c = ScreenLines[off];
8833 }
8834 rettv->vval.v_number = c;
8835}
8836
8837/*
8838 * "screencol()" function
8839 *
8840 * First column is 1 to be consistent with virtcol().
8841 */
8842 static void
8843f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
8844{
8845 rettv->vval.v_number = screen_screencol() + 1;
8846}
8847
8848/*
8849 * "screenrow()" function
8850 */
8851 static void
8852f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
8853{
8854 rettv->vval.v_number = screen_screenrow() + 1;
8855}
8856
8857/*
8858 * "search()" function
8859 */
8860 static void
8861f_search(typval_T *argvars, typval_T *rettv)
8862{
8863 int flags = 0;
8864
8865 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
8866}
8867
8868/*
8869 * "searchdecl()" function
8870 */
8871 static void
8872f_searchdecl(typval_T *argvars, typval_T *rettv)
8873{
8874 int locally = 1;
8875 int thisblock = 0;
8876 int error = FALSE;
8877 char_u *name;
8878
8879 rettv->vval.v_number = 1; /* default: FAIL */
8880
8881 name = get_tv_string_chk(&argvars[0]);
8882 if (argvars[1].v_type != VAR_UNKNOWN)
8883 {
8884 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
8885 if (!error && argvars[2].v_type != VAR_UNKNOWN)
8886 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
8887 }
8888 if (!error && name != NULL)
8889 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
8890 locally, thisblock, SEARCH_KEEP) == FAIL;
8891}
8892
8893/*
8894 * Used by searchpair() and searchpairpos()
8895 */
8896 static int
8897searchpair_cmn(typval_T *argvars, pos_T *match_pos)
8898{
8899 char_u *spat, *mpat, *epat;
8900 char_u *skip;
8901 int save_p_ws = p_ws;
8902 int dir;
8903 int flags = 0;
8904 char_u nbuf1[NUMBUFLEN];
8905 char_u nbuf2[NUMBUFLEN];
8906 char_u nbuf3[NUMBUFLEN];
8907 int retval = 0; /* default: FAIL */
8908 long lnum_stop = 0;
8909 long time_limit = 0;
8910
8911 /* Get the three pattern arguments: start, middle, end. */
8912 spat = get_tv_string_chk(&argvars[0]);
8913 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
8914 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
8915 if (spat == NULL || mpat == NULL || epat == NULL)
8916 goto theend; /* type error */
8917
8918 /* Handle the optional fourth argument: flags */
8919 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
8920 if (dir == 0)
8921 goto theend;
8922
8923 /* Don't accept SP_END or SP_SUBPAT.
8924 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
8925 */
8926 if ((flags & (SP_END | SP_SUBPAT)) != 0
8927 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8928 {
8929 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
8930 goto theend;
8931 }
8932
8933 /* Using 'r' implies 'W', otherwise it doesn't work. */
8934 if (flags & SP_REPEAT)
8935 p_ws = FALSE;
8936
8937 /* Optional fifth argument: skip expression */
8938 if (argvars[3].v_type == VAR_UNKNOWN
8939 || argvars[4].v_type == VAR_UNKNOWN)
8940 skip = (char_u *)"";
8941 else
8942 {
8943 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
8944 if (argvars[5].v_type != VAR_UNKNOWN)
8945 {
8946 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
8947 if (lnum_stop < 0)
8948 goto theend;
8949#ifdef FEAT_RELTIME
8950 if (argvars[6].v_type != VAR_UNKNOWN)
8951 {
8952 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
8953 if (time_limit < 0)
8954 goto theend;
8955 }
8956#endif
8957 }
8958 }
8959 if (skip == NULL)
8960 goto theend; /* type error */
8961
8962 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
8963 match_pos, lnum_stop, time_limit);
8964
8965theend:
8966 p_ws = save_p_ws;
8967
8968 return retval;
8969}
8970
8971/*
8972 * "searchpair()" function
8973 */
8974 static void
8975f_searchpair(typval_T *argvars, typval_T *rettv)
8976{
8977 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
8978}
8979
8980/*
8981 * "searchpairpos()" function
8982 */
8983 static void
8984f_searchpairpos(typval_T *argvars, typval_T *rettv)
8985{
8986 pos_T match_pos;
8987 int lnum = 0;
8988 int col = 0;
8989
8990 if (rettv_list_alloc(rettv) == FAIL)
8991 return;
8992
8993 if (searchpair_cmn(argvars, &match_pos) > 0)
8994 {
8995 lnum = match_pos.lnum;
8996 col = match_pos.col;
8997 }
8998
8999 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9000 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9001}
9002
9003/*
9004 * Search for a start/middle/end thing.
9005 * Used by searchpair(), see its documentation for the details.
9006 * Returns 0 or -1 for no match,
9007 */
9008 long
9009do_searchpair(
9010 char_u *spat, /* start pattern */
9011 char_u *mpat, /* middle pattern */
9012 char_u *epat, /* end pattern */
9013 int dir, /* BACKWARD or FORWARD */
9014 char_u *skip, /* skip expression */
9015 int flags, /* SP_SETPCMARK and other SP_ values */
9016 pos_T *match_pos,
9017 linenr_T lnum_stop, /* stop at this line if not zero */
9018 long time_limit UNUSED) /* stop after this many msec */
9019{
9020 char_u *save_cpo;
9021 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9022 long retval = 0;
9023 pos_T pos;
9024 pos_T firstpos;
9025 pos_T foundpos;
9026 pos_T save_cursor;
9027 pos_T save_pos;
9028 int n;
9029 int r;
9030 int nest = 1;
9031 int err;
9032 int options = SEARCH_KEEP;
9033 proftime_T tm;
9034
9035 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9036 save_cpo = p_cpo;
9037 p_cpo = empty_option;
9038
9039#ifdef FEAT_RELTIME
9040 /* Set the time limit, if there is one. */
9041 profile_setlimit(time_limit, &tm);
9042#endif
9043
9044 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9045 * start/middle/end (pat3, for the top pair). */
9046 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15));
9047 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23));
9048 if (pat2 == NULL || pat3 == NULL)
9049 goto theend;
9050 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
9051 if (*mpat == NUL)
9052 STRCPY(pat3, pat2);
9053 else
9054 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
9055 spat, epat, mpat);
9056 if (flags & SP_START)
9057 options |= SEARCH_START;
9058
9059 save_cursor = curwin->w_cursor;
9060 pos = curwin->w_cursor;
9061 clearpos(&firstpos);
9062 clearpos(&foundpos);
9063 pat = pat3;
9064 for (;;)
9065 {
9066 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9067 options, RE_SEARCH, lnum_stop, &tm);
9068 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
9069 /* didn't find it or found the first match again: FAIL */
9070 break;
9071
9072 if (firstpos.lnum == 0)
9073 firstpos = pos;
9074 if (equalpos(pos, foundpos))
9075 {
9076 /* Found the same position again. Can happen with a pattern that
9077 * has "\zs" at the end and searching backwards. Advance one
9078 * character and try again. */
9079 if (dir == BACKWARD)
9080 decl(&pos);
9081 else
9082 incl(&pos);
9083 }
9084 foundpos = pos;
9085
9086 /* clear the start flag to avoid getting stuck here */
9087 options &= ~SEARCH_START;
9088
9089 /* If the skip pattern matches, ignore this match. */
9090 if (*skip != NUL)
9091 {
9092 save_pos = curwin->w_cursor;
9093 curwin->w_cursor = pos;
9094 r = eval_to_bool(skip, &err, NULL, FALSE);
9095 curwin->w_cursor = save_pos;
9096 if (err)
9097 {
9098 /* Evaluating {skip} caused an error, break here. */
9099 curwin->w_cursor = save_cursor;
9100 retval = -1;
9101 break;
9102 }
9103 if (r)
9104 continue;
9105 }
9106
9107 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9108 {
9109 /* Found end when searching backwards or start when searching
9110 * forward: nested pair. */
9111 ++nest;
9112 pat = pat2; /* nested, don't search for middle */
9113 }
9114 else
9115 {
9116 /* Found end when searching forward or start when searching
9117 * backward: end of (nested) pair; or found middle in outer pair. */
9118 if (--nest == 1)
9119 pat = pat3; /* outer level, search for middle */
9120 }
9121
9122 if (nest == 0)
9123 {
9124 /* Found the match: return matchcount or line number. */
9125 if (flags & SP_RETCOUNT)
9126 ++retval;
9127 else
9128 retval = pos.lnum;
9129 if (flags & SP_SETPCMARK)
9130 setpcmark();
9131 curwin->w_cursor = pos;
9132 if (!(flags & SP_REPEAT))
9133 break;
9134 nest = 1; /* search for next unmatched */
9135 }
9136 }
9137
9138 if (match_pos != NULL)
9139 {
9140 /* Store the match cursor position */
9141 match_pos->lnum = curwin->w_cursor.lnum;
9142 match_pos->col = curwin->w_cursor.col + 1;
9143 }
9144
9145 /* If 'n' flag is used or search failed: restore cursor position. */
9146 if ((flags & SP_NOMOVE) || retval == 0)
9147 curwin->w_cursor = save_cursor;
9148
9149theend:
9150 vim_free(pat2);
9151 vim_free(pat3);
9152 if (p_cpo == empty_option)
9153 p_cpo = save_cpo;
9154 else
9155 /* Darn, evaluating the {skip} expression changed the value. */
9156 free_string_option(save_cpo);
9157
9158 return retval;
9159}
9160
9161/*
9162 * "searchpos()" function
9163 */
9164 static void
9165f_searchpos(typval_T *argvars, typval_T *rettv)
9166{
9167 pos_T match_pos;
9168 int lnum = 0;
9169 int col = 0;
9170 int n;
9171 int flags = 0;
9172
9173 if (rettv_list_alloc(rettv) == FAIL)
9174 return;
9175
9176 n = search_cmn(argvars, &match_pos, &flags);
9177 if (n > 0)
9178 {
9179 lnum = match_pos.lnum;
9180 col = match_pos.col;
9181 }
9182
9183 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9184 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9185 if (flags & SP_SUBPAT)
9186 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9187}
9188
9189 static void
9190f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9191{
9192#ifdef FEAT_CLIENTSERVER
9193 char_u buf[NUMBUFLEN];
9194 char_u *server = get_tv_string_chk(&argvars[0]);
9195 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9196
9197 rettv->vval.v_number = -1;
9198 if (server == NULL || reply == NULL)
9199 return;
9200 if (check_restricted() || check_secure())
9201 return;
9202# ifdef FEAT_X11
9203 if (check_connection() == FAIL)
9204 return;
9205# endif
9206
9207 if (serverSendReply(server, reply) < 0)
9208 {
9209 EMSG(_("E258: Unable to send to client"));
9210 return;
9211 }
9212 rettv->vval.v_number = 0;
9213#else
9214 rettv->vval.v_number = -1;
9215#endif
9216}
9217
9218 static void
9219f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9220{
9221 char_u *r = NULL;
9222
9223#ifdef FEAT_CLIENTSERVER
9224# ifdef WIN32
9225 r = serverGetVimNames();
9226# else
9227 make_connection();
9228 if (X_DISPLAY != NULL)
9229 r = serverGetVimNames(X_DISPLAY);
9230# endif
9231#endif
9232 rettv->v_type = VAR_STRING;
9233 rettv->vval.v_string = r;
9234}
9235
9236/*
9237 * "setbufvar()" function
9238 */
9239 static void
9240f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9241{
9242 buf_T *buf;
9243 char_u *varname, *bufvarname;
9244 typval_T *varp;
9245 char_u nbuf[NUMBUFLEN];
9246
9247 if (check_restricted() || check_secure())
9248 return;
9249 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
9250 varname = get_tv_string_chk(&argvars[1]);
9251 buf = get_buf_tv(&argvars[0], FALSE);
9252 varp = &argvars[2];
9253
9254 if (buf != NULL && varname != NULL && varp != NULL)
9255 {
9256 if (*varname == '&')
9257 {
9258 long numval;
9259 char_u *strval;
9260 int error = FALSE;
9261 aco_save_T aco;
9262
9263 /* set curbuf to be our buf, temporarily */
9264 aucmd_prepbuf(&aco, buf);
9265
9266 ++varname;
9267 numval = (long)get_tv_number_chk(varp, &error);
9268 strval = get_tv_string_buf_chk(varp, nbuf);
9269 if (!error && strval != NULL)
9270 set_option_value(varname, numval, strval, OPT_LOCAL);
9271
9272 /* reset notion of buffer */
9273 aucmd_restbuf(&aco);
9274 }
9275 else
9276 {
9277 buf_T *save_curbuf = curbuf;
9278
9279 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9280 if (bufvarname != NULL)
9281 {
9282 curbuf = buf;
9283 STRCPY(bufvarname, "b:");
9284 STRCPY(bufvarname + 2, varname);
9285 set_var(bufvarname, varp, TRUE);
9286 vim_free(bufvarname);
9287 curbuf = save_curbuf;
9288 }
9289 }
9290 }
9291}
9292
9293 static void
9294f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9295{
9296 dict_T *d;
9297 dictitem_T *di;
9298 char_u *csearch;
9299
9300 if (argvars[0].v_type != VAR_DICT)
9301 {
9302 EMSG(_(e_dictreq));
9303 return;
9304 }
9305
9306 if ((d = argvars[0].vval.v_dict) != NULL)
9307 {
9308 csearch = get_dict_string(d, (char_u *)"char", FALSE);
9309 if (csearch != NULL)
9310 {
9311#ifdef FEAT_MBYTE
9312 if (enc_utf8)
9313 {
9314 int pcc[MAX_MCO];
9315 int c = utfc_ptr2char(csearch, pcc);
9316
9317 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9318 }
9319 else
9320#endif
9321 set_last_csearch(PTR2CHAR(csearch),
9322 csearch, MB_PTR2LEN(csearch));
9323 }
9324
9325 di = dict_find(d, (char_u *)"forward", -1);
9326 if (di != NULL)
9327 set_csearch_direction((int)get_tv_number(&di->di_tv)
9328 ? FORWARD : BACKWARD);
9329
9330 di = dict_find(d, (char_u *)"until", -1);
9331 if (di != NULL)
9332 set_csearch_until(!!get_tv_number(&di->di_tv));
9333 }
9334}
9335
9336/*
9337 * "setcmdpos()" function
9338 */
9339 static void
9340f_setcmdpos(typval_T *argvars, typval_T *rettv)
9341{
9342 int pos = (int)get_tv_number(&argvars[0]) - 1;
9343
9344 if (pos >= 0)
9345 rettv->vval.v_number = set_cmdline_pos(pos);
9346}
9347
9348/*
9349 * "setfperm({fname}, {mode})" function
9350 */
9351 static void
9352f_setfperm(typval_T *argvars, typval_T *rettv)
9353{
9354 char_u *fname;
9355 char_u modebuf[NUMBUFLEN];
9356 char_u *mode_str;
9357 int i;
9358 int mask;
9359 int mode = 0;
9360
9361 rettv->vval.v_number = 0;
9362 fname = get_tv_string_chk(&argvars[0]);
9363 if (fname == NULL)
9364 return;
9365 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9366 if (mode_str == NULL)
9367 return;
9368 if (STRLEN(mode_str) != 9)
9369 {
9370 EMSG2(_(e_invarg2), mode_str);
9371 return;
9372 }
9373
9374 mask = 1;
9375 for (i = 8; i >= 0; --i)
9376 {
9377 if (mode_str[i] != '-')
9378 mode |= mask;
9379 mask = mask << 1;
9380 }
9381 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9382}
9383
9384/*
9385 * "setline()" function
9386 */
9387 static void
9388f_setline(typval_T *argvars, typval_T *rettv)
9389{
9390 linenr_T lnum;
9391 char_u *line = NULL;
9392 list_T *l = NULL;
9393 listitem_T *li = NULL;
9394 long added = 0;
9395 linenr_T lcount = curbuf->b_ml.ml_line_count;
9396
9397 lnum = get_tv_lnum(&argvars[0]);
9398 if (argvars[1].v_type == VAR_LIST)
9399 {
9400 l = argvars[1].vval.v_list;
9401 li = l->lv_first;
9402 }
9403 else
9404 line = get_tv_string_chk(&argvars[1]);
9405
9406 /* default result is zero == OK */
9407 for (;;)
9408 {
9409 if (l != NULL)
9410 {
9411 /* list argument, get next string */
9412 if (li == NULL)
9413 break;
9414 line = get_tv_string_chk(&li->li_tv);
9415 li = li->li_next;
9416 }
9417
9418 rettv->vval.v_number = 1; /* FAIL */
9419 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9420 break;
9421
9422 /* When coming here from Insert mode, sync undo, so that this can be
9423 * undone separately from what was previously inserted. */
9424 if (u_sync_once == 2)
9425 {
9426 u_sync_once = 1; /* notify that u_sync() was called */
9427 u_sync(TRUE);
9428 }
9429
9430 if (lnum <= curbuf->b_ml.ml_line_count)
9431 {
9432 /* existing line, replace it */
9433 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
9434 {
9435 changed_bytes(lnum, 0);
9436 if (lnum == curwin->w_cursor.lnum)
9437 check_cursor_col();
9438 rettv->vval.v_number = 0; /* OK */
9439 }
9440 }
9441 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
9442 {
9443 /* lnum is one past the last line, append the line */
9444 ++added;
9445 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
9446 rettv->vval.v_number = 0; /* OK */
9447 }
9448
9449 if (l == NULL) /* only one string argument */
9450 break;
9451 ++lnum;
9452 }
9453
9454 if (added > 0)
9455 appended_lines_mark(lcount, added);
9456}
9457
9458static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv);
9459
9460/*
9461 * Used by "setqflist()" and "setloclist()" functions
9462 */
9463 static void
9464set_qf_ll_list(
9465 win_T *wp UNUSED,
9466 typval_T *list_arg UNUSED,
9467 typval_T *action_arg UNUSED,
9468 typval_T *rettv)
9469{
9470#ifdef FEAT_QUICKFIX
9471 static char *e_invact = N_("E927: Invalid action: '%s'");
9472 char_u *act;
9473 int action = 0;
9474#endif
9475
9476 rettv->vval.v_number = -1;
9477
9478#ifdef FEAT_QUICKFIX
9479 if (list_arg->v_type != VAR_LIST)
9480 EMSG(_(e_listreq));
9481 else
9482 {
9483 list_T *l = list_arg->vval.v_list;
9484
9485 if (action_arg->v_type == VAR_STRING)
9486 {
9487 act = get_tv_string_chk(action_arg);
9488 if (act == NULL)
9489 return; /* type error; errmsg already given */
9490 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL)
9491 action = *act;
9492 else
9493 EMSG2(_(e_invact), act);
9494 }
9495 else if (action_arg->v_type == VAR_UNKNOWN)
9496 action = ' ';
9497 else
9498 EMSG(_(e_stringreq));
9499
9500 if (l != NULL && action && set_errorlist(wp, l, action,
9501 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK)
9502 rettv->vval.v_number = 0;
9503 }
9504#endif
9505}
9506
9507/*
9508 * "setloclist()" function
9509 */
9510 static void
9511f_setloclist(typval_T *argvars, typval_T *rettv)
9512{
9513 win_T *win;
9514
9515 rettv->vval.v_number = -1;
9516
9517 win = find_win_by_nr(&argvars[0], NULL);
9518 if (win != NULL)
9519 set_qf_ll_list(win, &argvars[1], &argvars[2], rettv);
9520}
9521
9522/*
9523 * "setmatches()" function
9524 */
9525 static void
9526f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9527{
9528#ifdef FEAT_SEARCH_EXTRA
9529 list_T *l;
9530 listitem_T *li;
9531 dict_T *d;
9532 list_T *s = NULL;
9533
9534 rettv->vval.v_number = -1;
9535 if (argvars[0].v_type != VAR_LIST)
9536 {
9537 EMSG(_(e_listreq));
9538 return;
9539 }
9540 if ((l = argvars[0].vval.v_list) != NULL)
9541 {
9542
9543 /* To some extent make sure that we are dealing with a list from
9544 * "getmatches()". */
9545 li = l->lv_first;
9546 while (li != NULL)
9547 {
9548 if (li->li_tv.v_type != VAR_DICT
9549 || (d = li->li_tv.vval.v_dict) == NULL)
9550 {
9551 EMSG(_(e_invarg));
9552 return;
9553 }
9554 if (!(dict_find(d, (char_u *)"group", -1) != NULL
9555 && (dict_find(d, (char_u *)"pattern", -1) != NULL
9556 || dict_find(d, (char_u *)"pos1", -1) != NULL)
9557 && dict_find(d, (char_u *)"priority", -1) != NULL
9558 && dict_find(d, (char_u *)"id", -1) != NULL))
9559 {
9560 EMSG(_(e_invarg));
9561 return;
9562 }
9563 li = li->li_next;
9564 }
9565
9566 clear_matches(curwin);
9567 li = l->lv_first;
9568 while (li != NULL)
9569 {
9570 int i = 0;
9571 char_u buf[5];
9572 dictitem_T *di;
9573 char_u *group;
9574 int priority;
9575 int id;
9576 char_u *conceal;
9577
9578 d = li->li_tv.vval.v_dict;
9579 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
9580 {
9581 if (s == NULL)
9582 {
9583 s = list_alloc();
9584 if (s == NULL)
9585 return;
9586 }
9587
9588 /* match from matchaddpos() */
9589 for (i = 1; i < 9; i++)
9590 {
9591 sprintf((char *)buf, (char *)"pos%d", i);
9592 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
9593 {
9594 if (di->di_tv.v_type != VAR_LIST)
9595 return;
9596
9597 list_append_tv(s, &di->di_tv);
9598 s->lv_refcount++;
9599 }
9600 else
9601 break;
9602 }
9603 }
9604
9605 group = get_dict_string(d, (char_u *)"group", FALSE);
9606 priority = (int)get_dict_number(d, (char_u *)"priority");
9607 id = (int)get_dict_number(d, (char_u *)"id");
9608 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
9609 ? get_dict_string(d, (char_u *)"conceal", FALSE)
9610 : NULL;
9611 if (i == 0)
9612 {
9613 match_add(curwin, group,
9614 get_dict_string(d, (char_u *)"pattern", FALSE),
9615 priority, id, NULL, conceal);
9616 }
9617 else
9618 {
9619 match_add(curwin, group, NULL, priority, id, s, conceal);
9620 list_unref(s);
9621 s = NULL;
9622 }
9623
9624 li = li->li_next;
9625 }
9626 rettv->vval.v_number = 0;
9627 }
9628#endif
9629}
9630
9631/*
9632 * "setpos()" function
9633 */
9634 static void
9635f_setpos(typval_T *argvars, typval_T *rettv)
9636{
9637 pos_T pos;
9638 int fnum;
9639 char_u *name;
9640 colnr_T curswant = -1;
9641
9642 rettv->vval.v_number = -1;
9643 name = get_tv_string_chk(argvars);
9644 if (name != NULL)
9645 {
9646 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
9647 {
9648 if (--pos.col < 0)
9649 pos.col = 0;
9650 if (name[0] == '.' && name[1] == NUL)
9651 {
9652 /* set cursor */
9653 if (fnum == curbuf->b_fnum)
9654 {
9655 curwin->w_cursor = pos;
9656 if (curswant >= 0)
9657 {
9658 curwin->w_curswant = curswant - 1;
9659 curwin->w_set_curswant = FALSE;
9660 }
9661 check_cursor();
9662 rettv->vval.v_number = 0;
9663 }
9664 else
9665 EMSG(_(e_invarg));
9666 }
9667 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
9668 {
9669 /* set mark */
9670 if (setmark_pos(name[1], &pos, fnum) == OK)
9671 rettv->vval.v_number = 0;
9672 }
9673 else
9674 EMSG(_(e_invarg));
9675 }
9676 }
9677}
9678
9679/*
9680 * "setqflist()" function
9681 */
9682 static void
9683f_setqflist(typval_T *argvars, typval_T *rettv)
9684{
9685 set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv);
9686}
9687
9688/*
9689 * "setreg()" function
9690 */
9691 static void
9692f_setreg(typval_T *argvars, typval_T *rettv)
9693{
9694 int regname;
9695 char_u *strregname;
9696 char_u *stropt;
9697 char_u *strval;
9698 int append;
9699 char_u yank_type;
9700 long block_len;
9701
9702 block_len = -1;
9703 yank_type = MAUTO;
9704 append = FALSE;
9705
9706 strregname = get_tv_string_chk(argvars);
9707 rettv->vval.v_number = 1; /* FAIL is default */
9708
9709 if (strregname == NULL)
9710 return; /* type error; errmsg already given */
9711 regname = *strregname;
9712 if (regname == 0 || regname == '@')
9713 regname = '"';
9714
9715 if (argvars[2].v_type != VAR_UNKNOWN)
9716 {
9717 stropt = get_tv_string_chk(&argvars[2]);
9718 if (stropt == NULL)
9719 return; /* type error */
9720 for (; *stropt != NUL; ++stropt)
9721 switch (*stropt)
9722 {
9723 case 'a': case 'A': /* append */
9724 append = TRUE;
9725 break;
9726 case 'v': case 'c': /* character-wise selection */
9727 yank_type = MCHAR;
9728 break;
9729 case 'V': case 'l': /* line-wise selection */
9730 yank_type = MLINE;
9731 break;
9732 case 'b': case Ctrl_V: /* block-wise selection */
9733 yank_type = MBLOCK;
9734 if (VIM_ISDIGIT(stropt[1]))
9735 {
9736 ++stropt;
9737 block_len = getdigits(&stropt) - 1;
9738 --stropt;
9739 }
9740 break;
9741 }
9742 }
9743
9744 if (argvars[1].v_type == VAR_LIST)
9745 {
9746 char_u **lstval;
9747 char_u **allocval;
9748 char_u buf[NUMBUFLEN];
9749 char_u **curval;
9750 char_u **curallocval;
9751 list_T *ll = argvars[1].vval.v_list;
9752 listitem_T *li;
9753 int len;
9754
9755 /* If the list is NULL handle like an empty list. */
9756 len = ll == NULL ? 0 : ll->lv_len;
9757
9758 /* First half: use for pointers to result lines; second half: use for
9759 * pointers to allocated copies. */
9760 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
9761 if (lstval == NULL)
9762 return;
9763 curval = lstval;
9764 allocval = lstval + len + 2;
9765 curallocval = allocval;
9766
9767 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
9768 li = li->li_next)
9769 {
9770 strval = get_tv_string_buf_chk(&li->li_tv, buf);
9771 if (strval == NULL)
9772 goto free_lstval;
9773 if (strval == buf)
9774 {
9775 /* Need to make a copy, next get_tv_string_buf_chk() will
9776 * overwrite the string. */
9777 strval = vim_strsave(buf);
9778 if (strval == NULL)
9779 goto free_lstval;
9780 *curallocval++ = strval;
9781 }
9782 *curval++ = strval;
9783 }
9784 *curval++ = NULL;
9785
9786 write_reg_contents_lst(regname, lstval, -1,
9787 append, yank_type, block_len);
9788free_lstval:
9789 while (curallocval > allocval)
9790 vim_free(*--curallocval);
9791 vim_free(lstval);
9792 }
9793 else
9794 {
9795 strval = get_tv_string_chk(&argvars[1]);
9796 if (strval == NULL)
9797 return;
9798 write_reg_contents_ex(regname, strval, -1,
9799 append, yank_type, block_len);
9800 }
9801 rettv->vval.v_number = 0;
9802}
9803
9804/*
9805 * "settabvar()" function
9806 */
9807 static void
9808f_settabvar(typval_T *argvars, typval_T *rettv)
9809{
9810#ifdef FEAT_WINDOWS
9811 tabpage_T *save_curtab;
9812 tabpage_T *tp;
9813#endif
9814 char_u *varname, *tabvarname;
9815 typval_T *varp;
9816
9817 rettv->vval.v_number = 0;
9818
9819 if (check_restricted() || check_secure())
9820 return;
9821
9822#ifdef FEAT_WINDOWS
9823 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
9824#endif
9825 varname = get_tv_string_chk(&argvars[1]);
9826 varp = &argvars[2];
9827
9828 if (varname != NULL && varp != NULL
9829#ifdef FEAT_WINDOWS
9830 && tp != NULL
9831#endif
9832 )
9833 {
9834#ifdef FEAT_WINDOWS
9835 save_curtab = curtab;
9836 goto_tabpage_tp(tp, FALSE, FALSE);
9837#endif
9838
9839 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
9840 if (tabvarname != NULL)
9841 {
9842 STRCPY(tabvarname, "t:");
9843 STRCPY(tabvarname + 2, varname);
9844 set_var(tabvarname, varp, TRUE);
9845 vim_free(tabvarname);
9846 }
9847
9848#ifdef FEAT_WINDOWS
9849 /* Restore current tabpage */
9850 if (valid_tabpage(save_curtab))
9851 goto_tabpage_tp(save_curtab, FALSE, FALSE);
9852#endif
9853 }
9854}
9855
9856/*
9857 * "settabwinvar()" function
9858 */
9859 static void
9860f_settabwinvar(typval_T *argvars, typval_T *rettv)
9861{
9862 setwinvar(argvars, rettv, 1);
9863}
9864
9865/*
9866 * "setwinvar()" function
9867 */
9868 static void
9869f_setwinvar(typval_T *argvars, typval_T *rettv)
9870{
9871 setwinvar(argvars, rettv, 0);
9872}
9873
9874#ifdef FEAT_CRYPT
9875/*
9876 * "sha256({string})" function
9877 */
9878 static void
9879f_sha256(typval_T *argvars, typval_T *rettv)
9880{
9881 char_u *p;
9882
9883 p = get_tv_string(&argvars[0]);
9884 rettv->vval.v_string = vim_strsave(
9885 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
9886 rettv->v_type = VAR_STRING;
9887}
9888#endif /* FEAT_CRYPT */
9889
9890/*
9891 * "shellescape({string})" function
9892 */
9893 static void
9894f_shellescape(typval_T *argvars, typval_T *rettv)
9895{
9896 rettv->vval.v_string = vim_strsave_shellescape(
9897 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE);
9898 rettv->v_type = VAR_STRING;
9899}
9900
9901/*
9902 * shiftwidth() function
9903 */
9904 static void
9905f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
9906{
9907 rettv->vval.v_number = get_sw_value(curbuf);
9908}
9909
9910/*
9911 * "simplify()" function
9912 */
9913 static void
9914f_simplify(typval_T *argvars, typval_T *rettv)
9915{
9916 char_u *p;
9917
9918 p = get_tv_string(&argvars[0]);
9919 rettv->vval.v_string = vim_strsave(p);
9920 simplify_filename(rettv->vval.v_string); /* simplify in place */
9921 rettv->v_type = VAR_STRING;
9922}
9923
9924#ifdef FEAT_FLOAT
9925/*
9926 * "sin()" function
9927 */
9928 static void
9929f_sin(typval_T *argvars, typval_T *rettv)
9930{
9931 float_T f = 0.0;
9932
9933 rettv->v_type = VAR_FLOAT;
9934 if (get_float_arg(argvars, &f) == OK)
9935 rettv->vval.v_float = sin(f);
9936 else
9937 rettv->vval.v_float = 0.0;
9938}
9939
9940/*
9941 * "sinh()" function
9942 */
9943 static void
9944f_sinh(typval_T *argvars, typval_T *rettv)
9945{
9946 float_T f = 0.0;
9947
9948 rettv->v_type = VAR_FLOAT;
9949 if (get_float_arg(argvars, &f) == OK)
9950 rettv->vval.v_float = sinh(f);
9951 else
9952 rettv->vval.v_float = 0.0;
9953}
9954#endif
9955
9956static int
9957#ifdef __BORLANDC__
9958 _RTLENTRYF
9959#endif
9960 item_compare(const void *s1, const void *s2);
9961static int
9962#ifdef __BORLANDC__
9963 _RTLENTRYF
9964#endif
9965 item_compare2(const void *s1, const void *s2);
9966
9967/* struct used in the array that's given to qsort() */
9968typedef struct
9969{
9970 listitem_T *item;
9971 int idx;
9972} sortItem_T;
9973
9974/* struct storing information about current sort */
9975typedef struct
9976{
9977 int item_compare_ic;
9978 int item_compare_numeric;
9979 int item_compare_numbers;
9980#ifdef FEAT_FLOAT
9981 int item_compare_float;
9982#endif
9983 char_u *item_compare_func;
9984 partial_T *item_compare_partial;
9985 dict_T *item_compare_selfdict;
9986 int item_compare_func_err;
9987 int item_compare_keep_zero;
9988} sortinfo_T;
9989static sortinfo_T *sortinfo = NULL;
9990static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
9991#define ITEM_COMPARE_FAIL 999
9992
9993/*
9994 * Compare functions for f_sort() and f_uniq() below.
9995 */
9996 static int
9997#ifdef __BORLANDC__
9998_RTLENTRYF
9999#endif
10000item_compare(const void *s1, const void *s2)
10001{
10002 sortItem_T *si1, *si2;
10003 typval_T *tv1, *tv2;
10004 char_u *p1, *p2;
10005 char_u *tofree1 = NULL, *tofree2 = NULL;
10006 int res;
10007 char_u numbuf1[NUMBUFLEN];
10008 char_u numbuf2[NUMBUFLEN];
10009
10010 si1 = (sortItem_T *)s1;
10011 si2 = (sortItem_T *)s2;
10012 tv1 = &si1->item->li_tv;
10013 tv2 = &si2->item->li_tv;
10014
10015 if (sortinfo->item_compare_numbers)
10016 {
10017 varnumber_T v1 = get_tv_number(tv1);
10018 varnumber_T v2 = get_tv_number(tv2);
10019
10020 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10021 }
10022
10023#ifdef FEAT_FLOAT
10024 if (sortinfo->item_compare_float)
10025 {
10026 float_T v1 = get_tv_float(tv1);
10027 float_T v2 = get_tv_float(tv2);
10028
10029 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10030 }
10031#endif
10032
10033 /* tv2string() puts quotes around a string and allocates memory. Don't do
10034 * that for string variables. Use a single quote when comparing with a
10035 * non-string to do what the docs promise. */
10036 if (tv1->v_type == VAR_STRING)
10037 {
10038 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10039 p1 = (char_u *)"'";
10040 else
10041 p1 = tv1->vval.v_string;
10042 }
10043 else
10044 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10045 if (tv2->v_type == VAR_STRING)
10046 {
10047 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10048 p2 = (char_u *)"'";
10049 else
10050 p2 = tv2->vval.v_string;
10051 }
10052 else
10053 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10054 if (p1 == NULL)
10055 p1 = (char_u *)"";
10056 if (p2 == NULL)
10057 p2 = (char_u *)"";
10058 if (!sortinfo->item_compare_numeric)
10059 {
10060 if (sortinfo->item_compare_ic)
10061 res = STRICMP(p1, p2);
10062 else
10063 res = STRCMP(p1, p2);
10064 }
10065 else
10066 {
10067 double n1, n2;
10068 n1 = strtod((char *)p1, (char **)&p1);
10069 n2 = strtod((char *)p2, (char **)&p2);
10070 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10071 }
10072
10073 /* When the result would be zero, compare the item indexes. Makes the
10074 * sort stable. */
10075 if (res == 0 && !sortinfo->item_compare_keep_zero)
10076 res = si1->idx > si2->idx ? 1 : -1;
10077
10078 vim_free(tofree1);
10079 vim_free(tofree2);
10080 return res;
10081}
10082
10083 static int
10084#ifdef __BORLANDC__
10085_RTLENTRYF
10086#endif
10087item_compare2(const void *s1, const void *s2)
10088{
10089 sortItem_T *si1, *si2;
10090 int res;
10091 typval_T rettv;
10092 typval_T argv[3];
10093 int dummy;
10094 char_u *func_name;
10095 partial_T *partial = sortinfo->item_compare_partial;
10096
10097 /* shortcut after failure in previous call; compare all items equal */
10098 if (sortinfo->item_compare_func_err)
10099 return 0;
10100
10101 si1 = (sortItem_T *)s1;
10102 si2 = (sortItem_T *)s2;
10103
10104 if (partial == NULL)
10105 func_name = sortinfo->item_compare_func;
10106 else
10107 func_name = partial->pt_name;
10108
10109 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10110 * in the copy without changing the original list items. */
10111 copy_tv(&si1->item->li_tv, &argv[0]);
10112 copy_tv(&si2->item->li_tv, &argv[1]);
10113
10114 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10115 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010116 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010117 partial, sortinfo->item_compare_selfdict);
10118 clear_tv(&argv[0]);
10119 clear_tv(&argv[1]);
10120
10121 if (res == FAIL)
10122 res = ITEM_COMPARE_FAIL;
10123 else
10124 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10125 if (sortinfo->item_compare_func_err)
10126 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10127 clear_tv(&rettv);
10128
10129 /* When the result would be zero, compare the pointers themselves. Makes
10130 * the sort stable. */
10131 if (res == 0 && !sortinfo->item_compare_keep_zero)
10132 res = si1->idx > si2->idx ? 1 : -1;
10133
10134 return res;
10135}
10136
10137/*
10138 * "sort({list})" function
10139 */
10140 static void
10141do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10142{
10143 list_T *l;
10144 listitem_T *li;
10145 sortItem_T *ptrs;
10146 sortinfo_T *old_sortinfo;
10147 sortinfo_T info;
10148 long len;
10149 long i;
10150
10151 /* Pointer to current info struct used in compare function. Save and
10152 * restore the current one for nested calls. */
10153 old_sortinfo = sortinfo;
10154 sortinfo = &info;
10155
10156 if (argvars[0].v_type != VAR_LIST)
10157 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10158 else
10159 {
10160 l = argvars[0].vval.v_list;
10161 if (l == NULL || tv_check_lock(l->lv_lock,
10162 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10163 TRUE))
10164 goto theend;
10165 rettv->vval.v_list = l;
10166 rettv->v_type = VAR_LIST;
10167 ++l->lv_refcount;
10168
10169 len = list_len(l);
10170 if (len <= 1)
10171 goto theend; /* short list sorts pretty quickly */
10172
10173 info.item_compare_ic = FALSE;
10174 info.item_compare_numeric = FALSE;
10175 info.item_compare_numbers = FALSE;
10176#ifdef FEAT_FLOAT
10177 info.item_compare_float = FALSE;
10178#endif
10179 info.item_compare_func = NULL;
10180 info.item_compare_partial = NULL;
10181 info.item_compare_selfdict = NULL;
10182 if (argvars[1].v_type != VAR_UNKNOWN)
10183 {
10184 /* optional second argument: {func} */
10185 if (argvars[1].v_type == VAR_FUNC)
10186 info.item_compare_func = argvars[1].vval.v_string;
10187 else if (argvars[1].v_type == VAR_PARTIAL)
10188 info.item_compare_partial = argvars[1].vval.v_partial;
10189 else
10190 {
10191 int error = FALSE;
10192
10193 i = (long)get_tv_number_chk(&argvars[1], &error);
10194 if (error)
10195 goto theend; /* type error; errmsg already given */
10196 if (i == 1)
10197 info.item_compare_ic = TRUE;
10198 else if (argvars[1].v_type != VAR_NUMBER)
10199 info.item_compare_func = get_tv_string(&argvars[1]);
10200 else if (i != 0)
10201 {
10202 EMSG(_(e_invarg));
10203 goto theend;
10204 }
10205 if (info.item_compare_func != NULL)
10206 {
10207 if (*info.item_compare_func == NUL)
10208 {
10209 /* empty string means default sort */
10210 info.item_compare_func = NULL;
10211 }
10212 else if (STRCMP(info.item_compare_func, "n") == 0)
10213 {
10214 info.item_compare_func = NULL;
10215 info.item_compare_numeric = TRUE;
10216 }
10217 else if (STRCMP(info.item_compare_func, "N") == 0)
10218 {
10219 info.item_compare_func = NULL;
10220 info.item_compare_numbers = TRUE;
10221 }
10222#ifdef FEAT_FLOAT
10223 else if (STRCMP(info.item_compare_func, "f") == 0)
10224 {
10225 info.item_compare_func = NULL;
10226 info.item_compare_float = TRUE;
10227 }
10228#endif
10229 else if (STRCMP(info.item_compare_func, "i") == 0)
10230 {
10231 info.item_compare_func = NULL;
10232 info.item_compare_ic = TRUE;
10233 }
10234 }
10235 }
10236
10237 if (argvars[2].v_type != VAR_UNKNOWN)
10238 {
10239 /* optional third argument: {dict} */
10240 if (argvars[2].v_type != VAR_DICT)
10241 {
10242 EMSG(_(e_dictreq));
10243 goto theend;
10244 }
10245 info.item_compare_selfdict = argvars[2].vval.v_dict;
10246 }
10247 }
10248
10249 /* Make an array with each entry pointing to an item in the List. */
10250 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10251 if (ptrs == NULL)
10252 goto theend;
10253
10254 i = 0;
10255 if (sort)
10256 {
10257 /* sort(): ptrs will be the list to sort */
10258 for (li = l->lv_first; li != NULL; li = li->li_next)
10259 {
10260 ptrs[i].item = li;
10261 ptrs[i].idx = i;
10262 ++i;
10263 }
10264
10265 info.item_compare_func_err = FALSE;
10266 info.item_compare_keep_zero = FALSE;
10267 /* test the compare function */
10268 if ((info.item_compare_func != NULL
10269 || info.item_compare_partial != NULL)
10270 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10271 == ITEM_COMPARE_FAIL)
10272 EMSG(_("E702: Sort compare function failed"));
10273 else
10274 {
10275 /* Sort the array with item pointers. */
10276 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10277 info.item_compare_func == NULL
10278 && info.item_compare_partial == NULL
10279 ? item_compare : item_compare2);
10280
10281 if (!info.item_compare_func_err)
10282 {
10283 /* Clear the List and append the items in sorted order. */
10284 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10285 l->lv_len = 0;
10286 for (i = 0; i < len; ++i)
10287 list_append(l, ptrs[i].item);
10288 }
10289 }
10290 }
10291 else
10292 {
10293 int (*item_compare_func_ptr)(const void *, const void *);
10294
10295 /* f_uniq(): ptrs will be a stack of items to remove */
10296 info.item_compare_func_err = FALSE;
10297 info.item_compare_keep_zero = TRUE;
10298 item_compare_func_ptr = info.item_compare_func != NULL
10299 || info.item_compare_partial != NULL
10300 ? item_compare2 : item_compare;
10301
10302 for (li = l->lv_first; li != NULL && li->li_next != NULL;
10303 li = li->li_next)
10304 {
10305 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10306 == 0)
10307 ptrs[i++].item = li;
10308 if (info.item_compare_func_err)
10309 {
10310 EMSG(_("E882: Uniq compare function failed"));
10311 break;
10312 }
10313 }
10314
10315 if (!info.item_compare_func_err)
10316 {
10317 while (--i >= 0)
10318 {
10319 li = ptrs[i].item->li_next;
10320 ptrs[i].item->li_next = li->li_next;
10321 if (li->li_next != NULL)
10322 li->li_next->li_prev = ptrs[i].item;
10323 else
10324 l->lv_last = ptrs[i].item;
10325 list_fix_watch(l, li);
10326 listitem_free(li);
10327 l->lv_len--;
10328 }
10329 }
10330 }
10331
10332 vim_free(ptrs);
10333 }
10334theend:
10335 sortinfo = old_sortinfo;
10336}
10337
10338/*
10339 * "sort({list})" function
10340 */
10341 static void
10342f_sort(typval_T *argvars, typval_T *rettv)
10343{
10344 do_sort_uniq(argvars, rettv, TRUE);
10345}
10346
10347/*
10348 * "uniq({list})" function
10349 */
10350 static void
10351f_uniq(typval_T *argvars, typval_T *rettv)
10352{
10353 do_sort_uniq(argvars, rettv, FALSE);
10354}
10355
10356/*
10357 * "soundfold({word})" function
10358 */
10359 static void
10360f_soundfold(typval_T *argvars, typval_T *rettv)
10361{
10362 char_u *s;
10363
10364 rettv->v_type = VAR_STRING;
10365 s = get_tv_string(&argvars[0]);
10366#ifdef FEAT_SPELL
10367 rettv->vval.v_string = eval_soundfold(s);
10368#else
10369 rettv->vval.v_string = vim_strsave(s);
10370#endif
10371}
10372
10373/*
10374 * "spellbadword()" function
10375 */
10376 static void
10377f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10378{
10379 char_u *word = (char_u *)"";
10380 hlf_T attr = HLF_COUNT;
10381 int len = 0;
10382
10383 if (rettv_list_alloc(rettv) == FAIL)
10384 return;
10385
10386#ifdef FEAT_SPELL
10387 if (argvars[0].v_type == VAR_UNKNOWN)
10388 {
10389 /* Find the start and length of the badly spelled word. */
10390 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10391 if (len != 0)
10392 word = ml_get_cursor();
10393 }
10394 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10395 {
10396 char_u *str = get_tv_string_chk(&argvars[0]);
10397 int capcol = -1;
10398
10399 if (str != NULL)
10400 {
10401 /* Check the argument for spelling. */
10402 while (*str != NUL)
10403 {
10404 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10405 if (attr != HLF_COUNT)
10406 {
10407 word = str;
10408 break;
10409 }
10410 str += len;
10411 }
10412 }
10413 }
10414#endif
10415
10416 list_append_string(rettv->vval.v_list, word, len);
10417 list_append_string(rettv->vval.v_list, (char_u *)(
10418 attr == HLF_SPB ? "bad" :
10419 attr == HLF_SPR ? "rare" :
10420 attr == HLF_SPL ? "local" :
10421 attr == HLF_SPC ? "caps" :
10422 ""), -1);
10423}
10424
10425/*
10426 * "spellsuggest()" function
10427 */
10428 static void
10429f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10430{
10431#ifdef FEAT_SPELL
10432 char_u *str;
10433 int typeerr = FALSE;
10434 int maxcount;
10435 garray_T ga;
10436 int i;
10437 listitem_T *li;
10438 int need_capital = FALSE;
10439#endif
10440
10441 if (rettv_list_alloc(rettv) == FAIL)
10442 return;
10443
10444#ifdef FEAT_SPELL
10445 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10446 {
10447 str = get_tv_string(&argvars[0]);
10448 if (argvars[1].v_type != VAR_UNKNOWN)
10449 {
10450 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
10451 if (maxcount <= 0)
10452 return;
10453 if (argvars[2].v_type != VAR_UNKNOWN)
10454 {
10455 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
10456 if (typeerr)
10457 return;
10458 }
10459 }
10460 else
10461 maxcount = 25;
10462
10463 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10464
10465 for (i = 0; i < ga.ga_len; ++i)
10466 {
10467 str = ((char_u **)ga.ga_data)[i];
10468
10469 li = listitem_alloc();
10470 if (li == NULL)
10471 vim_free(str);
10472 else
10473 {
10474 li->li_tv.v_type = VAR_STRING;
10475 li->li_tv.v_lock = 0;
10476 li->li_tv.vval.v_string = str;
10477 list_append(rettv->vval.v_list, li);
10478 }
10479 }
10480 ga_clear(&ga);
10481 }
10482#endif
10483}
10484
10485 static void
10486f_split(typval_T *argvars, typval_T *rettv)
10487{
10488 char_u *str;
10489 char_u *end;
10490 char_u *pat = NULL;
10491 regmatch_T regmatch;
10492 char_u patbuf[NUMBUFLEN];
10493 char_u *save_cpo;
10494 int match;
10495 colnr_T col = 0;
10496 int keepempty = FALSE;
10497 int typeerr = FALSE;
10498
10499 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10500 save_cpo = p_cpo;
10501 p_cpo = (char_u *)"";
10502
10503 str = get_tv_string(&argvars[0]);
10504 if (argvars[1].v_type != VAR_UNKNOWN)
10505 {
10506 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
10507 if (pat == NULL)
10508 typeerr = TRUE;
10509 if (argvars[2].v_type != VAR_UNKNOWN)
10510 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
10511 }
10512 if (pat == NULL || *pat == NUL)
10513 pat = (char_u *)"[\\x01- ]\\+";
10514
10515 if (rettv_list_alloc(rettv) == FAIL)
10516 return;
10517 if (typeerr)
10518 return;
10519
10520 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10521 if (regmatch.regprog != NULL)
10522 {
10523 regmatch.rm_ic = FALSE;
10524 while (*str != NUL || keepempty)
10525 {
10526 if (*str == NUL)
10527 match = FALSE; /* empty item at the end */
10528 else
10529 match = vim_regexec_nl(&regmatch, str, col);
10530 if (match)
10531 end = regmatch.startp[0];
10532 else
10533 end = str + STRLEN(str);
10534 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10535 && *str != NUL && match && end < regmatch.endp[0]))
10536 {
10537 if (list_append_string(rettv->vval.v_list, str,
10538 (int)(end - str)) == FAIL)
10539 break;
10540 }
10541 if (!match)
10542 break;
10543 /* Advance to just after the match. */
10544 if (regmatch.endp[0] > str)
10545 col = 0;
10546 else
10547 {
10548 /* Don't get stuck at the same match. */
10549#ifdef FEAT_MBYTE
10550 col = (*mb_ptr2len)(regmatch.endp[0]);
10551#else
10552 col = 1;
10553#endif
10554 }
10555 str = regmatch.endp[0];
10556 }
10557
10558 vim_regfree(regmatch.regprog);
10559 }
10560
10561 p_cpo = save_cpo;
10562}
10563
10564#ifdef FEAT_FLOAT
10565/*
10566 * "sqrt()" function
10567 */
10568 static void
10569f_sqrt(typval_T *argvars, typval_T *rettv)
10570{
10571 float_T f = 0.0;
10572
10573 rettv->v_type = VAR_FLOAT;
10574 if (get_float_arg(argvars, &f) == OK)
10575 rettv->vval.v_float = sqrt(f);
10576 else
10577 rettv->vval.v_float = 0.0;
10578}
10579
10580/*
10581 * "str2float()" function
10582 */
10583 static void
10584f_str2float(typval_T *argvars, typval_T *rettv)
10585{
10586 char_u *p = skipwhite(get_tv_string(&argvars[0]));
10587
10588 if (*p == '+')
10589 p = skipwhite(p + 1);
10590 (void)string2float(p, &rettv->vval.v_float);
10591 rettv->v_type = VAR_FLOAT;
10592}
10593#endif
10594
10595/*
10596 * "str2nr()" function
10597 */
10598 static void
10599f_str2nr(typval_T *argvars, typval_T *rettv)
10600{
10601 int base = 10;
10602 char_u *p;
10603 varnumber_T n;
10604 int what;
10605
10606 if (argvars[1].v_type != VAR_UNKNOWN)
10607 {
10608 base = (int)get_tv_number(&argvars[1]);
10609 if (base != 2 && base != 8 && base != 10 && base != 16)
10610 {
10611 EMSG(_(e_invarg));
10612 return;
10613 }
10614 }
10615
10616 p = skipwhite(get_tv_string(&argvars[0]));
10617 if (*p == '+')
10618 p = skipwhite(p + 1);
10619 switch (base)
10620 {
10621 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10622 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10623 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10624 default: what = 0;
10625 }
10626 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
10627 rettv->vval.v_number = n;
10628}
10629
10630#ifdef HAVE_STRFTIME
10631/*
10632 * "strftime({format}[, {time}])" function
10633 */
10634 static void
10635f_strftime(typval_T *argvars, typval_T *rettv)
10636{
10637 char_u result_buf[256];
10638 struct tm *curtime;
10639 time_t seconds;
10640 char_u *p;
10641
10642 rettv->v_type = VAR_STRING;
10643
10644 p = get_tv_string(&argvars[0]);
10645 if (argvars[1].v_type == VAR_UNKNOWN)
10646 seconds = time(NULL);
10647 else
10648 seconds = (time_t)get_tv_number(&argvars[1]);
10649 curtime = localtime(&seconds);
10650 /* MSVC returns NULL for an invalid value of seconds. */
10651 if (curtime == NULL)
10652 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10653 else
10654 {
10655# ifdef FEAT_MBYTE
10656 vimconv_T conv;
10657 char_u *enc;
10658
10659 conv.vc_type = CONV_NONE;
10660 enc = enc_locale();
10661 convert_setup(&conv, p_enc, enc);
10662 if (conv.vc_type != CONV_NONE)
10663 p = string_convert(&conv, p, NULL);
10664# endif
10665 if (p != NULL)
10666 (void)strftime((char *)result_buf, sizeof(result_buf),
10667 (char *)p, curtime);
10668 else
10669 result_buf[0] = NUL;
10670
10671# ifdef FEAT_MBYTE
10672 if (conv.vc_type != CONV_NONE)
10673 vim_free(p);
10674 convert_setup(&conv, enc, p_enc);
10675 if (conv.vc_type != CONV_NONE)
10676 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10677 else
10678# endif
10679 rettv->vval.v_string = vim_strsave(result_buf);
10680
10681# ifdef FEAT_MBYTE
10682 /* Release conversion descriptors */
10683 convert_setup(&conv, NULL, NULL);
10684 vim_free(enc);
10685# endif
10686 }
10687}
10688#endif
10689
10690/*
10691 * "strgetchar()" function
10692 */
10693 static void
10694f_strgetchar(typval_T *argvars, typval_T *rettv)
10695{
10696 char_u *str;
10697 int len;
10698 int error = FALSE;
10699 int charidx;
10700
10701 rettv->vval.v_number = -1;
10702 str = get_tv_string_chk(&argvars[0]);
10703 if (str == NULL)
10704 return;
10705 len = (int)STRLEN(str);
10706 charidx = (int)get_tv_number_chk(&argvars[1], &error);
10707 if (error)
10708 return;
10709#ifdef FEAT_MBYTE
10710 {
10711 int byteidx = 0;
10712
10713 while (charidx >= 0 && byteidx < len)
10714 {
10715 if (charidx == 0)
10716 {
10717 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10718 break;
10719 }
10720 --charidx;
10721 byteidx += mb_cptr2len(str + byteidx);
10722 }
10723 }
10724#else
10725 if (charidx < len)
10726 rettv->vval.v_number = str[charidx];
10727#endif
10728}
10729
10730/*
10731 * "stridx()" function
10732 */
10733 static void
10734f_stridx(typval_T *argvars, typval_T *rettv)
10735{
10736 char_u buf[NUMBUFLEN];
10737 char_u *needle;
10738 char_u *haystack;
10739 char_u *save_haystack;
10740 char_u *pos;
10741 int start_idx;
10742
10743 needle = get_tv_string_chk(&argvars[1]);
10744 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
10745 rettv->vval.v_number = -1;
10746 if (needle == NULL || haystack == NULL)
10747 return; /* type error; errmsg already given */
10748
10749 if (argvars[2].v_type != VAR_UNKNOWN)
10750 {
10751 int error = FALSE;
10752
10753 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
10754 if (error || start_idx >= (int)STRLEN(haystack))
10755 return;
10756 if (start_idx >= 0)
10757 haystack += start_idx;
10758 }
10759
10760 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10761 if (pos != NULL)
10762 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10763}
10764
10765/*
10766 * "string()" function
10767 */
10768 static void
10769f_string(typval_T *argvars, typval_T *rettv)
10770{
10771 char_u *tofree;
10772 char_u numbuf[NUMBUFLEN];
10773
10774 rettv->v_type = VAR_STRING;
10775 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10776 get_copyID());
10777 /* Make a copy if we have a value but it's not in allocated memory. */
10778 if (rettv->vval.v_string != NULL && tofree == NULL)
10779 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10780}
10781
10782/*
10783 * "strlen()" function
10784 */
10785 static void
10786f_strlen(typval_T *argvars, typval_T *rettv)
10787{
10788 rettv->vval.v_number = (varnumber_T)(STRLEN(
10789 get_tv_string(&argvars[0])));
10790}
10791
10792/*
10793 * "strchars()" function
10794 */
10795 static void
10796f_strchars(typval_T *argvars, typval_T *rettv)
10797{
10798 char_u *s = get_tv_string(&argvars[0]);
10799 int skipcc = 0;
10800#ifdef FEAT_MBYTE
10801 varnumber_T len = 0;
10802 int (*func_mb_ptr2char_adv)(char_u **pp);
10803#endif
10804
10805 if (argvars[1].v_type != VAR_UNKNOWN)
10806 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
10807 if (skipcc < 0 || skipcc > 1)
10808 EMSG(_(e_invarg));
10809 else
10810 {
10811#ifdef FEAT_MBYTE
10812 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10813 while (*s != NUL)
10814 {
10815 func_mb_ptr2char_adv(&s);
10816 ++len;
10817 }
10818 rettv->vval.v_number = len;
10819#else
10820 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
10821#endif
10822 }
10823}
10824
10825/*
10826 * "strdisplaywidth()" function
10827 */
10828 static void
10829f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10830{
10831 char_u *s = get_tv_string(&argvars[0]);
10832 int col = 0;
10833
10834 if (argvars[1].v_type != VAR_UNKNOWN)
10835 col = (int)get_tv_number(&argvars[1]);
10836
10837 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10838}
10839
10840/*
10841 * "strwidth()" function
10842 */
10843 static void
10844f_strwidth(typval_T *argvars, typval_T *rettv)
10845{
10846 char_u *s = get_tv_string(&argvars[0]);
10847
10848 rettv->vval.v_number = (varnumber_T)(
10849#ifdef FEAT_MBYTE
10850 mb_string2cells(s, -1)
10851#else
10852 STRLEN(s)
10853#endif
10854 );
10855}
10856
10857/*
10858 * "strcharpart()" function
10859 */
10860 static void
10861f_strcharpart(typval_T *argvars, typval_T *rettv)
10862{
10863#ifdef FEAT_MBYTE
10864 char_u *p;
10865 int nchar;
10866 int nbyte = 0;
10867 int charlen;
10868 int len = 0;
10869 int slen;
10870 int error = FALSE;
10871
10872 p = get_tv_string(&argvars[0]);
10873 slen = (int)STRLEN(p);
10874
10875 nchar = (int)get_tv_number_chk(&argvars[1], &error);
10876 if (!error)
10877 {
10878 if (nchar > 0)
10879 while (nchar > 0 && nbyte < slen)
10880 {
10881 nbyte += mb_cptr2len(p + nbyte);
10882 --nchar;
10883 }
10884 else
10885 nbyte = nchar;
10886 if (argvars[2].v_type != VAR_UNKNOWN)
10887 {
10888 charlen = (int)get_tv_number(&argvars[2]);
10889 while (charlen > 0 && nbyte + len < slen)
10890 {
10891 int off = nbyte + len;
10892
10893 if (off < 0)
10894 len += 1;
10895 else
10896 len += mb_cptr2len(p + off);
10897 --charlen;
10898 }
10899 }
10900 else
10901 len = slen - nbyte; /* default: all bytes that are available. */
10902 }
10903
10904 /*
10905 * Only return the overlap between the specified part and the actual
10906 * string.
10907 */
10908 if (nbyte < 0)
10909 {
10910 len += nbyte;
10911 nbyte = 0;
10912 }
10913 else if (nbyte > slen)
10914 nbyte = slen;
10915 if (len < 0)
10916 len = 0;
10917 else if (nbyte + len > slen)
10918 len = slen - nbyte;
10919
10920 rettv->v_type = VAR_STRING;
10921 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
10922#else
10923 f_strpart(argvars, rettv);
10924#endif
10925}
10926
10927/*
10928 * "strpart()" function
10929 */
10930 static void
10931f_strpart(typval_T *argvars, typval_T *rettv)
10932{
10933 char_u *p;
10934 int n;
10935 int len;
10936 int slen;
10937 int error = FALSE;
10938
10939 p = get_tv_string(&argvars[0]);
10940 slen = (int)STRLEN(p);
10941
10942 n = (int)get_tv_number_chk(&argvars[1], &error);
10943 if (error)
10944 len = 0;
10945 else if (argvars[2].v_type != VAR_UNKNOWN)
10946 len = (int)get_tv_number(&argvars[2]);
10947 else
10948 len = slen - n; /* default len: all bytes that are available. */
10949
10950 /*
10951 * Only return the overlap between the specified part and the actual
10952 * string.
10953 */
10954 if (n < 0)
10955 {
10956 len += n;
10957 n = 0;
10958 }
10959 else if (n > slen)
10960 n = slen;
10961 if (len < 0)
10962 len = 0;
10963 else if (n + len > slen)
10964 len = slen - n;
10965
10966 rettv->v_type = VAR_STRING;
10967 rettv->vval.v_string = vim_strnsave(p + n, len);
10968}
10969
10970/*
10971 * "strridx()" function
10972 */
10973 static void
10974f_strridx(typval_T *argvars, typval_T *rettv)
10975{
10976 char_u buf[NUMBUFLEN];
10977 char_u *needle;
10978 char_u *haystack;
10979 char_u *rest;
10980 char_u *lastmatch = NULL;
10981 int haystack_len, end_idx;
10982
10983 needle = get_tv_string_chk(&argvars[1]);
10984 haystack = get_tv_string_buf_chk(&argvars[0], buf);
10985
10986 rettv->vval.v_number = -1;
10987 if (needle == NULL || haystack == NULL)
10988 return; /* type error; errmsg already given */
10989
10990 haystack_len = (int)STRLEN(haystack);
10991 if (argvars[2].v_type != VAR_UNKNOWN)
10992 {
10993 /* Third argument: upper limit for index */
10994 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
10995 if (end_idx < 0)
10996 return; /* can never find a match */
10997 }
10998 else
10999 end_idx = haystack_len;
11000
11001 if (*needle == NUL)
11002 {
11003 /* Empty string matches past the end. */
11004 lastmatch = haystack + end_idx;
11005 }
11006 else
11007 {
11008 for (rest = haystack; *rest != '\0'; ++rest)
11009 {
11010 rest = (char_u *)strstr((char *)rest, (char *)needle);
11011 if (rest == NULL || rest > haystack + end_idx)
11012 break;
11013 lastmatch = rest;
11014 }
11015 }
11016
11017 if (lastmatch == NULL)
11018 rettv->vval.v_number = -1;
11019 else
11020 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11021}
11022
11023/*
11024 * "strtrans()" function
11025 */
11026 static void
11027f_strtrans(typval_T *argvars, typval_T *rettv)
11028{
11029 rettv->v_type = VAR_STRING;
11030 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11031}
11032
11033/*
11034 * "submatch()" function
11035 */
11036 static void
11037f_submatch(typval_T *argvars, typval_T *rettv)
11038{
11039 int error = FALSE;
11040 int no;
11041 int retList = 0;
11042
11043 no = (int)get_tv_number_chk(&argvars[0], &error);
11044 if (error)
11045 return;
11046 error = FALSE;
11047 if (argvars[1].v_type != VAR_UNKNOWN)
11048 retList = (int)get_tv_number_chk(&argvars[1], &error);
11049 if (error)
11050 return;
11051
11052 if (retList == 0)
11053 {
11054 rettv->v_type = VAR_STRING;
11055 rettv->vval.v_string = reg_submatch(no);
11056 }
11057 else
11058 {
11059 rettv->v_type = VAR_LIST;
11060 rettv->vval.v_list = reg_submatch_list(no);
11061 }
11062}
11063
11064/*
11065 * "substitute()" function
11066 */
11067 static void
11068f_substitute(typval_T *argvars, typval_T *rettv)
11069{
11070 char_u patbuf[NUMBUFLEN];
11071 char_u subbuf[NUMBUFLEN];
11072 char_u flagsbuf[NUMBUFLEN];
11073
11074 char_u *str = get_tv_string_chk(&argvars[0]);
11075 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011076 char_u *sub = NULL;
11077 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011078 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11079
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011080 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11081 expr = &argvars[2];
11082 else
11083 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11084
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011085 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011086 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11087 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011088 rettv->vval.v_string = NULL;
11089 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011090 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011091}
11092
11093/*
11094 * "synID(lnum, col, trans)" function
11095 */
11096 static void
11097f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11098{
11099 int id = 0;
11100#ifdef FEAT_SYN_HL
11101 linenr_T lnum;
11102 colnr_T col;
11103 int trans;
11104 int transerr = FALSE;
11105
11106 lnum = get_tv_lnum(argvars); /* -1 on type error */
11107 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11108 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11109
11110 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11111 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11112 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11113#endif
11114
11115 rettv->vval.v_number = id;
11116}
11117
11118/*
11119 * "synIDattr(id, what [, mode])" function
11120 */
11121 static void
11122f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11123{
11124 char_u *p = NULL;
11125#ifdef FEAT_SYN_HL
11126 int id;
11127 char_u *what;
11128 char_u *mode;
11129 char_u modebuf[NUMBUFLEN];
11130 int modec;
11131
11132 id = (int)get_tv_number(&argvars[0]);
11133 what = get_tv_string(&argvars[1]);
11134 if (argvars[2].v_type != VAR_UNKNOWN)
11135 {
11136 mode = get_tv_string_buf(&argvars[2], modebuf);
11137 modec = TOLOWER_ASC(mode[0]);
11138 if (modec != 't' && modec != 'c' && modec != 'g')
11139 modec = 0; /* replace invalid with current */
11140 }
11141 else
11142 {
11143#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11144 if (USE_24BIT)
11145 modec = 'g';
11146 else
11147#endif
11148 if (t_colors > 1)
11149 modec = 'c';
11150 else
11151 modec = 't';
11152 }
11153
11154
11155 switch (TOLOWER_ASC(what[0]))
11156 {
11157 case 'b':
11158 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11159 p = highlight_color(id, what, modec);
11160 else /* bold */
11161 p = highlight_has_attr(id, HL_BOLD, modec);
11162 break;
11163
11164 case 'f': /* fg[#] or font */
11165 p = highlight_color(id, what, modec);
11166 break;
11167
11168 case 'i':
11169 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11170 p = highlight_has_attr(id, HL_INVERSE, modec);
11171 else /* italic */
11172 p = highlight_has_attr(id, HL_ITALIC, modec);
11173 break;
11174
11175 case 'n': /* name */
11176 p = get_highlight_name(NULL, id - 1);
11177 break;
11178
11179 case 'r': /* reverse */
11180 p = highlight_has_attr(id, HL_INVERSE, modec);
11181 break;
11182
11183 case 's':
11184 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11185 p = highlight_color(id, what, modec);
11186 else /* standout */
11187 p = highlight_has_attr(id, HL_STANDOUT, modec);
11188 break;
11189
11190 case 'u':
11191 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11192 /* underline */
11193 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11194 else
11195 /* undercurl */
11196 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11197 break;
11198 }
11199
11200 if (p != NULL)
11201 p = vim_strsave(p);
11202#endif
11203 rettv->v_type = VAR_STRING;
11204 rettv->vval.v_string = p;
11205}
11206
11207/*
11208 * "synIDtrans(id)" function
11209 */
11210 static void
11211f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11212{
11213 int id;
11214
11215#ifdef FEAT_SYN_HL
11216 id = (int)get_tv_number(&argvars[0]);
11217
11218 if (id > 0)
11219 id = syn_get_final_id(id);
11220 else
11221#endif
11222 id = 0;
11223
11224 rettv->vval.v_number = id;
11225}
11226
11227/*
11228 * "synconcealed(lnum, col)" function
11229 */
11230 static void
11231f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11232{
11233#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11234 linenr_T lnum;
11235 colnr_T col;
11236 int syntax_flags = 0;
11237 int cchar;
11238 int matchid = 0;
11239 char_u str[NUMBUFLEN];
11240#endif
11241
11242 rettv->v_type = VAR_LIST;
11243 rettv->vval.v_list = NULL;
11244
11245#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11246 lnum = get_tv_lnum(argvars); /* -1 on type error */
11247 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11248
11249 vim_memset(str, NUL, sizeof(str));
11250
11251 if (rettv_list_alloc(rettv) != FAIL)
11252 {
11253 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11254 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11255 && curwin->w_p_cole > 0)
11256 {
11257 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11258 syntax_flags = get_syntax_info(&matchid);
11259
11260 /* get the conceal character */
11261 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11262 {
11263 cchar = syn_get_sub_char();
11264 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL)
11265 cchar = lcs_conceal;
11266 if (cchar != NUL)
11267 {
11268# ifdef FEAT_MBYTE
11269 if (has_mbyte)
11270 (*mb_char2bytes)(cchar, str);
11271 else
11272# endif
11273 str[0] = cchar;
11274 }
11275 }
11276 }
11277
11278 list_append_number(rettv->vval.v_list,
11279 (syntax_flags & HL_CONCEAL) != 0);
11280 /* -1 to auto-determine strlen */
11281 list_append_string(rettv->vval.v_list, str, -1);
11282 list_append_number(rettv->vval.v_list, matchid);
11283 }
11284#endif
11285}
11286
11287/*
11288 * "synstack(lnum, col)" function
11289 */
11290 static void
11291f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11292{
11293#ifdef FEAT_SYN_HL
11294 linenr_T lnum;
11295 colnr_T col;
11296 int i;
11297 int id;
11298#endif
11299
11300 rettv->v_type = VAR_LIST;
11301 rettv->vval.v_list = NULL;
11302
11303#ifdef FEAT_SYN_HL
11304 lnum = get_tv_lnum(argvars); /* -1 on type error */
11305 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11306
11307 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11308 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11309 && rettv_list_alloc(rettv) != FAIL)
11310 {
11311 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11312 for (i = 0; ; ++i)
11313 {
11314 id = syn_get_stack_item(i);
11315 if (id < 0)
11316 break;
11317 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11318 break;
11319 }
11320 }
11321#endif
11322}
11323
11324 static void
11325get_cmd_output_as_rettv(
11326 typval_T *argvars,
11327 typval_T *rettv,
11328 int retlist)
11329{
11330 char_u *res = NULL;
11331 char_u *p;
11332 char_u *infile = NULL;
11333 char_u buf[NUMBUFLEN];
11334 int err = FALSE;
11335 FILE *fd;
11336 list_T *list = NULL;
11337 int flags = SHELL_SILENT;
11338
11339 rettv->v_type = VAR_STRING;
11340 rettv->vval.v_string = NULL;
11341 if (check_restricted() || check_secure())
11342 goto errret;
11343
11344 if (argvars[1].v_type != VAR_UNKNOWN)
11345 {
11346 /*
11347 * Write the string to a temp file, to be used for input of the shell
11348 * command.
11349 */
11350 if ((infile = vim_tempname('i', TRUE)) == NULL)
11351 {
11352 EMSG(_(e_notmp));
11353 goto errret;
11354 }
11355
11356 fd = mch_fopen((char *)infile, WRITEBIN);
11357 if (fd == NULL)
11358 {
11359 EMSG2(_(e_notopen), infile);
11360 goto errret;
11361 }
11362 if (argvars[1].v_type == VAR_LIST)
11363 {
11364 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11365 err = TRUE;
11366 }
11367 else
11368 {
11369 size_t len;
11370
11371 p = get_tv_string_buf_chk(&argvars[1], buf);
11372 if (p == NULL)
11373 {
11374 fclose(fd);
11375 goto errret; /* type error; errmsg already given */
11376 }
11377 len = STRLEN(p);
11378 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11379 err = TRUE;
11380 }
11381 if (fclose(fd) != 0)
11382 err = TRUE;
11383 if (err)
11384 {
11385 EMSG(_("E677: Error writing temp file"));
11386 goto errret;
11387 }
11388 }
11389
11390 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11391 * echoes typeahead, that messes up the display. */
11392 if (!msg_silent)
11393 flags += SHELL_COOKED;
11394
11395 if (retlist)
11396 {
11397 int len;
11398 listitem_T *li;
11399 char_u *s = NULL;
11400 char_u *start;
11401 char_u *end;
11402 int i;
11403
11404 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
11405 if (res == NULL)
11406 goto errret;
11407
11408 list = list_alloc();
11409 if (list == NULL)
11410 goto errret;
11411
11412 for (i = 0; i < len; ++i)
11413 {
11414 start = res + i;
11415 while (i < len && res[i] != NL)
11416 ++i;
11417 end = res + i;
11418
11419 s = alloc((unsigned)(end - start + 1));
11420 if (s == NULL)
11421 goto errret;
11422
11423 for (p = s; start < end; ++p, ++start)
11424 *p = *start == NUL ? NL : *start;
11425 *p = NUL;
11426
11427 li = listitem_alloc();
11428 if (li == NULL)
11429 {
11430 vim_free(s);
11431 goto errret;
11432 }
11433 li->li_tv.v_type = VAR_STRING;
11434 li->li_tv.v_lock = 0;
11435 li->li_tv.vval.v_string = s;
11436 list_append(list, li);
11437 }
11438
11439 ++list->lv_refcount;
11440 rettv->v_type = VAR_LIST;
11441 rettv->vval.v_list = list;
11442 list = NULL;
11443 }
11444 else
11445 {
11446 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
11447#ifdef USE_CR
11448 /* translate <CR> into <NL> */
11449 if (res != NULL)
11450 {
11451 char_u *s;
11452
11453 for (s = res; *s; ++s)
11454 {
11455 if (*s == CAR)
11456 *s = NL;
11457 }
11458 }
11459#else
11460# ifdef USE_CRNL
11461 /* translate <CR><NL> into <NL> */
11462 if (res != NULL)
11463 {
11464 char_u *s, *d;
11465
11466 d = res;
11467 for (s = res; *s; ++s)
11468 {
11469 if (s[0] == CAR && s[1] == NL)
11470 ++s;
11471 *d++ = *s;
11472 }
11473 *d = NUL;
11474 }
11475# endif
11476#endif
11477 rettv->vval.v_string = res;
11478 res = NULL;
11479 }
11480
11481errret:
11482 if (infile != NULL)
11483 {
11484 mch_remove(infile);
11485 vim_free(infile);
11486 }
11487 if (res != NULL)
11488 vim_free(res);
11489 if (list != NULL)
11490 list_free(list);
11491}
11492
11493/*
11494 * "system()" function
11495 */
11496 static void
11497f_system(typval_T *argvars, typval_T *rettv)
11498{
11499 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11500}
11501
11502/*
11503 * "systemlist()" function
11504 */
11505 static void
11506f_systemlist(typval_T *argvars, typval_T *rettv)
11507{
11508 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11509}
11510
11511/*
11512 * "tabpagebuflist()" function
11513 */
11514 static void
11515f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11516{
11517#ifdef FEAT_WINDOWS
11518 tabpage_T *tp;
11519 win_T *wp = NULL;
11520
11521 if (argvars[0].v_type == VAR_UNKNOWN)
11522 wp = firstwin;
11523 else
11524 {
11525 tp = find_tabpage((int)get_tv_number(&argvars[0]));
11526 if (tp != NULL)
11527 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11528 }
11529 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11530 {
11531 for (; wp != NULL; wp = wp->w_next)
11532 if (list_append_number(rettv->vval.v_list,
11533 wp->w_buffer->b_fnum) == FAIL)
11534 break;
11535 }
11536#endif
11537}
11538
11539
11540/*
11541 * "tabpagenr()" function
11542 */
11543 static void
11544f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11545{
11546 int nr = 1;
11547#ifdef FEAT_WINDOWS
11548 char_u *arg;
11549
11550 if (argvars[0].v_type != VAR_UNKNOWN)
11551 {
11552 arg = get_tv_string_chk(&argvars[0]);
11553 nr = 0;
11554 if (arg != NULL)
11555 {
11556 if (STRCMP(arg, "$") == 0)
11557 nr = tabpage_index(NULL) - 1;
11558 else
11559 EMSG2(_(e_invexpr2), arg);
11560 }
11561 }
11562 else
11563 nr = tabpage_index(curtab);
11564#endif
11565 rettv->vval.v_number = nr;
11566}
11567
11568
11569#ifdef FEAT_WINDOWS
11570static int get_winnr(tabpage_T *tp, typval_T *argvar);
11571
11572/*
11573 * Common code for tabpagewinnr() and winnr().
11574 */
11575 static int
11576get_winnr(tabpage_T *tp, typval_T *argvar)
11577{
11578 win_T *twin;
11579 int nr = 1;
11580 win_T *wp;
11581 char_u *arg;
11582
11583 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11584 if (argvar->v_type != VAR_UNKNOWN)
11585 {
11586 arg = get_tv_string_chk(argvar);
11587 if (arg == NULL)
11588 nr = 0; /* type error; errmsg already given */
11589 else if (STRCMP(arg, "$") == 0)
11590 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11591 else if (STRCMP(arg, "#") == 0)
11592 {
11593 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11594 if (twin == NULL)
11595 nr = 0;
11596 }
11597 else
11598 {
11599 EMSG2(_(e_invexpr2), arg);
11600 nr = 0;
11601 }
11602 }
11603
11604 if (nr > 0)
11605 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11606 wp != twin; wp = wp->w_next)
11607 {
11608 if (wp == NULL)
11609 {
11610 /* didn't find it in this tabpage */
11611 nr = 0;
11612 break;
11613 }
11614 ++nr;
11615 }
11616 return nr;
11617}
11618#endif
11619
11620/*
11621 * "tabpagewinnr()" function
11622 */
11623 static void
11624f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11625{
11626 int nr = 1;
11627#ifdef FEAT_WINDOWS
11628 tabpage_T *tp;
11629
11630 tp = find_tabpage((int)get_tv_number(&argvars[0]));
11631 if (tp == NULL)
11632 nr = 0;
11633 else
11634 nr = get_winnr(tp, &argvars[1]);
11635#endif
11636 rettv->vval.v_number = nr;
11637}
11638
11639
11640/*
11641 * "tagfiles()" function
11642 */
11643 static void
11644f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11645{
11646 char_u *fname;
11647 tagname_T tn;
11648 int first;
11649
11650 if (rettv_list_alloc(rettv) == FAIL)
11651 return;
11652 fname = alloc(MAXPATHL);
11653 if (fname == NULL)
11654 return;
11655
11656 for (first = TRUE; ; first = FALSE)
11657 if (get_tagfname(&tn, first, fname) == FAIL
11658 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11659 break;
11660 tagname_free(&tn);
11661 vim_free(fname);
11662}
11663
11664/*
11665 * "taglist()" function
11666 */
11667 static void
11668f_taglist(typval_T *argvars, typval_T *rettv)
11669{
11670 char_u *tag_pattern;
11671
11672 tag_pattern = get_tv_string(&argvars[0]);
11673
11674 rettv->vval.v_number = FALSE;
11675 if (*tag_pattern == NUL)
11676 return;
11677
11678 if (rettv_list_alloc(rettv) == OK)
11679 (void)get_tags(rettv->vval.v_list, tag_pattern);
11680}
11681
11682/*
11683 * "tempname()" function
11684 */
11685 static void
11686f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11687{
11688 static int x = 'A';
11689
11690 rettv->v_type = VAR_STRING;
11691 rettv->vval.v_string = vim_tempname(x, FALSE);
11692
11693 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11694 * names. Skip 'I' and 'O', they are used for shell redirection. */
11695 do
11696 {
11697 if (x == 'Z')
11698 x = '0';
11699 else if (x == '9')
11700 x = 'A';
11701 else
11702 {
11703#ifdef EBCDIC
11704 if (x == 'I')
11705 x = 'J';
11706 else if (x == 'R')
11707 x = 'S';
11708 else
11709#endif
11710 ++x;
11711 }
11712 } while (x == 'I' || x == 'O');
11713}
11714
11715#ifdef FEAT_FLOAT
11716/*
11717 * "tan()" function
11718 */
11719 static void
11720f_tan(typval_T *argvars, typval_T *rettv)
11721{
11722 float_T f = 0.0;
11723
11724 rettv->v_type = VAR_FLOAT;
11725 if (get_float_arg(argvars, &f) == OK)
11726 rettv->vval.v_float = tan(f);
11727 else
11728 rettv->vval.v_float = 0.0;
11729}
11730
11731/*
11732 * "tanh()" function
11733 */
11734 static void
11735f_tanh(typval_T *argvars, typval_T *rettv)
11736{
11737 float_T f = 0.0;
11738
11739 rettv->v_type = VAR_FLOAT;
11740 if (get_float_arg(argvars, &f) == OK)
11741 rettv->vval.v_float = tanh(f);
11742 else
11743 rettv->vval.v_float = 0.0;
11744}
11745#endif
11746
11747/*
11748 * "test_alloc_fail(id, countdown, repeat)" function
11749 */
11750 static void
11751f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
11752{
11753 if (argvars[0].v_type != VAR_NUMBER
11754 || argvars[0].vval.v_number <= 0
11755 || argvars[1].v_type != VAR_NUMBER
11756 || argvars[1].vval.v_number < 0
11757 || argvars[2].v_type != VAR_NUMBER)
11758 EMSG(_(e_invarg));
11759 else
11760 {
11761 alloc_fail_id = argvars[0].vval.v_number;
11762 if (alloc_fail_id >= aid_last)
11763 EMSG(_(e_invarg));
11764 alloc_fail_countdown = argvars[1].vval.v_number;
11765 alloc_fail_repeat = argvars[2].vval.v_number;
11766 did_outofmem_msg = FALSE;
11767 }
11768}
11769
11770/*
11771 * "test_autochdir()"
11772 */
11773 static void
11774f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11775{
11776#if defined(FEAT_AUTOCHDIR)
11777 test_autochdir = TRUE;
11778#endif
11779}
11780
11781/*
11782 * "test_disable_char_avail({expr})" function
11783 */
11784 static void
11785f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED)
11786{
11787 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]);
11788}
11789
11790/*
11791 * "test_garbagecollect_now()" function
11792 */
11793 static void
11794f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11795{
11796 /* This is dangerous, any Lists and Dicts used internally may be freed
11797 * while still in use. */
11798 garbage_collect(TRUE);
11799}
11800
11801#ifdef FEAT_JOB_CHANNEL
11802 static void
11803f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
11804{
11805 rettv->v_type = VAR_CHANNEL;
11806 rettv->vval.v_channel = NULL;
11807}
11808#endif
11809
11810 static void
11811f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
11812{
11813 rettv->v_type = VAR_DICT;
11814 rettv->vval.v_dict = NULL;
11815}
11816
11817#ifdef FEAT_JOB_CHANNEL
11818 static void
11819f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
11820{
11821 rettv->v_type = VAR_JOB;
11822 rettv->vval.v_job = NULL;
11823}
11824#endif
11825
11826 static void
11827f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
11828{
11829 rettv->v_type = VAR_LIST;
11830 rettv->vval.v_list = NULL;
11831}
11832
11833 static void
11834f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
11835{
11836 rettv->v_type = VAR_PARTIAL;
11837 rettv->vval.v_partial = NULL;
11838}
11839
11840 static void
11841f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
11842{
11843 rettv->v_type = VAR_STRING;
11844 rettv->vval.v_string = NULL;
11845}
11846
11847 static void
11848f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
11849{
11850 time_for_testing = (time_t)get_tv_number(&argvars[0]);
11851}
11852
11853#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
11854/*
11855 * Get a callback from "arg". It can be a Funcref or a function name.
11856 * When "arg" is zero return an empty string.
11857 * Return NULL for an invalid argument.
11858 */
11859 char_u *
11860get_callback(typval_T *arg, partial_T **pp)
11861{
11862 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11863 {
11864 *pp = arg->vval.v_partial;
11865 ++(*pp)->pt_refcount;
11866 return (*pp)->pt_name;
11867 }
11868 *pp = NULL;
11869 if (arg->v_type == VAR_FUNC)
11870 {
11871 func_ref(arg->vval.v_string);
11872 return arg->vval.v_string;
11873 }
11874 if (arg->v_type == VAR_STRING)
11875 return arg->vval.v_string;
11876 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11877 return (char_u *)"";
11878 EMSG(_("E921: Invalid callback argument"));
11879 return NULL;
11880}
11881
11882/*
11883 * Unref/free "callback" and "partial" retured by get_callback().
11884 */
11885 void
11886free_callback(char_u *callback, partial_T *partial)
11887{
11888 if (partial != NULL)
11889 partial_unref(partial);
11890 else if (callback != NULL)
11891 {
11892 func_unref(callback);
11893 vim_free(callback);
11894 }
11895}
11896#endif
11897
11898#ifdef FEAT_TIMERS
11899/*
11900 * "timer_start(time, callback [, options])" function
11901 */
11902 static void
11903f_timer_start(typval_T *argvars, typval_T *rettv)
11904{
11905 long msec = (long)get_tv_number(&argvars[0]);
11906 timer_T *timer;
11907 int repeat = 0;
11908 char_u *callback;
11909 dict_T *dict;
11910
11911 if (check_secure())
11912 return;
11913 if (argvars[2].v_type != VAR_UNKNOWN)
11914 {
11915 if (argvars[2].v_type != VAR_DICT
11916 || (dict = argvars[2].vval.v_dict) == NULL)
11917 {
11918 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
11919 return;
11920 }
11921 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
11922 repeat = get_dict_number(dict, (char_u *)"repeat");
11923 }
11924
11925 timer = create_timer(msec, repeat);
11926 callback = get_callback(&argvars[1], &timer->tr_partial);
11927 if (callback == NULL)
11928 {
11929 stop_timer(timer);
11930 rettv->vval.v_number = -1;
11931 }
11932 else
11933 {
Bram Moolenaar3ab14352016-07-30 22:32:11 +020011934 if (timer->tr_partial == NULL)
11935 timer->tr_callback = vim_strsave(callback);
11936 else
11937 /* pointer into the partial */
11938 timer->tr_callback = callback;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011939 rettv->vval.v_number = timer->tr_id;
11940 }
11941}
11942
11943/*
11944 * "timer_stop(timer)" function
11945 */
11946 static void
11947f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
11948{
11949 timer_T *timer;
11950
11951 if (argvars[0].v_type != VAR_NUMBER)
11952 {
11953 EMSG(_(e_number_exp));
11954 return;
11955 }
11956 timer = find_timer((int)get_tv_number(&argvars[0]));
11957 if (timer != NULL)
11958 stop_timer(timer);
11959}
11960#endif
11961
11962/*
11963 * "tolower(string)" function
11964 */
11965 static void
11966f_tolower(typval_T *argvars, typval_T *rettv)
11967{
11968 char_u *p;
11969
11970 p = vim_strsave(get_tv_string(&argvars[0]));
11971 rettv->v_type = VAR_STRING;
11972 rettv->vval.v_string = p;
11973
11974 if (p != NULL)
11975 while (*p != NUL)
11976 {
11977#ifdef FEAT_MBYTE
11978 int l;
11979
11980 if (enc_utf8)
11981 {
11982 int c, lc;
11983
11984 c = utf_ptr2char(p);
11985 lc = utf_tolower(c);
11986 l = utf_ptr2len(p);
11987 /* TODO: reallocate string when byte count changes. */
11988 if (utf_char2len(lc) == l)
11989 utf_char2bytes(lc, p);
11990 p += l;
11991 }
11992 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
11993 p += l; /* skip multi-byte character */
11994 else
11995#endif
11996 {
11997 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
11998 ++p;
11999 }
12000 }
12001}
12002
12003/*
12004 * "toupper(string)" function
12005 */
12006 static void
12007f_toupper(typval_T *argvars, typval_T *rettv)
12008{
12009 rettv->v_type = VAR_STRING;
12010 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12011}
12012
12013/*
12014 * "tr(string, fromstr, tostr)" function
12015 */
12016 static void
12017f_tr(typval_T *argvars, typval_T *rettv)
12018{
12019 char_u *in_str;
12020 char_u *fromstr;
12021 char_u *tostr;
12022 char_u *p;
12023#ifdef FEAT_MBYTE
12024 int inlen;
12025 int fromlen;
12026 int tolen;
12027 int idx;
12028 char_u *cpstr;
12029 int cplen;
12030 int first = TRUE;
12031#endif
12032 char_u buf[NUMBUFLEN];
12033 char_u buf2[NUMBUFLEN];
12034 garray_T ga;
12035
12036 in_str = get_tv_string(&argvars[0]);
12037 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12038 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12039
12040 /* Default return value: empty string. */
12041 rettv->v_type = VAR_STRING;
12042 rettv->vval.v_string = NULL;
12043 if (fromstr == NULL || tostr == NULL)
12044 return; /* type error; errmsg already given */
12045 ga_init2(&ga, (int)sizeof(char), 80);
12046
12047#ifdef FEAT_MBYTE
12048 if (!has_mbyte)
12049#endif
12050 /* not multi-byte: fromstr and tostr must be the same length */
12051 if (STRLEN(fromstr) != STRLEN(tostr))
12052 {
12053#ifdef FEAT_MBYTE
12054error:
12055#endif
12056 EMSG2(_(e_invarg2), fromstr);
12057 ga_clear(&ga);
12058 return;
12059 }
12060
12061 /* fromstr and tostr have to contain the same number of chars */
12062 while (*in_str != NUL)
12063 {
12064#ifdef FEAT_MBYTE
12065 if (has_mbyte)
12066 {
12067 inlen = (*mb_ptr2len)(in_str);
12068 cpstr = in_str;
12069 cplen = inlen;
12070 idx = 0;
12071 for (p = fromstr; *p != NUL; p += fromlen)
12072 {
12073 fromlen = (*mb_ptr2len)(p);
12074 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12075 {
12076 for (p = tostr; *p != NUL; p += tolen)
12077 {
12078 tolen = (*mb_ptr2len)(p);
12079 if (idx-- == 0)
12080 {
12081 cplen = tolen;
12082 cpstr = p;
12083 break;
12084 }
12085 }
12086 if (*p == NUL) /* tostr is shorter than fromstr */
12087 goto error;
12088 break;
12089 }
12090 ++idx;
12091 }
12092
12093 if (first && cpstr == in_str)
12094 {
12095 /* Check that fromstr and tostr have the same number of
12096 * (multi-byte) characters. Done only once when a character
12097 * of in_str doesn't appear in fromstr. */
12098 first = FALSE;
12099 for (p = tostr; *p != NUL; p += tolen)
12100 {
12101 tolen = (*mb_ptr2len)(p);
12102 --idx;
12103 }
12104 if (idx != 0)
12105 goto error;
12106 }
12107
12108 (void)ga_grow(&ga, cplen);
12109 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12110 ga.ga_len += cplen;
12111
12112 in_str += inlen;
12113 }
12114 else
12115#endif
12116 {
12117 /* When not using multi-byte chars we can do it faster. */
12118 p = vim_strchr(fromstr, *in_str);
12119 if (p != NULL)
12120 ga_append(&ga, tostr[p - fromstr]);
12121 else
12122 ga_append(&ga, *in_str);
12123 ++in_str;
12124 }
12125 }
12126
12127 /* add a terminating NUL */
12128 (void)ga_grow(&ga, 1);
12129 ga_append(&ga, NUL);
12130
12131 rettv->vval.v_string = ga.ga_data;
12132}
12133
12134#ifdef FEAT_FLOAT
12135/*
12136 * "trunc({float})" function
12137 */
12138 static void
12139f_trunc(typval_T *argvars, typval_T *rettv)
12140{
12141 float_T f = 0.0;
12142
12143 rettv->v_type = VAR_FLOAT;
12144 if (get_float_arg(argvars, &f) == OK)
12145 /* trunc() is not in C90, use floor() or ceil() instead. */
12146 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12147 else
12148 rettv->vval.v_float = 0.0;
12149}
12150#endif
12151
12152/*
12153 * "type(expr)" function
12154 */
12155 static void
12156f_type(typval_T *argvars, typval_T *rettv)
12157{
12158 int n = -1;
12159
12160 switch (argvars[0].v_type)
12161 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012162 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12163 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012164 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012165 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12166 case VAR_LIST: n = VAR_TYPE_LIST; break;
12167 case VAR_DICT: n = VAR_TYPE_DICT; break;
12168 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012169 case VAR_SPECIAL:
12170 if (argvars[0].vval.v_number == VVAL_FALSE
12171 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012172 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012173 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012174 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012175 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012176 case VAR_JOB: n = VAR_TYPE_JOB; break;
12177 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012178 case VAR_UNKNOWN:
12179 EMSG2(_(e_intern2), "f_type(UNKNOWN)");
12180 n = -1;
12181 break;
12182 }
12183 rettv->vval.v_number = n;
12184}
12185
12186/*
12187 * "undofile(name)" function
12188 */
12189 static void
12190f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12191{
12192 rettv->v_type = VAR_STRING;
12193#ifdef FEAT_PERSISTENT_UNDO
12194 {
12195 char_u *fname = get_tv_string(&argvars[0]);
12196
12197 if (*fname == NUL)
12198 {
12199 /* If there is no file name there will be no undo file. */
12200 rettv->vval.v_string = NULL;
12201 }
12202 else
12203 {
12204 char_u *ffname = FullName_save(fname, FALSE);
12205
12206 if (ffname != NULL)
12207 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12208 vim_free(ffname);
12209 }
12210 }
12211#else
12212 rettv->vval.v_string = NULL;
12213#endif
12214}
12215
12216/*
12217 * "undotree()" function
12218 */
12219 static void
12220f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12221{
12222 if (rettv_dict_alloc(rettv) == OK)
12223 {
12224 dict_T *dict = rettv->vval.v_dict;
12225 list_T *list;
12226
12227 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12228 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12229 dict_add_nr_str(dict, "save_last",
12230 (long)curbuf->b_u_save_nr_last, NULL);
12231 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12232 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12233 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12234
12235 list = list_alloc();
12236 if (list != NULL)
12237 {
12238 u_eval_tree(curbuf->b_u_oldhead, list);
12239 dict_add_list(dict, "entries", list);
12240 }
12241 }
12242}
12243
12244/*
12245 * "values(dict)" function
12246 */
12247 static void
12248f_values(typval_T *argvars, typval_T *rettv)
12249{
12250 dict_list(argvars, rettv, 1);
12251}
12252
12253/*
12254 * "virtcol(string)" function
12255 */
12256 static void
12257f_virtcol(typval_T *argvars, typval_T *rettv)
12258{
12259 colnr_T vcol = 0;
12260 pos_T *fp;
12261 int fnum = curbuf->b_fnum;
12262
12263 fp = var2fpos(&argvars[0], FALSE, &fnum);
12264 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12265 && fnum == curbuf->b_fnum)
12266 {
12267 getvvcol(curwin, fp, NULL, NULL, &vcol);
12268 ++vcol;
12269 }
12270
12271 rettv->vval.v_number = vcol;
12272}
12273
12274/*
12275 * "visualmode()" function
12276 */
12277 static void
12278f_visualmode(typval_T *argvars, typval_T *rettv)
12279{
12280 char_u str[2];
12281
12282 rettv->v_type = VAR_STRING;
12283 str[0] = curbuf->b_visual_mode_eval;
12284 str[1] = NUL;
12285 rettv->vval.v_string = vim_strsave(str);
12286
12287 /* A non-zero number or non-empty string argument: reset mode. */
12288 if (non_zero_arg(&argvars[0]))
12289 curbuf->b_visual_mode_eval = NUL;
12290}
12291
12292/*
12293 * "wildmenumode()" function
12294 */
12295 static void
12296f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12297{
12298#ifdef FEAT_WILDMENU
12299 if (wild_menu_showing)
12300 rettv->vval.v_number = 1;
12301#endif
12302}
12303
12304/*
12305 * "winbufnr(nr)" function
12306 */
12307 static void
12308f_winbufnr(typval_T *argvars, typval_T *rettv)
12309{
12310 win_T *wp;
12311
12312 wp = find_win_by_nr(&argvars[0], NULL);
12313 if (wp == NULL)
12314 rettv->vval.v_number = -1;
12315 else
12316 rettv->vval.v_number = wp->w_buffer->b_fnum;
12317}
12318
12319/*
12320 * "wincol()" function
12321 */
12322 static void
12323f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12324{
12325 validate_cursor();
12326 rettv->vval.v_number = curwin->w_wcol + 1;
12327}
12328
12329/*
12330 * "winheight(nr)" function
12331 */
12332 static void
12333f_winheight(typval_T *argvars, typval_T *rettv)
12334{
12335 win_T *wp;
12336
12337 wp = find_win_by_nr(&argvars[0], NULL);
12338 if (wp == NULL)
12339 rettv->vval.v_number = -1;
12340 else
12341 rettv->vval.v_number = wp->w_height;
12342}
12343
12344/*
12345 * "winline()" function
12346 */
12347 static void
12348f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12349{
12350 validate_cursor();
12351 rettv->vval.v_number = curwin->w_wrow + 1;
12352}
12353
12354/*
12355 * "winnr()" function
12356 */
12357 static void
12358f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12359{
12360 int nr = 1;
12361
12362#ifdef FEAT_WINDOWS
12363 nr = get_winnr(curtab, &argvars[0]);
12364#endif
12365 rettv->vval.v_number = nr;
12366}
12367
12368/*
12369 * "winrestcmd()" function
12370 */
12371 static void
12372f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12373{
12374#ifdef FEAT_WINDOWS
12375 win_T *wp;
12376 int winnr = 1;
12377 garray_T ga;
12378 char_u buf[50];
12379
12380 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012381 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382 {
12383 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12384 ga_concat(&ga, buf);
12385 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12386 ga_concat(&ga, buf);
12387 ++winnr;
12388 }
12389 ga_append(&ga, NUL);
12390
12391 rettv->vval.v_string = ga.ga_data;
12392#else
12393 rettv->vval.v_string = NULL;
12394#endif
12395 rettv->v_type = VAR_STRING;
12396}
12397
12398/*
12399 * "winrestview()" function
12400 */
12401 static void
12402f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12403{
12404 dict_T *dict;
12405
12406 if (argvars[0].v_type != VAR_DICT
12407 || (dict = argvars[0].vval.v_dict) == NULL)
12408 EMSG(_(e_invarg));
12409 else
12410 {
12411 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
12412 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
12413 if (dict_find(dict, (char_u *)"col", -1) != NULL)
12414 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
12415#ifdef FEAT_VIRTUALEDIT
12416 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
12417 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
12418#endif
12419 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12420 {
12421 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
12422 curwin->w_set_curswant = FALSE;
12423 }
12424
12425 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
12426 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
12427#ifdef FEAT_DIFF
12428 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
12429 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
12430#endif
12431 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
12432 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
12433 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
12434 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
12435
12436 check_cursor();
12437 win_new_height(curwin, curwin->w_height);
12438# ifdef FEAT_WINDOWS
12439 win_new_width(curwin, W_WIDTH(curwin));
12440# endif
12441 changed_window_setting();
12442
12443 if (curwin->w_topline <= 0)
12444 curwin->w_topline = 1;
12445 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12446 curwin->w_topline = curbuf->b_ml.ml_line_count;
12447#ifdef FEAT_DIFF
12448 check_topfill(curwin, TRUE);
12449#endif
12450 }
12451}
12452
12453/*
12454 * "winsaveview()" function
12455 */
12456 static void
12457f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12458{
12459 dict_T *dict;
12460
12461 if (rettv_dict_alloc(rettv) == FAIL)
12462 return;
12463 dict = rettv->vval.v_dict;
12464
12465 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
12466 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
12467#ifdef FEAT_VIRTUALEDIT
12468 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
12469#endif
12470 update_curswant();
12471 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
12472
12473 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
12474#ifdef FEAT_DIFF
12475 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
12476#endif
12477 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
12478 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
12479}
12480
12481/*
12482 * "winwidth(nr)" function
12483 */
12484 static void
12485f_winwidth(typval_T *argvars, typval_T *rettv)
12486{
12487 win_T *wp;
12488
12489 wp = find_win_by_nr(&argvars[0], NULL);
12490 if (wp == NULL)
12491 rettv->vval.v_number = -1;
12492 else
12493#ifdef FEAT_WINDOWS
12494 rettv->vval.v_number = wp->w_width;
12495#else
12496 rettv->vval.v_number = Columns;
12497#endif
12498}
12499
12500/*
12501 * "wordcount()" function
12502 */
12503 static void
12504f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12505{
12506 if (rettv_dict_alloc(rettv) == FAIL)
12507 return;
12508 cursor_pos_info(rettv->vval.v_dict);
12509}
12510
12511/*
12512 * "writefile()" function
12513 */
12514 static void
12515f_writefile(typval_T *argvars, typval_T *rettv)
12516{
12517 int binary = FALSE;
12518 int append = FALSE;
12519 char_u *fname;
12520 FILE *fd;
12521 int ret = 0;
12522
12523 if (check_restricted() || check_secure())
12524 return;
12525
12526 if (argvars[0].v_type != VAR_LIST)
12527 {
12528 EMSG2(_(e_listarg), "writefile()");
12529 return;
12530 }
12531 if (argvars[0].vval.v_list == NULL)
12532 return;
12533
12534 if (argvars[2].v_type != VAR_UNKNOWN)
12535 {
12536 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL)
12537 binary = TRUE;
12538 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL)
12539 append = TRUE;
12540 }
12541
12542 /* Always open the file in binary mode, library functions have a mind of
12543 * their own about CR-LF conversion. */
12544 fname = get_tv_string(&argvars[1]);
12545 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12546 append ? APPENDBIN : WRITEBIN)) == NULL)
12547 {
12548 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
12549 ret = -1;
12550 }
12551 else
12552 {
12553 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL)
12554 ret = -1;
12555 fclose(fd);
12556 }
12557
12558 rettv->vval.v_number = ret;
12559}
12560
12561/*
12562 * "xor(expr, expr)" function
12563 */
12564 static void
12565f_xor(typval_T *argvars, typval_T *rettv)
12566{
12567 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
12568 ^ get_tv_number_chk(&argvars[1], NULL);
12569}
12570
12571
12572#endif /* FEAT_EVAL */