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