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