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