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