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