blob: 00956612f8d9d2584c4f52470c1edfd88166ed57 [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 Moolenaar73dad1e2016-07-17 22:13:49 +02004250
4251 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4252 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4253 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004254 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255
4256 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4257
4258 for (i = 0; i < xpc.xp_numfiles; i++)
4259 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4260 }
4261 vim_free(pat);
4262 ExpandCleanup(&xpc);
4263}
4264#endif
4265
4266/*
4267 * "getcwd()" function
4268 */
4269 static void
4270f_getcwd(typval_T *argvars, typval_T *rettv)
4271{
4272 win_T *wp = NULL;
4273 char_u *cwd;
4274
4275 rettv->v_type = VAR_STRING;
4276 rettv->vval.v_string = NULL;
4277
4278 wp = find_tabwin(&argvars[0], &argvars[1]);
4279 if (wp != NULL)
4280 {
4281 if (wp->w_localdir != NULL)
4282 rettv->vval.v_string = vim_strsave(wp->w_localdir);
4283 else if (globaldir != NULL)
4284 rettv->vval.v_string = vim_strsave(globaldir);
4285 else
4286 {
4287 cwd = alloc(MAXPATHL);
4288 if (cwd != NULL)
4289 {
4290 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4291 rettv->vval.v_string = vim_strsave(cwd);
4292 vim_free(cwd);
4293 }
4294 }
4295#ifdef BACKSLASH_IN_FILENAME
4296 if (rettv->vval.v_string != NULL)
4297 slash_adjust(rettv->vval.v_string);
4298#endif
4299 }
4300}
4301
4302/*
4303 * "getfontname()" function
4304 */
4305 static void
4306f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4307{
4308 rettv->v_type = VAR_STRING;
4309 rettv->vval.v_string = NULL;
4310#ifdef FEAT_GUI
4311 if (gui.in_use)
4312 {
4313 GuiFont font;
4314 char_u *name = NULL;
4315
4316 if (argvars[0].v_type == VAR_UNKNOWN)
4317 {
4318 /* Get the "Normal" font. Either the name saved by
4319 * hl_set_font_name() or from the font ID. */
4320 font = gui.norm_font;
4321 name = hl_get_font_name();
4322 }
4323 else
4324 {
4325 name = get_tv_string(&argvars[0]);
4326 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4327 return;
4328 font = gui_mch_get_font(name, FALSE);
4329 if (font == NOFONT)
4330 return; /* Invalid font name, return empty string. */
4331 }
4332 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4333 if (argvars[0].v_type != VAR_UNKNOWN)
4334 gui_mch_free_font(font);
4335 }
4336#endif
4337}
4338
4339/*
4340 * "getfperm({fname})" function
4341 */
4342 static void
4343f_getfperm(typval_T *argvars, typval_T *rettv)
4344{
4345 char_u *fname;
4346 stat_T st;
4347 char_u *perm = NULL;
4348 char_u flags[] = "rwx";
4349 int i;
4350
4351 fname = get_tv_string(&argvars[0]);
4352
4353 rettv->v_type = VAR_STRING;
4354 if (mch_stat((char *)fname, &st) >= 0)
4355 {
4356 perm = vim_strsave((char_u *)"---------");
4357 if (perm != NULL)
4358 {
4359 for (i = 0; i < 9; i++)
4360 {
4361 if (st.st_mode & (1 << (8 - i)))
4362 perm[i] = flags[i % 3];
4363 }
4364 }
4365 }
4366 rettv->vval.v_string = perm;
4367}
4368
4369/*
4370 * "getfsize({fname})" function
4371 */
4372 static void
4373f_getfsize(typval_T *argvars, typval_T *rettv)
4374{
4375 char_u *fname;
4376 stat_T st;
4377
4378 fname = get_tv_string(&argvars[0]);
4379
4380 rettv->v_type = VAR_NUMBER;
4381
4382 if (mch_stat((char *)fname, &st) >= 0)
4383 {
4384 if (mch_isdir(fname))
4385 rettv->vval.v_number = 0;
4386 else
4387 {
4388 rettv->vval.v_number = (varnumber_T)st.st_size;
4389
4390 /* non-perfect check for overflow */
4391 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4392 rettv->vval.v_number = -2;
4393 }
4394 }
4395 else
4396 rettv->vval.v_number = -1;
4397}
4398
4399/*
4400 * "getftime({fname})" function
4401 */
4402 static void
4403f_getftime(typval_T *argvars, typval_T *rettv)
4404{
4405 char_u *fname;
4406 stat_T st;
4407
4408 fname = get_tv_string(&argvars[0]);
4409
4410 if (mch_stat((char *)fname, &st) >= 0)
4411 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4412 else
4413 rettv->vval.v_number = -1;
4414}
4415
4416/*
4417 * "getftype({fname})" function
4418 */
4419 static void
4420f_getftype(typval_T *argvars, typval_T *rettv)
4421{
4422 char_u *fname;
4423 stat_T st;
4424 char_u *type = NULL;
4425 char *t;
4426
4427 fname = get_tv_string(&argvars[0]);
4428
4429 rettv->v_type = VAR_STRING;
4430 if (mch_lstat((char *)fname, &st) >= 0)
4431 {
4432#ifdef S_ISREG
4433 if (S_ISREG(st.st_mode))
4434 t = "file";
4435 else if (S_ISDIR(st.st_mode))
4436 t = "dir";
4437# ifdef S_ISLNK
4438 else if (S_ISLNK(st.st_mode))
4439 t = "link";
4440# endif
4441# ifdef S_ISBLK
4442 else if (S_ISBLK(st.st_mode))
4443 t = "bdev";
4444# endif
4445# ifdef S_ISCHR
4446 else if (S_ISCHR(st.st_mode))
4447 t = "cdev";
4448# endif
4449# ifdef S_ISFIFO
4450 else if (S_ISFIFO(st.st_mode))
4451 t = "fifo";
4452# endif
4453# ifdef S_ISSOCK
4454 else if (S_ISSOCK(st.st_mode))
4455 t = "fifo";
4456# endif
4457 else
4458 t = "other";
4459#else
4460# ifdef S_IFMT
4461 switch (st.st_mode & S_IFMT)
4462 {
4463 case S_IFREG: t = "file"; break;
4464 case S_IFDIR: t = "dir"; break;
4465# ifdef S_IFLNK
4466 case S_IFLNK: t = "link"; break;
4467# endif
4468# ifdef S_IFBLK
4469 case S_IFBLK: t = "bdev"; break;
4470# endif
4471# ifdef S_IFCHR
4472 case S_IFCHR: t = "cdev"; break;
4473# endif
4474# ifdef S_IFIFO
4475 case S_IFIFO: t = "fifo"; break;
4476# endif
4477# ifdef S_IFSOCK
4478 case S_IFSOCK: t = "socket"; break;
4479# endif
4480 default: t = "other";
4481 }
4482# else
4483 if (mch_isdir(fname))
4484 t = "dir";
4485 else
4486 t = "file";
4487# endif
4488#endif
4489 type = vim_strsave((char_u *)t);
4490 }
4491 rettv->vval.v_string = type;
4492}
4493
4494/*
4495 * "getline(lnum, [end])" function
4496 */
4497 static void
4498f_getline(typval_T *argvars, typval_T *rettv)
4499{
4500 linenr_T lnum;
4501 linenr_T end;
4502 int retlist;
4503
4504 lnum = get_tv_lnum(argvars);
4505 if (argvars[1].v_type == VAR_UNKNOWN)
4506 {
4507 end = 0;
4508 retlist = FALSE;
4509 }
4510 else
4511 {
4512 end = get_tv_lnum(&argvars[1]);
4513 retlist = TRUE;
4514 }
4515
4516 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4517}
4518
4519/*
4520 * "getmatches()" function
4521 */
4522 static void
4523f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4524{
4525#ifdef FEAT_SEARCH_EXTRA
4526 dict_T *dict;
4527 matchitem_T *cur = curwin->w_match_head;
4528 int i;
4529
4530 if (rettv_list_alloc(rettv) == OK)
4531 {
4532 while (cur != NULL)
4533 {
4534 dict = dict_alloc();
4535 if (dict == NULL)
4536 return;
4537 if (cur->match.regprog == NULL)
4538 {
4539 /* match added with matchaddpos() */
4540 for (i = 0; i < MAXPOSMATCH; ++i)
4541 {
4542 llpos_T *llpos;
4543 char buf[6];
4544 list_T *l;
4545
4546 llpos = &cur->pos.pos[i];
4547 if (llpos->lnum == 0)
4548 break;
4549 l = list_alloc();
4550 if (l == NULL)
4551 break;
4552 list_append_number(l, (varnumber_T)llpos->lnum);
4553 if (llpos->col > 0)
4554 {
4555 list_append_number(l, (varnumber_T)llpos->col);
4556 list_append_number(l, (varnumber_T)llpos->len);
4557 }
4558 sprintf(buf, "pos%d", i + 1);
4559 dict_add_list(dict, buf, l);
4560 }
4561 }
4562 else
4563 {
4564 dict_add_nr_str(dict, "pattern", 0L, cur->pattern);
4565 }
4566 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
4567 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
4568 dict_add_nr_str(dict, "id", (long)cur->id, NULL);
4569# if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE)
4570 if (cur->conceal_char)
4571 {
4572 char_u buf[MB_MAXBYTES + 1];
4573
4574 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
4575 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
4576 }
4577# endif
4578 list_append_dict(rettv->vval.v_list, dict);
4579 cur = cur->next;
4580 }
4581 }
4582#endif
4583}
4584
4585/*
4586 * "getpid()" function
4587 */
4588 static void
4589f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4590{
4591 rettv->vval.v_number = mch_get_pid();
4592}
4593
4594 static void
4595getpos_both(
4596 typval_T *argvars,
4597 typval_T *rettv,
4598 int getcurpos)
4599{
4600 pos_T *fp;
4601 list_T *l;
4602 int fnum = -1;
4603
4604 if (rettv_list_alloc(rettv) == OK)
4605 {
4606 l = rettv->vval.v_list;
4607 if (getcurpos)
4608 fp = &curwin->w_cursor;
4609 else
4610 fp = var2fpos(&argvars[0], TRUE, &fnum);
4611 if (fnum != -1)
4612 list_append_number(l, (varnumber_T)fnum);
4613 else
4614 list_append_number(l, (varnumber_T)0);
4615 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4616 : (varnumber_T)0);
4617 list_append_number(l, (fp != NULL)
4618 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4619 : (varnumber_T)0);
4620 list_append_number(l,
4621#ifdef FEAT_VIRTUALEDIT
4622 (fp != NULL) ? (varnumber_T)fp->coladd :
4623#endif
4624 (varnumber_T)0);
4625 if (getcurpos)
4626 {
4627 update_curswant();
4628 list_append_number(l, curwin->w_curswant == MAXCOL ?
4629 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
4630 }
4631 }
4632 else
4633 rettv->vval.v_number = FALSE;
4634}
4635
4636
4637/*
4638 * "getcurpos()" function
4639 */
4640 static void
4641f_getcurpos(typval_T *argvars, typval_T *rettv)
4642{
4643 getpos_both(argvars, rettv, TRUE);
4644}
4645
4646/*
4647 * "getpos(string)" function
4648 */
4649 static void
4650f_getpos(typval_T *argvars, typval_T *rettv)
4651{
4652 getpos_both(argvars, rettv, FALSE);
4653}
4654
4655/*
4656 * "getqflist()" and "getloclist()" functions
4657 */
4658 static void
4659f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4660{
4661#ifdef FEAT_QUICKFIX
4662 win_T *wp;
4663#endif
4664
4665#ifdef FEAT_QUICKFIX
4666 if (rettv_list_alloc(rettv) == OK)
4667 {
4668 wp = NULL;
4669 if (argvars[0].v_type != VAR_UNKNOWN) /* getloclist() */
4670 {
4671 wp = find_win_by_nr(&argvars[0], NULL);
4672 if (wp == NULL)
4673 return;
4674 }
4675
4676 (void)get_errorlist(wp, rettv->vval.v_list);
4677 }
4678#endif
4679}
4680
4681/*
4682 * "getreg()" function
4683 */
4684 static void
4685f_getreg(typval_T *argvars, typval_T *rettv)
4686{
4687 char_u *strregname;
4688 int regname;
4689 int arg2 = FALSE;
4690 int return_list = FALSE;
4691 int error = FALSE;
4692
4693 if (argvars[0].v_type != VAR_UNKNOWN)
4694 {
4695 strregname = get_tv_string_chk(&argvars[0]);
4696 error = strregname == NULL;
4697 if (argvars[1].v_type != VAR_UNKNOWN)
4698 {
4699 arg2 = (int)get_tv_number_chk(&argvars[1], &error);
4700 if (!error && argvars[2].v_type != VAR_UNKNOWN)
4701 return_list = (int)get_tv_number_chk(&argvars[2], &error);
4702 }
4703 }
4704 else
4705 strregname = get_vim_var_str(VV_REG);
4706
4707 if (error)
4708 return;
4709
4710 regname = (strregname == NULL ? '"' : *strregname);
4711 if (regname == 0)
4712 regname = '"';
4713
4714 if (return_list)
4715 {
4716 rettv->v_type = VAR_LIST;
4717 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4718 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4719 if (rettv->vval.v_list == NULL)
4720 (void)rettv_list_alloc(rettv);
4721 else
4722 ++rettv->vval.v_list->lv_refcount;
4723 }
4724 else
4725 {
4726 rettv->v_type = VAR_STRING;
4727 rettv->vval.v_string = get_reg_contents(regname,
4728 arg2 ? GREG_EXPR_SRC : 0);
4729 }
4730}
4731
4732/*
4733 * "getregtype()" function
4734 */
4735 static void
4736f_getregtype(typval_T *argvars, typval_T *rettv)
4737{
4738 char_u *strregname;
4739 int regname;
4740 char_u buf[NUMBUFLEN + 2];
4741 long reglen = 0;
4742
4743 if (argvars[0].v_type != VAR_UNKNOWN)
4744 {
4745 strregname = get_tv_string_chk(&argvars[0]);
4746 if (strregname == NULL) /* type error; errmsg already given */
4747 {
4748 rettv->v_type = VAR_STRING;
4749 rettv->vval.v_string = NULL;
4750 return;
4751 }
4752 }
4753 else
4754 /* Default to v:register */
4755 strregname = get_vim_var_str(VV_REG);
4756
4757 regname = (strregname == NULL ? '"' : *strregname);
4758 if (regname == 0)
4759 regname = '"';
4760
4761 buf[0] = NUL;
4762 buf[1] = NUL;
4763 switch (get_reg_type(regname, &reglen))
4764 {
4765 case MLINE: buf[0] = 'V'; break;
4766 case MCHAR: buf[0] = 'v'; break;
4767 case MBLOCK:
4768 buf[0] = Ctrl_V;
4769 sprintf((char *)buf + 1, "%ld", reglen + 1);
4770 break;
4771 }
4772 rettv->v_type = VAR_STRING;
4773 rettv->vval.v_string = vim_strsave(buf);
4774}
4775
4776/*
4777 * "gettabvar()" function
4778 */
4779 static void
4780f_gettabvar(typval_T *argvars, typval_T *rettv)
4781{
4782 win_T *oldcurwin;
4783 tabpage_T *tp, *oldtabpage;
4784 dictitem_T *v;
4785 char_u *varname;
4786 int done = FALSE;
4787
4788 rettv->v_type = VAR_STRING;
4789 rettv->vval.v_string = NULL;
4790
4791 varname = get_tv_string_chk(&argvars[1]);
4792 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
4793 if (tp != NULL && varname != NULL)
4794 {
4795 /* Set tp to be our tabpage, temporarily. Also set the window to the
4796 * first window in the tabpage, otherwise the window is not valid. */
4797 if (switch_win(&oldcurwin, &oldtabpage,
4798 tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE)
4799 == OK)
4800 {
4801 /* look up the variable */
4802 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
4803 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
4804 if (v != NULL)
4805 {
4806 copy_tv(&v->di_tv, rettv);
4807 done = TRUE;
4808 }
4809 }
4810
4811 /* restore previous notion of curwin */
4812 restore_win(oldcurwin, oldtabpage, TRUE);
4813 }
4814
4815 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4816 copy_tv(&argvars[2], rettv);
4817}
4818
4819/*
4820 * "gettabwinvar()" function
4821 */
4822 static void
4823f_gettabwinvar(typval_T *argvars, typval_T *rettv)
4824{
4825 getwinvar(argvars, rettv, 1);
4826}
4827
4828/*
4829 * "getwinposx()" function
4830 */
4831 static void
4832f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
4833{
4834 rettv->vval.v_number = -1;
4835#ifdef FEAT_GUI
4836 if (gui.in_use)
4837 {
4838 int x, y;
4839
4840 if (gui_mch_get_winpos(&x, &y) == OK)
4841 rettv->vval.v_number = x;
4842 }
4843#endif
4844}
4845
4846/*
4847 * "win_findbuf()" function
4848 */
4849 static void
4850f_win_findbuf(typval_T *argvars, typval_T *rettv)
4851{
4852 if (rettv_list_alloc(rettv) != FAIL)
4853 win_findbuf(argvars, rettv->vval.v_list);
4854}
4855
4856/*
4857 * "win_getid()" function
4858 */
4859 static void
4860f_win_getid(typval_T *argvars, typval_T *rettv)
4861{
4862 rettv->vval.v_number = win_getid(argvars);
4863}
4864
4865/*
4866 * "win_gotoid()" function
4867 */
4868 static void
4869f_win_gotoid(typval_T *argvars, typval_T *rettv)
4870{
4871 rettv->vval.v_number = win_gotoid(argvars);
4872}
4873
4874/*
4875 * "win_id2tabwin()" function
4876 */
4877 static void
4878f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
4879{
4880 if (rettv_list_alloc(rettv) != FAIL)
4881 win_id2tabwin(argvars, rettv->vval.v_list);
4882}
4883
4884/*
4885 * "win_id2win()" function
4886 */
4887 static void
4888f_win_id2win(typval_T *argvars, typval_T *rettv)
4889{
4890 rettv->vval.v_number = win_id2win(argvars);
4891}
4892
4893/*
4894 * "getwinposy()" function
4895 */
4896 static void
4897f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
4898{
4899 rettv->vval.v_number = -1;
4900#ifdef FEAT_GUI
4901 if (gui.in_use)
4902 {
4903 int x, y;
4904
4905 if (gui_mch_get_winpos(&x, &y) == OK)
4906 rettv->vval.v_number = y;
4907 }
4908#endif
4909}
4910
4911/*
4912 * "getwinvar()" function
4913 */
4914 static void
4915f_getwinvar(typval_T *argvars, typval_T *rettv)
4916{
4917 getwinvar(argvars, rettv, 0);
4918}
4919
4920/*
4921 * "glob()" function
4922 */
4923 static void
4924f_glob(typval_T *argvars, typval_T *rettv)
4925{
4926 int options = WILD_SILENT|WILD_USE_NL;
4927 expand_T xpc;
4928 int error = FALSE;
4929
4930 /* When the optional second argument is non-zero, don't remove matches
4931 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
4932 rettv->v_type = VAR_STRING;
4933 if (argvars[1].v_type != VAR_UNKNOWN)
4934 {
4935 if (get_tv_number_chk(&argvars[1], &error))
4936 options |= WILD_KEEP_ALL;
4937 if (argvars[2].v_type != VAR_UNKNOWN)
4938 {
4939 if (get_tv_number_chk(&argvars[2], &error))
4940 {
4941 rettv->v_type = VAR_LIST;
4942 rettv->vval.v_list = NULL;
4943 }
4944 if (argvars[3].v_type != VAR_UNKNOWN
4945 && get_tv_number_chk(&argvars[3], &error))
4946 options |= WILD_ALLLINKS;
4947 }
4948 }
4949 if (!error)
4950 {
4951 ExpandInit(&xpc);
4952 xpc.xp_context = EXPAND_FILES;
4953 if (p_wic)
4954 options += WILD_ICASE;
4955 if (rettv->v_type == VAR_STRING)
4956 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]),
4957 NULL, options, WILD_ALL);
4958 else if (rettv_list_alloc(rettv) != FAIL)
4959 {
4960 int i;
4961
4962 ExpandOne(&xpc, get_tv_string(&argvars[0]),
4963 NULL, options, WILD_ALL_KEEP);
4964 for (i = 0; i < xpc.xp_numfiles; i++)
4965 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4966
4967 ExpandCleanup(&xpc);
4968 }
4969 }
4970 else
4971 rettv->vval.v_string = NULL;
4972}
4973
4974/*
4975 * "globpath()" function
4976 */
4977 static void
4978f_globpath(typval_T *argvars, typval_T *rettv)
4979{
4980 int flags = 0;
4981 char_u buf1[NUMBUFLEN];
4982 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1);
4983 int error = FALSE;
4984 garray_T ga;
4985 int i;
4986
4987 /* When the optional second argument is non-zero, don't remove matches
4988 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
4989 rettv->v_type = VAR_STRING;
4990 if (argvars[2].v_type != VAR_UNKNOWN)
4991 {
4992 if (get_tv_number_chk(&argvars[2], &error))
4993 flags |= WILD_KEEP_ALL;
4994 if (argvars[3].v_type != VAR_UNKNOWN)
4995 {
4996 if (get_tv_number_chk(&argvars[3], &error))
4997 {
4998 rettv->v_type = VAR_LIST;
4999 rettv->vval.v_list = NULL;
5000 }
5001 if (argvars[4].v_type != VAR_UNKNOWN
5002 && get_tv_number_chk(&argvars[4], &error))
5003 flags |= WILD_ALLLINKS;
5004 }
5005 }
5006 if (file != NULL && !error)
5007 {
5008 ga_init2(&ga, (int)sizeof(char_u *), 10);
5009 globpath(get_tv_string(&argvars[0]), file, &ga, flags);
5010 if (rettv->v_type == VAR_STRING)
5011 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5012 else if (rettv_list_alloc(rettv) != FAIL)
5013 for (i = 0; i < ga.ga_len; ++i)
5014 list_append_string(rettv->vval.v_list,
5015 ((char_u **)(ga.ga_data))[i], -1);
5016 ga_clear_strings(&ga);
5017 }
5018 else
5019 rettv->vval.v_string = NULL;
5020}
5021
5022/*
5023 * "glob2regpat()" function
5024 */
5025 static void
5026f_glob2regpat(typval_T *argvars, typval_T *rettv)
5027{
5028 char_u *pat = get_tv_string_chk(&argvars[0]);
5029
5030 rettv->v_type = VAR_STRING;
5031 rettv->vval.v_string = (pat == NULL)
5032 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5033}
5034
5035/* for VIM_VERSION_ defines */
5036#include "version.h"
5037
5038/*
5039 * "has()" function
5040 */
5041 static void
5042f_has(typval_T *argvars, typval_T *rettv)
5043{
5044 int i;
5045 char_u *name;
5046 int n = FALSE;
5047 static char *(has_list[]) =
5048 {
5049#ifdef AMIGA
5050 "amiga",
5051# ifdef FEAT_ARP
5052 "arp",
5053# endif
5054#endif
5055#ifdef __BEOS__
5056 "beos",
5057#endif
5058#ifdef MACOS
5059 "mac",
5060#endif
5061#if defined(MACOS_X_UNIX)
5062 "macunix", /* built with 'darwin' enabled */
5063#endif
5064#if defined(__APPLE__) && __APPLE__ == 1
5065 "osx", /* built with or without 'darwin' enabled */
5066#endif
5067#ifdef __QNX__
5068 "qnx",
5069#endif
5070#ifdef UNIX
5071 "unix",
5072#endif
5073#ifdef VMS
5074 "vms",
5075#endif
5076#ifdef WIN32
5077 "win32",
5078#endif
5079#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5080 "win32unix",
5081#endif
5082#if defined(WIN64) || defined(_WIN64)
5083 "win64",
5084#endif
5085#ifdef EBCDIC
5086 "ebcdic",
5087#endif
5088#ifndef CASE_INSENSITIVE_FILENAME
5089 "fname_case",
5090#endif
5091#ifdef HAVE_ACL
5092 "acl",
5093#endif
5094#ifdef FEAT_ARABIC
5095 "arabic",
5096#endif
5097#ifdef FEAT_AUTOCMD
5098 "autocmd",
5099#endif
5100#ifdef FEAT_BEVAL
5101 "balloon_eval",
5102# ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */
5103 "balloon_multiline",
5104# endif
5105#endif
5106#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5107 "builtin_terms",
5108# ifdef ALL_BUILTIN_TCAPS
5109 "all_builtin_terms",
5110# endif
5111#endif
5112#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
5113 || defined(FEAT_GUI_W32) \
5114 || defined(FEAT_GUI_MOTIF))
5115 "browsefilter",
5116#endif
5117#ifdef FEAT_BYTEOFF
5118 "byte_offset",
5119#endif
5120#ifdef FEAT_JOB_CHANNEL
5121 "channel",
5122#endif
5123#ifdef FEAT_CINDENT
5124 "cindent",
5125#endif
5126#ifdef FEAT_CLIENTSERVER
5127 "clientserver",
5128#endif
5129#ifdef FEAT_CLIPBOARD
5130 "clipboard",
5131#endif
5132#ifdef FEAT_CMDL_COMPL
5133 "cmdline_compl",
5134#endif
5135#ifdef FEAT_CMDHIST
5136 "cmdline_hist",
5137#endif
5138#ifdef FEAT_COMMENTS
5139 "comments",
5140#endif
5141#ifdef FEAT_CONCEAL
5142 "conceal",
5143#endif
5144#ifdef FEAT_CRYPT
5145 "cryptv",
5146 "crypt-blowfish",
5147 "crypt-blowfish2",
5148#endif
5149#ifdef FEAT_CSCOPE
5150 "cscope",
5151#endif
5152#ifdef FEAT_CURSORBIND
5153 "cursorbind",
5154#endif
5155#ifdef CURSOR_SHAPE
5156 "cursorshape",
5157#endif
5158#ifdef DEBUG
5159 "debug",
5160#endif
5161#ifdef FEAT_CON_DIALOG
5162 "dialog_con",
5163#endif
5164#ifdef FEAT_GUI_DIALOG
5165 "dialog_gui",
5166#endif
5167#ifdef FEAT_DIFF
5168 "diff",
5169#endif
5170#ifdef FEAT_DIGRAPHS
5171 "digraphs",
5172#endif
5173#ifdef FEAT_DIRECTX
5174 "directx",
5175#endif
5176#ifdef FEAT_DND
5177 "dnd",
5178#endif
5179#ifdef FEAT_EMACS_TAGS
5180 "emacs_tags",
5181#endif
5182 "eval", /* always present, of course! */
5183 "ex_extra", /* graduated feature */
5184#ifdef FEAT_SEARCH_EXTRA
5185 "extra_search",
5186#endif
5187#ifdef FEAT_FKMAP
5188 "farsi",
5189#endif
5190#ifdef FEAT_SEARCHPATH
5191 "file_in_path",
5192#endif
5193#ifdef FEAT_FILTERPIPE
5194 "filterpipe",
5195#endif
5196#ifdef FEAT_FIND_ID
5197 "find_in_path",
5198#endif
5199#ifdef FEAT_FLOAT
5200 "float",
5201#endif
5202#ifdef FEAT_FOLDING
5203 "folding",
5204#endif
5205#ifdef FEAT_FOOTER
5206 "footer",
5207#endif
5208#if !defined(USE_SYSTEM) && defined(UNIX)
5209 "fork",
5210#endif
5211#ifdef FEAT_GETTEXT
5212 "gettext",
5213#endif
5214#ifdef FEAT_GUI
5215 "gui",
5216#endif
5217#ifdef FEAT_GUI_ATHENA
5218# ifdef FEAT_GUI_NEXTAW
5219 "gui_neXtaw",
5220# else
5221 "gui_athena",
5222# endif
5223#endif
5224#ifdef FEAT_GUI_GTK
5225 "gui_gtk",
5226# ifdef USE_GTK3
5227 "gui_gtk3",
5228# else
5229 "gui_gtk2",
5230# endif
5231#endif
5232#ifdef FEAT_GUI_GNOME
5233 "gui_gnome",
5234#endif
5235#ifdef FEAT_GUI_MAC
5236 "gui_mac",
5237#endif
5238#ifdef FEAT_GUI_MOTIF
5239 "gui_motif",
5240#endif
5241#ifdef FEAT_GUI_PHOTON
5242 "gui_photon",
5243#endif
5244#ifdef FEAT_GUI_W32
5245 "gui_win32",
5246#endif
5247#ifdef FEAT_HANGULIN
5248 "hangul_input",
5249#endif
5250#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5251 "iconv",
5252#endif
5253#ifdef FEAT_INS_EXPAND
5254 "insert_expand",
5255#endif
5256#ifdef FEAT_JOB_CHANNEL
5257 "job",
5258#endif
5259#ifdef FEAT_JUMPLIST
5260 "jumplist",
5261#endif
5262#ifdef FEAT_KEYMAP
5263 "keymap",
5264#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005265 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005266#ifdef FEAT_LANGMAP
5267 "langmap",
5268#endif
5269#ifdef FEAT_LIBCALL
5270 "libcall",
5271#endif
5272#ifdef FEAT_LINEBREAK
5273 "linebreak",
5274#endif
5275#ifdef FEAT_LISP
5276 "lispindent",
5277#endif
5278#ifdef FEAT_LISTCMDS
5279 "listcmds",
5280#endif
5281#ifdef FEAT_LOCALMAP
5282 "localmap",
5283#endif
5284#ifdef FEAT_LUA
5285# ifndef DYNAMIC_LUA
5286 "lua",
5287# endif
5288#endif
5289#ifdef FEAT_MENU
5290 "menu",
5291#endif
5292#ifdef FEAT_SESSION
5293 "mksession",
5294#endif
5295#ifdef FEAT_MODIFY_FNAME
5296 "modify_fname",
5297#endif
5298#ifdef FEAT_MOUSE
5299 "mouse",
5300#endif
5301#ifdef FEAT_MOUSESHAPE
5302 "mouseshape",
5303#endif
5304#if defined(UNIX) || defined(VMS)
5305# ifdef FEAT_MOUSE_DEC
5306 "mouse_dec",
5307# endif
5308# ifdef FEAT_MOUSE_GPM
5309 "mouse_gpm",
5310# endif
5311# ifdef FEAT_MOUSE_JSB
5312 "mouse_jsbterm",
5313# endif
5314# ifdef FEAT_MOUSE_NET
5315 "mouse_netterm",
5316# endif
5317# ifdef FEAT_MOUSE_PTERM
5318 "mouse_pterm",
5319# endif
5320# ifdef FEAT_MOUSE_SGR
5321 "mouse_sgr",
5322# endif
5323# ifdef FEAT_SYSMOUSE
5324 "mouse_sysmouse",
5325# endif
5326# ifdef FEAT_MOUSE_URXVT
5327 "mouse_urxvt",
5328# endif
5329# ifdef FEAT_MOUSE_XTERM
5330 "mouse_xterm",
5331# endif
5332#endif
5333#ifdef FEAT_MBYTE
5334 "multi_byte",
5335#endif
5336#ifdef FEAT_MBYTE_IME
5337 "multi_byte_ime",
5338#endif
5339#ifdef FEAT_MULTI_LANG
5340 "multi_lang",
5341#endif
5342#ifdef FEAT_MZSCHEME
5343#ifndef DYNAMIC_MZSCHEME
5344 "mzscheme",
5345#endif
5346#endif
5347#ifdef FEAT_NUM64
5348 "num64",
5349#endif
5350#ifdef FEAT_OLE
5351 "ole",
5352#endif
5353 "packages",
5354#ifdef FEAT_PATH_EXTRA
5355 "path_extra",
5356#endif
5357#ifdef FEAT_PERL
5358#ifndef DYNAMIC_PERL
5359 "perl",
5360#endif
5361#endif
5362#ifdef FEAT_PERSISTENT_UNDO
5363 "persistent_undo",
5364#endif
5365#ifdef FEAT_PYTHON
5366#ifndef DYNAMIC_PYTHON
5367 "python",
5368#endif
5369#endif
5370#ifdef FEAT_PYTHON3
5371#ifndef DYNAMIC_PYTHON3
5372 "python3",
5373#endif
5374#endif
5375#ifdef FEAT_POSTSCRIPT
5376 "postscript",
5377#endif
5378#ifdef FEAT_PRINTER
5379 "printer",
5380#endif
5381#ifdef FEAT_PROFILE
5382 "profile",
5383#endif
5384#ifdef FEAT_RELTIME
5385 "reltime",
5386#endif
5387#ifdef FEAT_QUICKFIX
5388 "quickfix",
5389#endif
5390#ifdef FEAT_RIGHTLEFT
5391 "rightleft",
5392#endif
5393#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5394 "ruby",
5395#endif
5396#ifdef FEAT_SCROLLBIND
5397 "scrollbind",
5398#endif
5399#ifdef FEAT_CMDL_INFO
5400 "showcmd",
5401 "cmdline_info",
5402#endif
5403#ifdef FEAT_SIGNS
5404 "signs",
5405#endif
5406#ifdef FEAT_SMARTINDENT
5407 "smartindent",
5408#endif
5409#ifdef STARTUPTIME
5410 "startuptime",
5411#endif
5412#ifdef FEAT_STL_OPT
5413 "statusline",
5414#endif
5415#ifdef FEAT_SUN_WORKSHOP
5416 "sun_workshop",
5417#endif
5418#ifdef FEAT_NETBEANS_INTG
5419 "netbeans_intg",
5420#endif
5421#ifdef FEAT_SPELL
5422 "spell",
5423#endif
5424#ifdef FEAT_SYN_HL
5425 "syntax",
5426#endif
5427#if defined(USE_SYSTEM) || !defined(UNIX)
5428 "system",
5429#endif
5430#ifdef FEAT_TAG_BINS
5431 "tag_binary",
5432#endif
5433#ifdef FEAT_TAG_OLDSTATIC
5434 "tag_old_static",
5435#endif
5436#ifdef FEAT_TAG_ANYWHITE
5437 "tag_any_white",
5438#endif
5439#ifdef FEAT_TCL
5440# ifndef DYNAMIC_TCL
5441 "tcl",
5442# endif
5443#endif
5444#ifdef FEAT_TERMGUICOLORS
5445 "termguicolors",
5446#endif
5447#ifdef TERMINFO
5448 "terminfo",
5449#endif
5450#ifdef FEAT_TERMRESPONSE
5451 "termresponse",
5452#endif
5453#ifdef FEAT_TEXTOBJ
5454 "textobjects",
5455#endif
5456#ifdef HAVE_TGETENT
5457 "tgetent",
5458#endif
5459#ifdef FEAT_TIMERS
5460 "timers",
5461#endif
5462#ifdef FEAT_TITLE
5463 "title",
5464#endif
5465#ifdef FEAT_TOOLBAR
5466 "toolbar",
5467#endif
5468#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5469 "unnamedplus",
5470#endif
5471#ifdef FEAT_USR_CMDS
5472 "user-commands", /* was accidentally included in 5.4 */
5473 "user_commands",
5474#endif
5475#ifdef FEAT_VIMINFO
5476 "viminfo",
5477#endif
5478#ifdef FEAT_WINDOWS
5479 "vertsplit",
5480#endif
5481#ifdef FEAT_VIRTUALEDIT
5482 "virtualedit",
5483#endif
5484 "visual",
5485#ifdef FEAT_VISUALEXTRA
5486 "visualextra",
5487#endif
5488#ifdef FEAT_VREPLACE
5489 "vreplace",
5490#endif
5491#ifdef FEAT_WILDIGN
5492 "wildignore",
5493#endif
5494#ifdef FEAT_WILDMENU
5495 "wildmenu",
5496#endif
5497#ifdef FEAT_WINDOWS
5498 "windows",
5499#endif
5500#ifdef FEAT_WAK
5501 "winaltkeys",
5502#endif
5503#ifdef FEAT_WRITEBACKUP
5504 "writebackup",
5505#endif
5506#ifdef FEAT_XIM
5507 "xim",
5508#endif
5509#ifdef FEAT_XFONTSET
5510 "xfontset",
5511#endif
5512#ifdef FEAT_XPM_W32
5513 "xpm",
5514 "xpm_w32", /* for backward compatibility */
5515#else
5516# if defined(HAVE_XPM)
5517 "xpm",
5518# endif
5519#endif
5520#ifdef USE_XSMP
5521 "xsmp",
5522#endif
5523#ifdef USE_XSMP_INTERACT
5524 "xsmp_interact",
5525#endif
5526#ifdef FEAT_XCLIPBOARD
5527 "xterm_clipboard",
5528#endif
5529#ifdef FEAT_XTERM_SAVE
5530 "xterm_save",
5531#endif
5532#if defined(UNIX) && defined(FEAT_X11)
5533 "X11",
5534#endif
5535 NULL
5536 };
5537
5538 name = get_tv_string(&argvars[0]);
5539 for (i = 0; has_list[i] != NULL; ++i)
5540 if (STRICMP(name, has_list[i]) == 0)
5541 {
5542 n = TRUE;
5543 break;
5544 }
5545
5546 if (n == FALSE)
5547 {
5548 if (STRNICMP(name, "patch", 5) == 0)
5549 {
5550 if (name[5] == '-'
5551 && STRLEN(name) >= 11
5552 && vim_isdigit(name[6])
5553 && vim_isdigit(name[8])
5554 && vim_isdigit(name[10]))
5555 {
5556 int major = atoi((char *)name + 6);
5557 int minor = atoi((char *)name + 8);
5558
5559 /* Expect "patch-9.9.01234". */
5560 n = (major < VIM_VERSION_MAJOR
5561 || (major == VIM_VERSION_MAJOR
5562 && (minor < VIM_VERSION_MINOR
5563 || (minor == VIM_VERSION_MINOR
5564 && has_patch(atoi((char *)name + 10))))));
5565 }
5566 else
5567 n = has_patch(atoi((char *)name + 5));
5568 }
5569 else if (STRICMP(name, "vim_starting") == 0)
5570 n = (starting != 0);
5571#ifdef FEAT_MBYTE
5572 else if (STRICMP(name, "multi_byte_encoding") == 0)
5573 n = has_mbyte;
5574#endif
5575#if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32)
5576 else if (STRICMP(name, "balloon_multiline") == 0)
5577 n = multiline_balloon_available();
5578#endif
5579#ifdef DYNAMIC_TCL
5580 else if (STRICMP(name, "tcl") == 0)
5581 n = tcl_enabled(FALSE);
5582#endif
5583#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5584 else if (STRICMP(name, "iconv") == 0)
5585 n = iconv_enabled(FALSE);
5586#endif
5587#ifdef DYNAMIC_LUA
5588 else if (STRICMP(name, "lua") == 0)
5589 n = lua_enabled(FALSE);
5590#endif
5591#ifdef DYNAMIC_MZSCHEME
5592 else if (STRICMP(name, "mzscheme") == 0)
5593 n = mzscheme_enabled(FALSE);
5594#endif
5595#ifdef DYNAMIC_RUBY
5596 else if (STRICMP(name, "ruby") == 0)
5597 n = ruby_enabled(FALSE);
5598#endif
5599#ifdef FEAT_PYTHON
5600#ifdef DYNAMIC_PYTHON
5601 else if (STRICMP(name, "python") == 0)
5602 n = python_enabled(FALSE);
5603#endif
5604#endif
5605#ifdef FEAT_PYTHON3
5606#ifdef DYNAMIC_PYTHON3
5607 else if (STRICMP(name, "python3") == 0)
5608 n = python3_enabled(FALSE);
5609#endif
5610#endif
5611#ifdef DYNAMIC_PERL
5612 else if (STRICMP(name, "perl") == 0)
5613 n = perl_enabled(FALSE);
5614#endif
5615#ifdef FEAT_GUI
5616 else if (STRICMP(name, "gui_running") == 0)
5617 n = (gui.in_use || gui.starting);
5618# ifdef FEAT_GUI_W32
5619 else if (STRICMP(name, "gui_win32s") == 0)
5620 n = gui_is_win32s();
5621# endif
5622# ifdef FEAT_BROWSE
5623 else if (STRICMP(name, "browse") == 0)
5624 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5625# endif
5626#endif
5627#ifdef FEAT_SYN_HL
5628 else if (STRICMP(name, "syntax_items") == 0)
5629 n = syntax_present(curwin);
5630#endif
5631#if defined(WIN3264)
5632 else if (STRICMP(name, "win95") == 0)
5633 n = mch_windows95();
5634#endif
5635#ifdef FEAT_NETBEANS_INTG
5636 else if (STRICMP(name, "netbeans_enabled") == 0)
5637 n = netbeans_active();
5638#endif
5639 }
5640
5641 rettv->vval.v_number = n;
5642}
5643
5644/*
5645 * "has_key()" function
5646 */
5647 static void
5648f_has_key(typval_T *argvars, typval_T *rettv)
5649{
5650 if (argvars[0].v_type != VAR_DICT)
5651 {
5652 EMSG(_(e_dictreq));
5653 return;
5654 }
5655 if (argvars[0].vval.v_dict == NULL)
5656 return;
5657
5658 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
5659 get_tv_string(&argvars[1]), -1) != NULL;
5660}
5661
5662/*
5663 * "haslocaldir()" function
5664 */
5665 static void
5666f_haslocaldir(typval_T *argvars, typval_T *rettv)
5667{
5668 win_T *wp = NULL;
5669
5670 wp = find_tabwin(&argvars[0], &argvars[1]);
5671 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
5672}
5673
5674/*
5675 * "hasmapto()" function
5676 */
5677 static void
5678f_hasmapto(typval_T *argvars, typval_T *rettv)
5679{
5680 char_u *name;
5681 char_u *mode;
5682 char_u buf[NUMBUFLEN];
5683 int abbr = FALSE;
5684
5685 name = get_tv_string(&argvars[0]);
5686 if (argvars[1].v_type == VAR_UNKNOWN)
5687 mode = (char_u *)"nvo";
5688 else
5689 {
5690 mode = get_tv_string_buf(&argvars[1], buf);
5691 if (argvars[2].v_type != VAR_UNKNOWN)
5692 abbr = (int)get_tv_number(&argvars[2]);
5693 }
5694
5695 if (map_to_exists(name, mode, abbr))
5696 rettv->vval.v_number = TRUE;
5697 else
5698 rettv->vval.v_number = FALSE;
5699}
5700
5701/*
5702 * "histadd()" function
5703 */
5704 static void
5705f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
5706{
5707#ifdef FEAT_CMDHIST
5708 int histype;
5709 char_u *str;
5710 char_u buf[NUMBUFLEN];
5711#endif
5712
5713 rettv->vval.v_number = FALSE;
5714 if (check_restricted() || check_secure())
5715 return;
5716#ifdef FEAT_CMDHIST
5717 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5718 histype = str != NULL ? get_histtype(str) : -1;
5719 if (histype >= 0)
5720 {
5721 str = get_tv_string_buf(&argvars[1], buf);
5722 if (*str != NUL)
5723 {
5724 init_history();
5725 add_to_history(histype, str, FALSE, NUL);
5726 rettv->vval.v_number = TRUE;
5727 return;
5728 }
5729 }
5730#endif
5731}
5732
5733/*
5734 * "histdel()" function
5735 */
5736 static void
5737f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5738{
5739#ifdef FEAT_CMDHIST
5740 int n;
5741 char_u buf[NUMBUFLEN];
5742 char_u *str;
5743
5744 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5745 if (str == NULL)
5746 n = 0;
5747 else if (argvars[1].v_type == VAR_UNKNOWN)
5748 /* only one argument: clear entire history */
5749 n = clr_history(get_histtype(str));
5750 else if (argvars[1].v_type == VAR_NUMBER)
5751 /* index given: remove that entry */
5752 n = del_history_idx(get_histtype(str),
5753 (int)get_tv_number(&argvars[1]));
5754 else
5755 /* string given: remove all matching entries */
5756 n = del_history_entry(get_histtype(str),
5757 get_tv_string_buf(&argvars[1], buf));
5758 rettv->vval.v_number = n;
5759#endif
5760}
5761
5762/*
5763 * "histget()" function
5764 */
5765 static void
5766f_histget(typval_T *argvars UNUSED, typval_T *rettv)
5767{
5768#ifdef FEAT_CMDHIST
5769 int type;
5770 int idx;
5771 char_u *str;
5772
5773 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
5774 if (str == NULL)
5775 rettv->vval.v_string = NULL;
5776 else
5777 {
5778 type = get_histtype(str);
5779 if (argvars[1].v_type == VAR_UNKNOWN)
5780 idx = get_history_idx(type);
5781 else
5782 idx = (int)get_tv_number_chk(&argvars[1], NULL);
5783 /* -1 on type error */
5784 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
5785 }
5786#else
5787 rettv->vval.v_string = NULL;
5788#endif
5789 rettv->v_type = VAR_STRING;
5790}
5791
5792/*
5793 * "histnr()" function
5794 */
5795 static void
5796f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
5797{
5798 int i;
5799
5800#ifdef FEAT_CMDHIST
5801 char_u *history = get_tv_string_chk(&argvars[0]);
5802
5803 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
5804 if (i >= HIST_CMD && i < HIST_COUNT)
5805 i = get_history_idx(i);
5806 else
5807#endif
5808 i = -1;
5809 rettv->vval.v_number = i;
5810}
5811
5812/*
5813 * "highlightID(name)" function
5814 */
5815 static void
5816f_hlID(typval_T *argvars, typval_T *rettv)
5817{
5818 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0]));
5819}
5820
5821/*
5822 * "highlight_exists()" function
5823 */
5824 static void
5825f_hlexists(typval_T *argvars, typval_T *rettv)
5826{
5827 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0]));
5828}
5829
5830/*
5831 * "hostname()" function
5832 */
5833 static void
5834f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5835{
5836 char_u hostname[256];
5837
5838 mch_get_host_name(hostname, 256);
5839 rettv->v_type = VAR_STRING;
5840 rettv->vval.v_string = vim_strsave(hostname);
5841}
5842
5843/*
5844 * iconv() function
5845 */
5846 static void
5847f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5848{
5849#ifdef FEAT_MBYTE
5850 char_u buf1[NUMBUFLEN];
5851 char_u buf2[NUMBUFLEN];
5852 char_u *from, *to, *str;
5853 vimconv_T vimconv;
5854#endif
5855
5856 rettv->v_type = VAR_STRING;
5857 rettv->vval.v_string = NULL;
5858
5859#ifdef FEAT_MBYTE
5860 str = get_tv_string(&argvars[0]);
5861 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1)));
5862 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2)));
5863 vimconv.vc_type = CONV_NONE;
5864 convert_setup(&vimconv, from, to);
5865
5866 /* If the encodings are equal, no conversion needed. */
5867 if (vimconv.vc_type == CONV_NONE)
5868 rettv->vval.v_string = vim_strsave(str);
5869 else
5870 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5871
5872 convert_setup(&vimconv, NULL, NULL);
5873 vim_free(from);
5874 vim_free(to);
5875#endif
5876}
5877
5878/*
5879 * "indent()" function
5880 */
5881 static void
5882f_indent(typval_T *argvars, typval_T *rettv)
5883{
5884 linenr_T lnum;
5885
5886 lnum = get_tv_lnum(argvars);
5887 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5888 rettv->vval.v_number = get_indent_lnum(lnum);
5889 else
5890 rettv->vval.v_number = -1;
5891}
5892
5893/*
5894 * "index()" function
5895 */
5896 static void
5897f_index(typval_T *argvars, typval_T *rettv)
5898{
5899 list_T *l;
5900 listitem_T *item;
5901 long idx = 0;
5902 int ic = FALSE;
5903
5904 rettv->vval.v_number = -1;
5905 if (argvars[0].v_type != VAR_LIST)
5906 {
5907 EMSG(_(e_listreq));
5908 return;
5909 }
5910 l = argvars[0].vval.v_list;
5911 if (l != NULL)
5912 {
5913 item = l->lv_first;
5914 if (argvars[2].v_type != VAR_UNKNOWN)
5915 {
5916 int error = FALSE;
5917
5918 /* Start at specified item. Use the cached index that list_find()
5919 * sets, so that a negative number also works. */
5920 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error));
5921 idx = l->lv_idx;
5922 if (argvars[3].v_type != VAR_UNKNOWN)
5923 ic = (int)get_tv_number_chk(&argvars[3], &error);
5924 if (error)
5925 item = NULL;
5926 }
5927
5928 for ( ; item != NULL; item = item->li_next, ++idx)
5929 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5930 {
5931 rettv->vval.v_number = idx;
5932 break;
5933 }
5934 }
5935}
5936
5937static int inputsecret_flag = 0;
5938
5939/*
5940 * "input()" function
5941 * Also handles inputsecret() when inputsecret is set.
5942 */
5943 static void
5944f_input(typval_T *argvars, typval_T *rettv)
5945{
5946 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5947}
5948
5949/*
5950 * "inputdialog()" function
5951 */
5952 static void
5953f_inputdialog(typval_T *argvars, typval_T *rettv)
5954{
5955#if defined(FEAT_GUI_TEXTDIALOG)
5956 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5957 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5958 {
5959 char_u *message;
5960 char_u buf[NUMBUFLEN];
5961 char_u *defstr = (char_u *)"";
5962
5963 message = get_tv_string_chk(&argvars[0]);
5964 if (argvars[1].v_type != VAR_UNKNOWN
5965 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL)
5966 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5967 else
5968 IObuff[0] = NUL;
5969 if (message != NULL && defstr != NULL
5970 && do_dialog(VIM_QUESTION, NULL, message,
5971 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5972 rettv->vval.v_string = vim_strsave(IObuff);
5973 else
5974 {
5975 if (message != NULL && defstr != NULL
5976 && argvars[1].v_type != VAR_UNKNOWN
5977 && argvars[2].v_type != VAR_UNKNOWN)
5978 rettv->vval.v_string = vim_strsave(
5979 get_tv_string_buf(&argvars[2], buf));
5980 else
5981 rettv->vval.v_string = NULL;
5982 }
5983 rettv->v_type = VAR_STRING;
5984 }
5985 else
5986#endif
5987 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5988}
5989
5990/*
5991 * "inputlist()" function
5992 */
5993 static void
5994f_inputlist(typval_T *argvars, typval_T *rettv)
5995{
5996 listitem_T *li;
5997 int selected;
5998 int mouse_used;
5999
6000#ifdef NO_CONSOLE_INPUT
6001 /* While starting up, there is no place to enter text. */
6002 if (no_console_input())
6003 return;
6004#endif
6005 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6006 {
6007 EMSG2(_(e_listarg), "inputlist()");
6008 return;
6009 }
6010
6011 msg_start();
6012 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6013 lines_left = Rows; /* avoid more prompt */
6014 msg_scroll = TRUE;
6015 msg_clr_eos();
6016
6017 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6018 {
6019 msg_puts(get_tv_string(&li->li_tv));
6020 msg_putchar('\n');
6021 }
6022
6023 /* Ask for choice. */
6024 selected = prompt_for_number(&mouse_used);
6025 if (mouse_used)
6026 selected -= lines_left;
6027
6028 rettv->vval.v_number = selected;
6029}
6030
6031
6032static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6033
6034/*
6035 * "inputrestore()" function
6036 */
6037 static void
6038f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6039{
6040 if (ga_userinput.ga_len > 0)
6041 {
6042 --ga_userinput.ga_len;
6043 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6044 + ga_userinput.ga_len);
6045 /* default return is zero == OK */
6046 }
6047 else if (p_verbose > 1)
6048 {
6049 verb_msg((char_u *)_("called inputrestore() more often than inputsave()"));
6050 rettv->vval.v_number = 1; /* Failed */
6051 }
6052}
6053
6054/*
6055 * "inputsave()" function
6056 */
6057 static void
6058f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6059{
6060 /* Add an entry to the stack of typeahead storage. */
6061 if (ga_grow(&ga_userinput, 1) == OK)
6062 {
6063 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6064 + ga_userinput.ga_len);
6065 ++ga_userinput.ga_len;
6066 /* default return is zero == OK */
6067 }
6068 else
6069 rettv->vval.v_number = 1; /* Failed */
6070}
6071
6072/*
6073 * "inputsecret()" function
6074 */
6075 static void
6076f_inputsecret(typval_T *argvars, typval_T *rettv)
6077{
6078 ++cmdline_star;
6079 ++inputsecret_flag;
6080 f_input(argvars, rettv);
6081 --cmdline_star;
6082 --inputsecret_flag;
6083}
6084
6085/*
6086 * "insert()" function
6087 */
6088 static void
6089f_insert(typval_T *argvars, typval_T *rettv)
6090{
6091 long before = 0;
6092 listitem_T *item;
6093 list_T *l;
6094 int error = FALSE;
6095
6096 if (argvars[0].v_type != VAR_LIST)
6097 EMSG2(_(e_listarg), "insert()");
6098 else if ((l = argvars[0].vval.v_list) != NULL
6099 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE))
6100 {
6101 if (argvars[2].v_type != VAR_UNKNOWN)
6102 before = (long)get_tv_number_chk(&argvars[2], &error);
6103 if (error)
6104 return; /* type error; errmsg already given */
6105
6106 if (before == l->lv_len)
6107 item = NULL;
6108 else
6109 {
6110 item = list_find(l, before);
6111 if (item == NULL)
6112 {
6113 EMSGN(_(e_listidx), before);
6114 l = NULL;
6115 }
6116 }
6117 if (l != NULL)
6118 {
6119 list_insert_tv(l, &argvars[1], item);
6120 copy_tv(&argvars[0], rettv);
6121 }
6122 }
6123}
6124
6125/*
6126 * "invert(expr)" function
6127 */
6128 static void
6129f_invert(typval_T *argvars, typval_T *rettv)
6130{
6131 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL);
6132}
6133
6134/*
6135 * "isdirectory()" function
6136 */
6137 static void
6138f_isdirectory(typval_T *argvars, typval_T *rettv)
6139{
6140 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0]));
6141}
6142
6143/*
6144 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6145 * or it refers to a List or Dictionary that is locked.
6146 */
6147 static int
6148tv_islocked(typval_T *tv)
6149{
6150 return (tv->v_lock & VAR_LOCKED)
6151 || (tv->v_type == VAR_LIST
6152 && tv->vval.v_list != NULL
6153 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6154 || (tv->v_type == VAR_DICT
6155 && tv->vval.v_dict != NULL
6156 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6157}
6158
6159/*
6160 * "islocked()" function
6161 */
6162 static void
6163f_islocked(typval_T *argvars, typval_T *rettv)
6164{
6165 lval_T lv;
6166 char_u *end;
6167 dictitem_T *di;
6168
6169 rettv->vval.v_number = -1;
6170 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
6171 GLV_NO_AUTOLOAD, FNE_CHECK_START);
6172 if (end != NULL && lv.ll_name != NULL)
6173 {
6174 if (*end != NUL)
6175 EMSG(_(e_trailing));
6176 else
6177 {
6178 if (lv.ll_tv == NULL)
6179 {
6180 if (check_changedtick(lv.ll_name))
6181 rettv->vval.v_number = 1; /* always locked */
6182 else
6183 {
6184 di = find_var(lv.ll_name, NULL, TRUE);
6185 if (di != NULL)
6186 {
6187 /* Consider a variable locked when:
6188 * 1. the variable itself is locked
6189 * 2. the value of the variable is locked.
6190 * 3. the List or Dict value is locked.
6191 */
6192 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6193 || tv_islocked(&di->di_tv));
6194 }
6195 }
6196 }
6197 else if (lv.ll_range)
6198 EMSG(_("E786: Range not allowed"));
6199 else if (lv.ll_newkey != NULL)
6200 EMSG2(_(e_dictkey), lv.ll_newkey);
6201 else if (lv.ll_list != NULL)
6202 /* List item. */
6203 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6204 else
6205 /* Dictionary item. */
6206 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6207 }
6208 }
6209
6210 clear_lval(&lv);
6211}
6212
6213#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6214/*
6215 * "isnan()" function
6216 */
6217 static void
6218f_isnan(typval_T *argvars, typval_T *rettv)
6219{
6220 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6221 && isnan(argvars[0].vval.v_float);
6222}
6223#endif
6224
6225/*
6226 * "items(dict)" function
6227 */
6228 static void
6229f_items(typval_T *argvars, typval_T *rettv)
6230{
6231 dict_list(argvars, rettv, 2);
6232}
6233
6234#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
6235/*
6236 * Get the job from the argument.
6237 * Returns NULL if the job is invalid.
6238 */
6239 static job_T *
6240get_job_arg(typval_T *tv)
6241{
6242 job_T *job;
6243
6244 if (tv->v_type != VAR_JOB)
6245 {
6246 EMSG2(_(e_invarg2), get_tv_string(tv));
6247 return NULL;
6248 }
6249 job = tv->vval.v_job;
6250
6251 if (job == NULL)
6252 EMSG(_("E916: not a valid job"));
6253 return job;
6254}
6255
6256/*
6257 * "job_getchannel()" function
6258 */
6259 static void
6260f_job_getchannel(typval_T *argvars, typval_T *rettv)
6261{
6262 job_T *job = get_job_arg(&argvars[0]);
6263
6264 if (job != NULL)
6265 {
6266 rettv->v_type = VAR_CHANNEL;
6267 rettv->vval.v_channel = job->jv_channel;
6268 if (job->jv_channel != NULL)
6269 ++job->jv_channel->ch_refcount;
6270 }
6271}
6272
6273/*
6274 * "job_info()" function
6275 */
6276 static void
6277f_job_info(typval_T *argvars, typval_T *rettv)
6278{
6279 job_T *job = get_job_arg(&argvars[0]);
6280
6281 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
6282 job_info(job, rettv->vval.v_dict);
6283}
6284
6285/*
6286 * "job_setoptions()" function
6287 */
6288 static void
6289f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
6290{
6291 job_T *job = get_job_arg(&argvars[0]);
6292 jobopt_T opt;
6293
6294 if (job == NULL)
6295 return;
6296 clear_job_options(&opt);
6297 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK)
6298 job_set_options(job, &opt);
6299 free_job_options(&opt);
6300}
6301
6302/*
6303 * "job_start()" function
6304 */
6305 static void
6306f_job_start(typval_T *argvars, typval_T *rettv)
6307{
6308 rettv->v_type = VAR_JOB;
6309 if (check_restricted() || check_secure())
6310 return;
6311 rettv->vval.v_job = job_start(argvars);
6312}
6313
6314/*
6315 * "job_status()" function
6316 */
6317 static void
6318f_job_status(typval_T *argvars, typval_T *rettv)
6319{
6320 job_T *job = get_job_arg(&argvars[0]);
6321
6322 if (job != NULL)
6323 {
6324 rettv->v_type = VAR_STRING;
6325 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
6326 }
6327}
6328
6329/*
6330 * "job_stop()" function
6331 */
6332 static void
6333f_job_stop(typval_T *argvars, typval_T *rettv)
6334{
6335 job_T *job = get_job_arg(&argvars[0]);
6336
6337 if (job != NULL)
6338 rettv->vval.v_number = job_stop(job, argvars);
6339}
6340#endif
6341
6342/*
6343 * "join()" function
6344 */
6345 static void
6346f_join(typval_T *argvars, typval_T *rettv)
6347{
6348 garray_T ga;
6349 char_u *sep;
6350
6351 if (argvars[0].v_type != VAR_LIST)
6352 {
6353 EMSG(_(e_listreq));
6354 return;
6355 }
6356 if (argvars[0].vval.v_list == NULL)
6357 return;
6358 if (argvars[1].v_type == VAR_UNKNOWN)
6359 sep = (char_u *)" ";
6360 else
6361 sep = get_tv_string_chk(&argvars[1]);
6362
6363 rettv->v_type = VAR_STRING;
6364
6365 if (sep != NULL)
6366 {
6367 ga_init2(&ga, (int)sizeof(char), 80);
6368 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
6369 ga_append(&ga, NUL);
6370 rettv->vval.v_string = (char_u *)ga.ga_data;
6371 }
6372 else
6373 rettv->vval.v_string = NULL;
6374}
6375
6376/*
6377 * "js_decode()" function
6378 */
6379 static void
6380f_js_decode(typval_T *argvars, typval_T *rettv)
6381{
6382 js_read_T reader;
6383
6384 reader.js_buf = get_tv_string(&argvars[0]);
6385 reader.js_fill = NULL;
6386 reader.js_used = 0;
6387 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
6388 EMSG(_(e_invarg));
6389}
6390
6391/*
6392 * "js_encode()" function
6393 */
6394 static void
6395f_js_encode(typval_T *argvars, typval_T *rettv)
6396{
6397 rettv->v_type = VAR_STRING;
6398 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
6399}
6400
6401/*
6402 * "json_decode()" function
6403 */
6404 static void
6405f_json_decode(typval_T *argvars, typval_T *rettv)
6406{
6407 js_read_T reader;
6408
6409 reader.js_buf = get_tv_string(&argvars[0]);
6410 reader.js_fill = NULL;
6411 reader.js_used = 0;
6412 if (json_decode_all(&reader, rettv, 0) != OK)
6413 EMSG(_(e_invarg));
6414}
6415
6416/*
6417 * "json_encode()" function
6418 */
6419 static void
6420f_json_encode(typval_T *argvars, typval_T *rettv)
6421{
6422 rettv->v_type = VAR_STRING;
6423 rettv->vval.v_string = json_encode(&argvars[0], 0);
6424}
6425
6426/*
6427 * "keys()" function
6428 */
6429 static void
6430f_keys(typval_T *argvars, typval_T *rettv)
6431{
6432 dict_list(argvars, rettv, 0);
6433}
6434
6435/*
6436 * "last_buffer_nr()" function.
6437 */
6438 static void
6439f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6440{
6441 int n = 0;
6442 buf_T *buf;
6443
Bram Moolenaar29323592016-07-24 22:04:11 +02006444 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445 if (n < buf->b_fnum)
6446 n = buf->b_fnum;
6447
6448 rettv->vval.v_number = n;
6449}
6450
6451/*
6452 * "len()" function
6453 */
6454 static void
6455f_len(typval_T *argvars, typval_T *rettv)
6456{
6457 switch (argvars[0].v_type)
6458 {
6459 case VAR_STRING:
6460 case VAR_NUMBER:
6461 rettv->vval.v_number = (varnumber_T)STRLEN(
6462 get_tv_string(&argvars[0]));
6463 break;
6464 case VAR_LIST:
6465 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6466 break;
6467 case VAR_DICT:
6468 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6469 break;
6470 case VAR_UNKNOWN:
6471 case VAR_SPECIAL:
6472 case VAR_FLOAT:
6473 case VAR_FUNC:
6474 case VAR_PARTIAL:
6475 case VAR_JOB:
6476 case VAR_CHANNEL:
6477 EMSG(_("E701: Invalid type for len()"));
6478 break;
6479 }
6480}
6481
6482static void libcall_common(typval_T *argvars, typval_T *rettv, int type);
6483
6484 static void
6485libcall_common(typval_T *argvars, typval_T *rettv, int type)
6486{
6487#ifdef FEAT_LIBCALL
6488 char_u *string_in;
6489 char_u **string_result;
6490 int nr_result;
6491#endif
6492
6493 rettv->v_type = type;
6494 if (type != VAR_NUMBER)
6495 rettv->vval.v_string = NULL;
6496
6497 if (check_restricted() || check_secure())
6498 return;
6499
6500#ifdef FEAT_LIBCALL
6501 /* The first two args must be strings, otherwise its meaningless */
6502 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6503 {
6504 string_in = NULL;
6505 if (argvars[2].v_type == VAR_STRING)
6506 string_in = argvars[2].vval.v_string;
6507 if (type == VAR_NUMBER)
6508 string_result = NULL;
6509 else
6510 string_result = &rettv->vval.v_string;
6511 if (mch_libcall(argvars[0].vval.v_string,
6512 argvars[1].vval.v_string,
6513 string_in,
6514 argvars[2].vval.v_number,
6515 string_result,
6516 &nr_result) == OK
6517 && type == VAR_NUMBER)
6518 rettv->vval.v_number = nr_result;
6519 }
6520#endif
6521}
6522
6523/*
6524 * "libcall()" function
6525 */
6526 static void
6527f_libcall(typval_T *argvars, typval_T *rettv)
6528{
6529 libcall_common(argvars, rettv, VAR_STRING);
6530}
6531
6532/*
6533 * "libcallnr()" function
6534 */
6535 static void
6536f_libcallnr(typval_T *argvars, typval_T *rettv)
6537{
6538 libcall_common(argvars, rettv, VAR_NUMBER);
6539}
6540
6541/*
6542 * "line(string)" function
6543 */
6544 static void
6545f_line(typval_T *argvars, typval_T *rettv)
6546{
6547 linenr_T lnum = 0;
6548 pos_T *fp;
6549 int fnum;
6550
6551 fp = var2fpos(&argvars[0], TRUE, &fnum);
6552 if (fp != NULL)
6553 lnum = fp->lnum;
6554 rettv->vval.v_number = lnum;
6555}
6556
6557/*
6558 * "line2byte(lnum)" function
6559 */
6560 static void
6561f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6562{
6563#ifndef FEAT_BYTEOFF
6564 rettv->vval.v_number = -1;
6565#else
6566 linenr_T lnum;
6567
6568 lnum = get_tv_lnum(argvars);
6569 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6570 rettv->vval.v_number = -1;
6571 else
6572 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6573 if (rettv->vval.v_number >= 0)
6574 ++rettv->vval.v_number;
6575#endif
6576}
6577
6578/*
6579 * "lispindent(lnum)" function
6580 */
6581 static void
6582f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
6583{
6584#ifdef FEAT_LISP
6585 pos_T pos;
6586 linenr_T lnum;
6587
6588 pos = curwin->w_cursor;
6589 lnum = get_tv_lnum(argvars);
6590 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6591 {
6592 curwin->w_cursor.lnum = lnum;
6593 rettv->vval.v_number = get_lisp_indent();
6594 curwin->w_cursor = pos;
6595 }
6596 else
6597#endif
6598 rettv->vval.v_number = -1;
6599}
6600
6601/*
6602 * "localtime()" function
6603 */
6604 static void
6605f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
6606{
6607 rettv->vval.v_number = (varnumber_T)time(NULL);
6608}
6609
6610static void get_maparg(typval_T *argvars, typval_T *rettv, int exact);
6611
6612 static void
6613get_maparg(typval_T *argvars, typval_T *rettv, int exact)
6614{
6615 char_u *keys;
6616 char_u *which;
6617 char_u buf[NUMBUFLEN];
6618 char_u *keys_buf = NULL;
6619 char_u *rhs;
6620 int mode;
6621 int abbr = FALSE;
6622 int get_dict = FALSE;
6623 mapblock_T *mp;
6624 int buffer_local;
6625
6626 /* return empty string for failure */
6627 rettv->v_type = VAR_STRING;
6628 rettv->vval.v_string = NULL;
6629
6630 keys = get_tv_string(&argvars[0]);
6631 if (*keys == NUL)
6632 return;
6633
6634 if (argvars[1].v_type != VAR_UNKNOWN)
6635 {
6636 which = get_tv_string_buf_chk(&argvars[1], buf);
6637 if (argvars[2].v_type != VAR_UNKNOWN)
6638 {
6639 abbr = (int)get_tv_number(&argvars[2]);
6640 if (argvars[3].v_type != VAR_UNKNOWN)
6641 get_dict = (int)get_tv_number(&argvars[3]);
6642 }
6643 }
6644 else
6645 which = (char_u *)"";
6646 if (which == NULL)
6647 return;
6648
6649 mode = get_map_mode(&which, 0);
6650
6651 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
6652 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
6653 vim_free(keys_buf);
6654
6655 if (!get_dict)
6656 {
6657 /* Return a string. */
6658 if (rhs != NULL)
6659 rettv->vval.v_string = str2special_save(rhs, FALSE);
6660
6661 }
6662 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
6663 {
6664 /* Return a dictionary. */
6665 char_u *lhs = str2special_save(mp->m_keys, TRUE);
6666 char_u *mapmode = map_mode_to_chars(mp->m_mode);
6667 dict_T *dict = rettv->vval.v_dict;
6668
6669 dict_add_nr_str(dict, "lhs", 0L, lhs);
6670 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str);
6671 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL);
6672 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL);
6673 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL);
6674 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL);
6675 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL);
6676 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL);
6677 dict_add_nr_str(dict, "mode", 0L, mapmode);
6678
6679 vim_free(lhs);
6680 vim_free(mapmode);
6681 }
6682}
6683
6684#ifdef FEAT_FLOAT
6685/*
6686 * "log()" function
6687 */
6688 static void
6689f_log(typval_T *argvars, typval_T *rettv)
6690{
6691 float_T f = 0.0;
6692
6693 rettv->v_type = VAR_FLOAT;
6694 if (get_float_arg(argvars, &f) == OK)
6695 rettv->vval.v_float = log(f);
6696 else
6697 rettv->vval.v_float = 0.0;
6698}
6699
6700/*
6701 * "log10()" function
6702 */
6703 static void
6704f_log10(typval_T *argvars, typval_T *rettv)
6705{
6706 float_T f = 0.0;
6707
6708 rettv->v_type = VAR_FLOAT;
6709 if (get_float_arg(argvars, &f) == OK)
6710 rettv->vval.v_float = log10(f);
6711 else
6712 rettv->vval.v_float = 0.0;
6713}
6714#endif
6715
6716#ifdef FEAT_LUA
6717/*
6718 * "luaeval()" function
6719 */
6720 static void
6721f_luaeval(typval_T *argvars, typval_T *rettv)
6722{
6723 char_u *str;
6724 char_u buf[NUMBUFLEN];
6725
6726 str = get_tv_string_buf(&argvars[0], buf);
6727 do_luaeval(str, argvars + 1, rettv);
6728}
6729#endif
6730
6731/*
6732 * "map()" function
6733 */
6734 static void
6735f_map(typval_T *argvars, typval_T *rettv)
6736{
6737 filter_map(argvars, rettv, TRUE);
6738}
6739
6740/*
6741 * "maparg()" function
6742 */
6743 static void
6744f_maparg(typval_T *argvars, typval_T *rettv)
6745{
6746 get_maparg(argvars, rettv, TRUE);
6747}
6748
6749/*
6750 * "mapcheck()" function
6751 */
6752 static void
6753f_mapcheck(typval_T *argvars, typval_T *rettv)
6754{
6755 get_maparg(argvars, rettv, FALSE);
6756}
6757
6758static void find_some_match(typval_T *argvars, typval_T *rettv, int start);
6759
6760 static void
6761find_some_match(typval_T *argvars, typval_T *rettv, int type)
6762{
6763 char_u *str = NULL;
6764 long len = 0;
6765 char_u *expr = NULL;
6766 char_u *pat;
6767 regmatch_T regmatch;
6768 char_u patbuf[NUMBUFLEN];
6769 char_u strbuf[NUMBUFLEN];
6770 char_u *save_cpo;
6771 long start = 0;
6772 long nth = 1;
6773 colnr_T startcol = 0;
6774 int match = 0;
6775 list_T *l = NULL;
6776 listitem_T *li = NULL;
6777 long idx = 0;
6778 char_u *tofree = NULL;
6779
6780 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6781 save_cpo = p_cpo;
6782 p_cpo = (char_u *)"";
6783
6784 rettv->vval.v_number = -1;
6785 if (type == 3 || type == 4)
6786 {
6787 /* type 3: return empty list when there are no matches.
6788 * type 4: return ["", -1, -1, -1] */
6789 if (rettv_list_alloc(rettv) == FAIL)
6790 goto theend;
6791 if (type == 4
6792 && (list_append_string(rettv->vval.v_list,
6793 (char_u *)"", 0) == FAIL
6794 || list_append_number(rettv->vval.v_list,
6795 (varnumber_T)-1) == FAIL
6796 || list_append_number(rettv->vval.v_list,
6797 (varnumber_T)-1) == FAIL
6798 || list_append_number(rettv->vval.v_list,
6799 (varnumber_T)-1) == FAIL))
6800 {
6801 list_free(rettv->vval.v_list);
6802 rettv->vval.v_list = NULL;
6803 goto theend;
6804 }
6805 }
6806 else if (type == 2)
6807 {
6808 rettv->v_type = VAR_STRING;
6809 rettv->vval.v_string = NULL;
6810 }
6811
6812 if (argvars[0].v_type == VAR_LIST)
6813 {
6814 if ((l = argvars[0].vval.v_list) == NULL)
6815 goto theend;
6816 li = l->lv_first;
6817 }
6818 else
6819 {
6820 expr = str = get_tv_string(&argvars[0]);
6821 len = (long)STRLEN(str);
6822 }
6823
6824 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
6825 if (pat == NULL)
6826 goto theend;
6827
6828 if (argvars[2].v_type != VAR_UNKNOWN)
6829 {
6830 int error = FALSE;
6831
6832 start = (long)get_tv_number_chk(&argvars[2], &error);
6833 if (error)
6834 goto theend;
6835 if (l != NULL)
6836 {
6837 li = list_find(l, start);
6838 if (li == NULL)
6839 goto theend;
6840 idx = l->lv_idx; /* use the cached index */
6841 }
6842 else
6843 {
6844 if (start < 0)
6845 start = 0;
6846 if (start > len)
6847 goto theend;
6848 /* When "count" argument is there ignore matches before "start",
6849 * otherwise skip part of the string. Differs when pattern is "^"
6850 * or "\<". */
6851 if (argvars[3].v_type != VAR_UNKNOWN)
6852 startcol = start;
6853 else
6854 {
6855 str += start;
6856 len -= start;
6857 }
6858 }
6859
6860 if (argvars[3].v_type != VAR_UNKNOWN)
6861 nth = (long)get_tv_number_chk(&argvars[3], &error);
6862 if (error)
6863 goto theend;
6864 }
6865
6866 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6867 if (regmatch.regprog != NULL)
6868 {
6869 regmatch.rm_ic = p_ic;
6870
6871 for (;;)
6872 {
6873 if (l != NULL)
6874 {
6875 if (li == NULL)
6876 {
6877 match = FALSE;
6878 break;
6879 }
6880 vim_free(tofree);
6881 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6882 if (str == NULL)
6883 break;
6884 }
6885
6886 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6887
6888 if (match && --nth <= 0)
6889 break;
6890 if (l == NULL && !match)
6891 break;
6892
6893 /* Advance to just after the match. */
6894 if (l != NULL)
6895 {
6896 li = li->li_next;
6897 ++idx;
6898 }
6899 else
6900 {
6901#ifdef FEAT_MBYTE
6902 startcol = (colnr_T)(regmatch.startp[0]
6903 + (*mb_ptr2len)(regmatch.startp[0]) - str);
6904#else
6905 startcol = (colnr_T)(regmatch.startp[0] + 1 - str);
6906#endif
6907 if (startcol > (colnr_T)len
6908 || str + startcol <= regmatch.startp[0])
6909 {
6910 match = FALSE;
6911 break;
6912 }
6913 }
6914 }
6915
6916 if (match)
6917 {
6918 if (type == 4)
6919 {
6920 listitem_T *li1 = rettv->vval.v_list->lv_first;
6921 listitem_T *li2 = li1->li_next;
6922 listitem_T *li3 = li2->li_next;
6923 listitem_T *li4 = li3->li_next;
6924
6925 vim_free(li1->li_tv.vval.v_string);
6926 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
6927 (int)(regmatch.endp[0] - regmatch.startp[0]));
6928 li3->li_tv.vval.v_number =
6929 (varnumber_T)(regmatch.startp[0] - expr);
6930 li4->li_tv.vval.v_number =
6931 (varnumber_T)(regmatch.endp[0] - expr);
6932 if (l != NULL)
6933 li2->li_tv.vval.v_number = (varnumber_T)idx;
6934 }
6935 else if (type == 3)
6936 {
6937 int i;
6938
6939 /* return list with matched string and submatches */
6940 for (i = 0; i < NSUBEXP; ++i)
6941 {
6942 if (regmatch.endp[i] == NULL)
6943 {
6944 if (list_append_string(rettv->vval.v_list,
6945 (char_u *)"", 0) == FAIL)
6946 break;
6947 }
6948 else if (list_append_string(rettv->vval.v_list,
6949 regmatch.startp[i],
6950 (int)(regmatch.endp[i] - regmatch.startp[i]))
6951 == FAIL)
6952 break;
6953 }
6954 }
6955 else if (type == 2)
6956 {
6957 /* return matched string */
6958 if (l != NULL)
6959 copy_tv(&li->li_tv, rettv);
6960 else
6961 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
6962 (int)(regmatch.endp[0] - regmatch.startp[0]));
6963 }
6964 else if (l != NULL)
6965 rettv->vval.v_number = idx;
6966 else
6967 {
6968 if (type != 0)
6969 rettv->vval.v_number =
6970 (varnumber_T)(regmatch.startp[0] - str);
6971 else
6972 rettv->vval.v_number =
6973 (varnumber_T)(regmatch.endp[0] - str);
6974 rettv->vval.v_number += (varnumber_T)(str - expr);
6975 }
6976 }
6977 vim_regfree(regmatch.regprog);
6978 }
6979
6980 if (type == 4 && l == NULL)
6981 /* matchstrpos() without a list: drop the second item. */
6982 listitem_remove(rettv->vval.v_list,
6983 rettv->vval.v_list->lv_first->li_next);
6984
6985theend:
6986 vim_free(tofree);
6987 p_cpo = save_cpo;
6988}
6989
6990/*
6991 * "match()" function
6992 */
6993 static void
6994f_match(typval_T *argvars, typval_T *rettv)
6995{
6996 find_some_match(argvars, rettv, 1);
6997}
6998
6999/*
7000 * "matchadd()" function
7001 */
7002 static void
7003f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7004{
7005#ifdef FEAT_SEARCH_EXTRA
7006 char_u buf[NUMBUFLEN];
7007 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */
7008 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
7009 int prio = 10; /* default priority */
7010 int id = -1;
7011 int error = FALSE;
7012 char_u *conceal_char = NULL;
7013
7014 rettv->vval.v_number = -1;
7015
7016 if (grp == NULL || pat == NULL)
7017 return;
7018 if (argvars[2].v_type != VAR_UNKNOWN)
7019 {
7020 prio = (int)get_tv_number_chk(&argvars[2], &error);
7021 if (argvars[3].v_type != VAR_UNKNOWN)
7022 {
7023 id = (int)get_tv_number_chk(&argvars[3], &error);
7024 if (argvars[4].v_type != VAR_UNKNOWN)
7025 {
7026 if (argvars[4].v_type != VAR_DICT)
7027 {
7028 EMSG(_(e_dictreq));
7029 return;
7030 }
7031 if (dict_find(argvars[4].vval.v_dict,
7032 (char_u *)"conceal", -1) != NULL)
7033 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7034 (char_u *)"conceal", FALSE);
7035 }
7036 }
7037 }
7038 if (error == TRUE)
7039 return;
7040 if (id >= 1 && id <= 3)
7041 {
7042 EMSGN("E798: ID is reserved for \":match\": %ld", id);
7043 return;
7044 }
7045
7046 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
7047 conceal_char);
7048#endif
7049}
7050
7051/*
7052 * "matchaddpos()" function
7053 */
7054 static void
7055f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7056{
7057#ifdef FEAT_SEARCH_EXTRA
7058 char_u buf[NUMBUFLEN];
7059 char_u *group;
7060 int prio = 10;
7061 int id = -1;
7062 int error = FALSE;
7063 list_T *l;
7064 char_u *conceal_char = NULL;
7065
7066 rettv->vval.v_number = -1;
7067
7068 group = get_tv_string_buf_chk(&argvars[0], buf);
7069 if (group == NULL)
7070 return;
7071
7072 if (argvars[1].v_type != VAR_LIST)
7073 {
7074 EMSG2(_(e_listarg), "matchaddpos()");
7075 return;
7076 }
7077 l = argvars[1].vval.v_list;
7078 if (l == NULL)
7079 return;
7080
7081 if (argvars[2].v_type != VAR_UNKNOWN)
7082 {
7083 prio = (int)get_tv_number_chk(&argvars[2], &error);
7084 if (argvars[3].v_type != VAR_UNKNOWN)
7085 {
7086 id = (int)get_tv_number_chk(&argvars[3], &error);
7087 if (argvars[4].v_type != VAR_UNKNOWN)
7088 {
7089 if (argvars[4].v_type != VAR_DICT)
7090 {
7091 EMSG(_(e_dictreq));
7092 return;
7093 }
7094 if (dict_find(argvars[4].vval.v_dict,
7095 (char_u *)"conceal", -1) != NULL)
7096 conceal_char = get_dict_string(argvars[4].vval.v_dict,
7097 (char_u *)"conceal", FALSE);
7098 }
7099 }
7100 }
7101 if (error == TRUE)
7102 return;
7103
7104 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
7105 if (id == 1 || id == 2)
7106 {
7107 EMSGN("E798: ID is reserved for \":match\": %ld", id);
7108 return;
7109 }
7110
7111 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
7112 conceal_char);
7113#endif
7114}
7115
7116/*
7117 * "matcharg()" function
7118 */
7119 static void
7120f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
7121{
7122 if (rettv_list_alloc(rettv) == OK)
7123 {
7124#ifdef FEAT_SEARCH_EXTRA
7125 int id = (int)get_tv_number(&argvars[0]);
7126 matchitem_T *m;
7127
7128 if (id >= 1 && id <= 3)
7129 {
7130 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
7131 {
7132 list_append_string(rettv->vval.v_list,
7133 syn_id2name(m->hlg_id), -1);
7134 list_append_string(rettv->vval.v_list, m->pattern, -1);
7135 }
7136 else
7137 {
7138 list_append_string(rettv->vval.v_list, NULL, -1);
7139 list_append_string(rettv->vval.v_list, NULL, -1);
7140 }
7141 }
7142#endif
7143 }
7144}
7145
7146/*
7147 * "matchdelete()" function
7148 */
7149 static void
7150f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7151{
7152#ifdef FEAT_SEARCH_EXTRA
7153 rettv->vval.v_number = match_delete(curwin,
7154 (int)get_tv_number(&argvars[0]), TRUE);
7155#endif
7156}
7157
7158/*
7159 * "matchend()" function
7160 */
7161 static void
7162f_matchend(typval_T *argvars, typval_T *rettv)
7163{
7164 find_some_match(argvars, rettv, 0);
7165}
7166
7167/*
7168 * "matchlist()" function
7169 */
7170 static void
7171f_matchlist(typval_T *argvars, typval_T *rettv)
7172{
7173 find_some_match(argvars, rettv, 3);
7174}
7175
7176/*
7177 * "matchstr()" function
7178 */
7179 static void
7180f_matchstr(typval_T *argvars, typval_T *rettv)
7181{
7182 find_some_match(argvars, rettv, 2);
7183}
7184
7185/*
7186 * "matchstrpos()" function
7187 */
7188 static void
7189f_matchstrpos(typval_T *argvars, typval_T *rettv)
7190{
7191 find_some_match(argvars, rettv, 4);
7192}
7193
7194static void max_min(typval_T *argvars, typval_T *rettv, int domax);
7195
7196 static void
7197max_min(typval_T *argvars, typval_T *rettv, int domax)
7198{
7199 varnumber_T n = 0;
7200 varnumber_T i;
7201 int error = FALSE;
7202
7203 if (argvars[0].v_type == VAR_LIST)
7204 {
7205 list_T *l;
7206 listitem_T *li;
7207
7208 l = argvars[0].vval.v_list;
7209 if (l != NULL)
7210 {
7211 li = l->lv_first;
7212 if (li != NULL)
7213 {
7214 n = get_tv_number_chk(&li->li_tv, &error);
7215 for (;;)
7216 {
7217 li = li->li_next;
7218 if (li == NULL)
7219 break;
7220 i = get_tv_number_chk(&li->li_tv, &error);
7221 if (domax ? i > n : i < n)
7222 n = i;
7223 }
7224 }
7225 }
7226 }
7227 else if (argvars[0].v_type == VAR_DICT)
7228 {
7229 dict_T *d;
7230 int first = TRUE;
7231 hashitem_T *hi;
7232 int todo;
7233
7234 d = argvars[0].vval.v_dict;
7235 if (d != NULL)
7236 {
7237 todo = (int)d->dv_hashtab.ht_used;
7238 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7239 {
7240 if (!HASHITEM_EMPTY(hi))
7241 {
7242 --todo;
7243 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error);
7244 if (first)
7245 {
7246 n = i;
7247 first = FALSE;
7248 }
7249 else if (domax ? i > n : i < n)
7250 n = i;
7251 }
7252 }
7253 }
7254 }
7255 else
7256 EMSG(_(e_listdictarg));
7257 rettv->vval.v_number = error ? 0 : n;
7258}
7259
7260/*
7261 * "max()" function
7262 */
7263 static void
7264f_max(typval_T *argvars, typval_T *rettv)
7265{
7266 max_min(argvars, rettv, TRUE);
7267}
7268
7269/*
7270 * "min()" function
7271 */
7272 static void
7273f_min(typval_T *argvars, typval_T *rettv)
7274{
7275 max_min(argvars, rettv, FALSE);
7276}
7277
7278static int mkdir_recurse(char_u *dir, int prot);
7279
7280/*
7281 * Create the directory in which "dir" is located, and higher levels when
7282 * needed.
7283 */
7284 static int
7285mkdir_recurse(char_u *dir, int prot)
7286{
7287 char_u *p;
7288 char_u *updir;
7289 int r = FAIL;
7290
7291 /* Get end of directory name in "dir".
7292 * We're done when it's "/" or "c:/". */
7293 p = gettail_sep(dir);
7294 if (p <= get_past_head(dir))
7295 return OK;
7296
7297 /* If the directory exists we're done. Otherwise: create it.*/
7298 updir = vim_strnsave(dir, (int)(p - dir));
7299 if (updir == NULL)
7300 return FAIL;
7301 if (mch_isdir(updir))
7302 r = OK;
7303 else if (mkdir_recurse(updir, prot) == OK)
7304 r = vim_mkdir_emsg(updir, prot);
7305 vim_free(updir);
7306 return r;
7307}
7308
7309#ifdef vim_mkdir
7310/*
7311 * "mkdir()" function
7312 */
7313 static void
7314f_mkdir(typval_T *argvars, typval_T *rettv)
7315{
7316 char_u *dir;
7317 char_u buf[NUMBUFLEN];
7318 int prot = 0755;
7319
7320 rettv->vval.v_number = FAIL;
7321 if (check_restricted() || check_secure())
7322 return;
7323
7324 dir = get_tv_string_buf(&argvars[0], buf);
7325 if (*dir == NUL)
7326 rettv->vval.v_number = FAIL;
7327 else
7328 {
7329 if (*gettail(dir) == NUL)
7330 /* remove trailing slashes */
7331 *gettail_sep(dir) = NUL;
7332
7333 if (argvars[1].v_type != VAR_UNKNOWN)
7334 {
7335 if (argvars[2].v_type != VAR_UNKNOWN)
7336 prot = (int)get_tv_number_chk(&argvars[2], NULL);
7337 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0)
7338 mkdir_recurse(dir, prot);
7339 }
7340 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot);
7341 }
7342}
7343#endif
7344
7345/*
7346 * "mode()" function
7347 */
7348 static void
7349f_mode(typval_T *argvars, typval_T *rettv)
7350{
7351 char_u buf[3];
7352
7353 buf[1] = NUL;
7354 buf[2] = NUL;
7355
7356 if (time_for_testing == 93784)
7357 {
7358 /* Testing the two-character code. */
7359 buf[0] = 'x';
7360 buf[1] = '!';
7361 }
7362 else if (VIsual_active)
7363 {
7364 if (VIsual_select)
7365 buf[0] = VIsual_mode + 's' - 'v';
7366 else
7367 buf[0] = VIsual_mode;
7368 }
7369 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7370 || State == CONFIRM)
7371 {
7372 buf[0] = 'r';
7373 if (State == ASKMORE)
7374 buf[1] = 'm';
7375 else if (State == CONFIRM)
7376 buf[1] = '?';
7377 }
7378 else if (State == EXTERNCMD)
7379 buf[0] = '!';
7380 else if (State & INSERT)
7381 {
7382#ifdef FEAT_VREPLACE
7383 if (State & VREPLACE_FLAG)
7384 {
7385 buf[0] = 'R';
7386 buf[1] = 'v';
7387 }
7388 else
7389#endif
7390 if (State & REPLACE_FLAG)
7391 buf[0] = 'R';
7392 else
7393 buf[0] = 'i';
7394 }
7395 else if (State & CMDLINE)
7396 {
7397 buf[0] = 'c';
7398 if (exmode_active)
7399 buf[1] = 'v';
7400 }
7401 else if (exmode_active)
7402 {
7403 buf[0] = 'c';
7404 buf[1] = 'e';
7405 }
7406 else
7407 {
7408 buf[0] = 'n';
7409 if (finish_op)
7410 buf[1] = 'o';
7411 }
7412
7413 /* Clear out the minor mode when the argument is not a non-zero number or
7414 * non-empty string. */
7415 if (!non_zero_arg(&argvars[0]))
7416 buf[1] = NUL;
7417
7418 rettv->vval.v_string = vim_strsave(buf);
7419 rettv->v_type = VAR_STRING;
7420}
7421
7422#if defined(FEAT_MZSCHEME) || defined(PROTO)
7423/*
7424 * "mzeval()" function
7425 */
7426 static void
7427f_mzeval(typval_T *argvars, typval_T *rettv)
7428{
7429 char_u *str;
7430 char_u buf[NUMBUFLEN];
7431
7432 str = get_tv_string_buf(&argvars[0], buf);
7433 do_mzeval(str, rettv);
7434}
7435
7436 void
7437mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7438{
7439 typval_T argvars[3];
7440
7441 argvars[0].v_type = VAR_STRING;
7442 argvars[0].vval.v_string = name;
7443 copy_tv(args, &argvars[1]);
7444 argvars[2].v_type = VAR_UNKNOWN;
7445 f_call(argvars, rettv);
7446 clear_tv(&argvars[1]);
7447}
7448#endif
7449
7450/*
7451 * "nextnonblank()" function
7452 */
7453 static void
7454f_nextnonblank(typval_T *argvars, typval_T *rettv)
7455{
7456 linenr_T lnum;
7457
7458 for (lnum = get_tv_lnum(argvars); ; ++lnum)
7459 {
7460 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7461 {
7462 lnum = 0;
7463 break;
7464 }
7465 if (*skipwhite(ml_get(lnum)) != NUL)
7466 break;
7467 }
7468 rettv->vval.v_number = lnum;
7469}
7470
7471/*
7472 * "nr2char()" function
7473 */
7474 static void
7475f_nr2char(typval_T *argvars, typval_T *rettv)
7476{
7477 char_u buf[NUMBUFLEN];
7478
7479#ifdef FEAT_MBYTE
7480 if (has_mbyte)
7481 {
7482 int utf8 = 0;
7483
7484 if (argvars[1].v_type != VAR_UNKNOWN)
7485 utf8 = (int)get_tv_number_chk(&argvars[1], NULL);
7486 if (utf8)
7487 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7488 else
7489 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL;
7490 }
7491 else
7492#endif
7493 {
7494 buf[0] = (char_u)get_tv_number(&argvars[0]);
7495 buf[1] = NUL;
7496 }
7497 rettv->v_type = VAR_STRING;
7498 rettv->vval.v_string = vim_strsave(buf);
7499}
7500
7501/*
7502 * "or(expr, expr)" function
7503 */
7504 static void
7505f_or(typval_T *argvars, typval_T *rettv)
7506{
7507 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
7508 | get_tv_number_chk(&argvars[1], NULL);
7509}
7510
7511/*
7512 * "pathshorten()" function
7513 */
7514 static void
7515f_pathshorten(typval_T *argvars, typval_T *rettv)
7516{
7517 char_u *p;
7518
7519 rettv->v_type = VAR_STRING;
7520 p = get_tv_string_chk(&argvars[0]);
7521 if (p == NULL)
7522 rettv->vval.v_string = NULL;
7523 else
7524 {
7525 p = vim_strsave(p);
7526 rettv->vval.v_string = p;
7527 if (p != NULL)
7528 shorten_dir(p);
7529 }
7530}
7531
7532#ifdef FEAT_PERL
7533/*
7534 * "perleval()" function
7535 */
7536 static void
7537f_perleval(typval_T *argvars, typval_T *rettv)
7538{
7539 char_u *str;
7540 char_u buf[NUMBUFLEN];
7541
7542 str = get_tv_string_buf(&argvars[0], buf);
7543 do_perleval(str, rettv);
7544}
7545#endif
7546
7547#ifdef FEAT_FLOAT
7548/*
7549 * "pow()" function
7550 */
7551 static void
7552f_pow(typval_T *argvars, typval_T *rettv)
7553{
7554 float_T fx = 0.0, fy = 0.0;
7555
7556 rettv->v_type = VAR_FLOAT;
7557 if (get_float_arg(argvars, &fx) == OK
7558 && get_float_arg(&argvars[1], &fy) == OK)
7559 rettv->vval.v_float = pow(fx, fy);
7560 else
7561 rettv->vval.v_float = 0.0;
7562}
7563#endif
7564
7565/*
7566 * "prevnonblank()" function
7567 */
7568 static void
7569f_prevnonblank(typval_T *argvars, typval_T *rettv)
7570{
7571 linenr_T lnum;
7572
7573 lnum = get_tv_lnum(argvars);
7574 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7575 lnum = 0;
7576 else
7577 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7578 --lnum;
7579 rettv->vval.v_number = lnum;
7580}
7581
7582/* This dummy va_list is here because:
7583 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7584 * - locally in the function results in a "used before set" warning
7585 * - using va_start() to initialize it gives "function with fixed args" error */
7586static va_list ap;
7587
7588/*
7589 * "printf()" function
7590 */
7591 static void
7592f_printf(typval_T *argvars, typval_T *rettv)
7593{
7594 char_u buf[NUMBUFLEN];
7595 int len;
7596 char_u *s;
7597 int saved_did_emsg = did_emsg;
7598 char *fmt;
7599
7600 rettv->v_type = VAR_STRING;
7601 rettv->vval.v_string = NULL;
7602
7603 /* Get the required length, allocate the buffer and do it for real. */
7604 did_emsg = FALSE;
7605 fmt = (char *)get_tv_string_buf(&argvars[0], buf);
7606 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1);
7607 if (!did_emsg)
7608 {
7609 s = alloc(len + 1);
7610 if (s != NULL)
7611 {
7612 rettv->vval.v_string = s;
7613 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1);
7614 }
7615 }
7616 did_emsg |= saved_did_emsg;
7617}
7618
7619/*
7620 * "pumvisible()" function
7621 */
7622 static void
7623f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7624{
7625#ifdef FEAT_INS_EXPAND
7626 if (pum_visible())
7627 rettv->vval.v_number = 1;
7628#endif
7629}
7630
7631#ifdef FEAT_PYTHON3
7632/*
7633 * "py3eval()" function
7634 */
7635 static void
7636f_py3eval(typval_T *argvars, typval_T *rettv)
7637{
7638 char_u *str;
7639 char_u buf[NUMBUFLEN];
7640
7641 str = get_tv_string_buf(&argvars[0], buf);
7642 do_py3eval(str, rettv);
7643}
7644#endif
7645
7646#ifdef FEAT_PYTHON
7647/*
7648 * "pyeval()" function
7649 */
7650 static void
7651f_pyeval(typval_T *argvars, typval_T *rettv)
7652{
7653 char_u *str;
7654 char_u buf[NUMBUFLEN];
7655
7656 str = get_tv_string_buf(&argvars[0], buf);
7657 do_pyeval(str, rettv);
7658}
7659#endif
7660
7661/*
7662 * "range()" function
7663 */
7664 static void
7665f_range(typval_T *argvars, typval_T *rettv)
7666{
7667 varnumber_T start;
7668 varnumber_T end;
7669 varnumber_T stride = 1;
7670 varnumber_T i;
7671 int error = FALSE;
7672
7673 start = get_tv_number_chk(&argvars[0], &error);
7674 if (argvars[1].v_type == VAR_UNKNOWN)
7675 {
7676 end = start - 1;
7677 start = 0;
7678 }
7679 else
7680 {
7681 end = get_tv_number_chk(&argvars[1], &error);
7682 if (argvars[2].v_type != VAR_UNKNOWN)
7683 stride = get_tv_number_chk(&argvars[2], &error);
7684 }
7685
7686 if (error)
7687 return; /* type error; errmsg already given */
7688 if (stride == 0)
7689 EMSG(_("E726: Stride is zero"));
7690 else if (stride > 0 ? end + 1 < start : end - 1 > start)
7691 EMSG(_("E727: Start past end"));
7692 else
7693 {
7694 if (rettv_list_alloc(rettv) == OK)
7695 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7696 if (list_append_number(rettv->vval.v_list,
7697 (varnumber_T)i) == FAIL)
7698 break;
7699 }
7700}
7701
7702/*
7703 * "readfile()" function
7704 */
7705 static void
7706f_readfile(typval_T *argvars, typval_T *rettv)
7707{
7708 int binary = FALSE;
7709 int failed = FALSE;
7710 char_u *fname;
7711 FILE *fd;
7712 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
7713 int io_size = sizeof(buf);
7714 int readlen; /* size of last fread() */
7715 char_u *prev = NULL; /* previously read bytes, if any */
7716 long prevlen = 0; /* length of data in prev */
7717 long prevsize = 0; /* size of prev buffer */
7718 long maxline = MAXLNUM;
7719 long cnt = 0;
7720 char_u *p; /* position in buf */
7721 char_u *start; /* start of current line */
7722
7723 if (argvars[1].v_type != VAR_UNKNOWN)
7724 {
7725 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0)
7726 binary = TRUE;
7727 if (argvars[2].v_type != VAR_UNKNOWN)
7728 maxline = (long)get_tv_number(&argvars[2]);
7729 }
7730
7731 if (rettv_list_alloc(rettv) == FAIL)
7732 return;
7733
7734 /* Always open the file in binary mode, library functions have a mind of
7735 * their own about CR-LF conversion. */
7736 fname = get_tv_string(&argvars[0]);
7737 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
7738 {
7739 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
7740 return;
7741 }
7742
7743 while (cnt < maxline || maxline < 0)
7744 {
7745 readlen = (int)fread(buf, 1, io_size, fd);
7746
7747 /* This for loop processes what was read, but is also entered at end
7748 * of file so that either:
7749 * - an incomplete line gets written
7750 * - a "binary" file gets an empty line at the end if it ends in a
7751 * newline. */
7752 for (p = buf, start = buf;
7753 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
7754 ++p)
7755 {
7756 if (*p == '\n' || readlen <= 0)
7757 {
7758 listitem_T *li;
7759 char_u *s = NULL;
7760 long_u len = p - start;
7761
7762 /* Finished a line. Remove CRs before NL. */
7763 if (readlen > 0 && !binary)
7764 {
7765 while (len > 0 && start[len - 1] == '\r')
7766 --len;
7767 /* removal may cross back to the "prev" string */
7768 if (len == 0)
7769 while (prevlen > 0 && prev[prevlen - 1] == '\r')
7770 --prevlen;
7771 }
7772 if (prevlen == 0)
7773 s = vim_strnsave(start, (int)len);
7774 else
7775 {
7776 /* Change "prev" buffer to be the right size. This way
7777 * the bytes are only copied once, and very long lines are
7778 * allocated only once. */
7779 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
7780 {
7781 mch_memmove(s + prevlen, start, len);
7782 s[prevlen + len] = NUL;
7783 prev = NULL; /* the list will own the string */
7784 prevlen = prevsize = 0;
7785 }
7786 }
7787 if (s == NULL)
7788 {
7789 do_outofmem_msg((long_u) prevlen + len + 1);
7790 failed = TRUE;
7791 break;
7792 }
7793
7794 if ((li = listitem_alloc()) == NULL)
7795 {
7796 vim_free(s);
7797 failed = TRUE;
7798 break;
7799 }
7800 li->li_tv.v_type = VAR_STRING;
7801 li->li_tv.v_lock = 0;
7802 li->li_tv.vval.v_string = s;
7803 list_append(rettv->vval.v_list, li);
7804
7805 start = p + 1; /* step over newline */
7806 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
7807 break;
7808 }
7809 else if (*p == NUL)
7810 *p = '\n';
7811#ifdef FEAT_MBYTE
7812 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
7813 * when finding the BF and check the previous two bytes. */
7814 else if (*p == 0xbf && enc_utf8 && !binary)
7815 {
7816 /* Find the two bytes before the 0xbf. If p is at buf, or buf
7817 * + 1, these may be in the "prev" string. */
7818 char_u back1 = p >= buf + 1 ? p[-1]
7819 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
7820 char_u back2 = p >= buf + 2 ? p[-2]
7821 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
7822 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
7823
7824 if (back2 == 0xef && back1 == 0xbb)
7825 {
7826 char_u *dest = p - 2;
7827
7828 /* Usually a BOM is at the beginning of a file, and so at
7829 * the beginning of a line; then we can just step over it.
7830 */
7831 if (start == dest)
7832 start = p + 1;
7833 else
7834 {
7835 /* have to shuffle buf to close gap */
7836 int adjust_prevlen = 0;
7837
7838 if (dest < buf)
7839 {
7840 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
7841 dest = buf;
7842 }
7843 if (readlen > p - buf + 1)
7844 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
7845 readlen -= 3 - adjust_prevlen;
7846 prevlen -= adjust_prevlen;
7847 p = dest - 1;
7848 }
7849 }
7850 }
7851#endif
7852 } /* for */
7853
7854 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
7855 break;
7856 if (start < p)
7857 {
7858 /* There's part of a line in buf, store it in "prev". */
7859 if (p - start + prevlen >= prevsize)
7860 {
7861 /* need bigger "prev" buffer */
7862 char_u *newprev;
7863
7864 /* A common use case is ordinary text files and "prev" gets a
7865 * fragment of a line, so the first allocation is made
7866 * small, to avoid repeatedly 'allocing' large and
7867 * 'reallocing' small. */
7868 if (prevsize == 0)
7869 prevsize = (long)(p - start);
7870 else
7871 {
7872 long grow50pc = (prevsize * 3) / 2;
7873 long growmin = (long)((p - start) * 2 + prevlen);
7874 prevsize = grow50pc > growmin ? grow50pc : growmin;
7875 }
7876 newprev = prev == NULL ? alloc(prevsize)
7877 : vim_realloc(prev, prevsize);
7878 if (newprev == NULL)
7879 {
7880 do_outofmem_msg((long_u)prevsize);
7881 failed = TRUE;
7882 break;
7883 }
7884 prev = newprev;
7885 }
7886 /* Add the line part to end of "prev". */
7887 mch_memmove(prev + prevlen, start, p - start);
7888 prevlen += (long)(p - start);
7889 }
7890 } /* while */
7891
7892 /*
7893 * For a negative line count use only the lines at the end of the file,
7894 * free the rest.
7895 */
7896 if (!failed && maxline < 0)
7897 while (cnt > -maxline)
7898 {
7899 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
7900 --cnt;
7901 }
7902
7903 if (failed)
7904 {
7905 list_free(rettv->vval.v_list);
7906 /* readfile doc says an empty list is returned on error */
7907 rettv->vval.v_list = list_alloc();
7908 }
7909
7910 vim_free(prev);
7911 fclose(fd);
7912}
7913
7914#if defined(FEAT_RELTIME)
7915static int list2proftime(typval_T *arg, proftime_T *tm);
7916
7917/*
7918 * Convert a List to proftime_T.
7919 * Return FAIL when there is something wrong.
7920 */
7921 static int
7922list2proftime(typval_T *arg, proftime_T *tm)
7923{
7924 long n1, n2;
7925 int error = FALSE;
7926
7927 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
7928 || arg->vval.v_list->lv_len != 2)
7929 return FAIL;
7930 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
7931 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
7932# ifdef WIN3264
7933 tm->HighPart = n1;
7934 tm->LowPart = n2;
7935# else
7936 tm->tv_sec = n1;
7937 tm->tv_usec = n2;
7938# endif
7939 return error ? FAIL : OK;
7940}
7941#endif /* FEAT_RELTIME */
7942
7943/*
7944 * "reltime()" function
7945 */
7946 static void
7947f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7948{
7949#ifdef FEAT_RELTIME
7950 proftime_T res;
7951 proftime_T start;
7952
7953 if (argvars[0].v_type == VAR_UNKNOWN)
7954 {
7955 /* No arguments: get current time. */
7956 profile_start(&res);
7957 }
7958 else if (argvars[1].v_type == VAR_UNKNOWN)
7959 {
7960 if (list2proftime(&argvars[0], &res) == FAIL)
7961 return;
7962 profile_end(&res);
7963 }
7964 else
7965 {
7966 /* Two arguments: compute the difference. */
7967 if (list2proftime(&argvars[0], &start) == FAIL
7968 || list2proftime(&argvars[1], &res) == FAIL)
7969 return;
7970 profile_sub(&res, &start);
7971 }
7972
7973 if (rettv_list_alloc(rettv) == OK)
7974 {
7975 long n1, n2;
7976
7977# ifdef WIN3264
7978 n1 = res.HighPart;
7979 n2 = res.LowPart;
7980# else
7981 n1 = res.tv_sec;
7982 n2 = res.tv_usec;
7983# endif
7984 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
7985 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
7986 }
7987#endif
7988}
7989
7990#ifdef FEAT_FLOAT
7991/*
7992 * "reltimefloat()" function
7993 */
7994 static void
7995f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
7996{
7997# ifdef FEAT_RELTIME
7998 proftime_T tm;
7999# endif
8000
8001 rettv->v_type = VAR_FLOAT;
8002 rettv->vval.v_float = 0;
8003# ifdef FEAT_RELTIME
8004 if (list2proftime(&argvars[0], &tm) == OK)
8005 rettv->vval.v_float = profile_float(&tm);
8006# endif
8007}
8008#endif
8009
8010/*
8011 * "reltimestr()" function
8012 */
8013 static void
8014f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8015{
8016#ifdef FEAT_RELTIME
8017 proftime_T tm;
8018#endif
8019
8020 rettv->v_type = VAR_STRING;
8021 rettv->vval.v_string = NULL;
8022#ifdef FEAT_RELTIME
8023 if (list2proftime(&argvars[0], &tm) == OK)
8024 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8025#endif
8026}
8027
8028#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
8029static void make_connection(void);
8030static int check_connection(void);
8031
8032 static void
8033make_connection(void)
8034{
8035 if (X_DISPLAY == NULL
8036# ifdef FEAT_GUI
8037 && !gui.in_use
8038# endif
8039 )
8040 {
8041 x_force_connect = TRUE;
8042 setup_term_clip();
8043 x_force_connect = FALSE;
8044 }
8045}
8046
8047 static int
8048check_connection(void)
8049{
8050 make_connection();
8051 if (X_DISPLAY == NULL)
8052 {
8053 EMSG(_("E240: No connection to Vim server"));
8054 return FAIL;
8055 }
8056 return OK;
8057}
8058#endif
8059
8060#ifdef FEAT_CLIENTSERVER
8061 static void
8062remote_common(typval_T *argvars, typval_T *rettv, int expr)
8063{
8064 char_u *server_name;
8065 char_u *keys;
8066 char_u *r = NULL;
8067 char_u buf[NUMBUFLEN];
8068# ifdef WIN32
8069 HWND w;
8070# else
8071 Window w;
8072# endif
8073
8074 if (check_restricted() || check_secure())
8075 return;
8076
8077# ifdef FEAT_X11
8078 if (check_connection() == FAIL)
8079 return;
8080# endif
8081
8082 server_name = get_tv_string_chk(&argvars[0]);
8083 if (server_name == NULL)
8084 return; /* type error; errmsg already given */
8085 keys = get_tv_string_buf(&argvars[1], buf);
8086# ifdef WIN32
8087 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
8088# else
8089 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
8090 < 0)
8091# endif
8092 {
8093 if (r != NULL)
8094 EMSG(r); /* sending worked but evaluation failed */
8095 else
8096 EMSG2(_("E241: Unable to send to %s"), server_name);
8097 return;
8098 }
8099
8100 rettv->vval.v_string = r;
8101
8102 if (argvars[2].v_type != VAR_UNKNOWN)
8103 {
8104 dictitem_T v;
8105 char_u str[30];
8106 char_u *idvar;
8107
8108 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8109 v.di_tv.v_type = VAR_STRING;
8110 v.di_tv.vval.v_string = vim_strsave(str);
8111 idvar = get_tv_string_chk(&argvars[2]);
8112 if (idvar != NULL)
8113 set_var(idvar, &v.di_tv, FALSE);
8114 vim_free(v.di_tv.vval.v_string);
8115 }
8116}
8117#endif
8118
8119/*
8120 * "remote_expr()" function
8121 */
8122 static void
8123f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8124{
8125 rettv->v_type = VAR_STRING;
8126 rettv->vval.v_string = NULL;
8127#ifdef FEAT_CLIENTSERVER
8128 remote_common(argvars, rettv, TRUE);
8129#endif
8130}
8131
8132/*
8133 * "remote_foreground()" function
8134 */
8135 static void
8136f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8137{
8138#ifdef FEAT_CLIENTSERVER
8139# ifdef WIN32
8140 /* On Win32 it's done in this application. */
8141 {
8142 char_u *server_name = get_tv_string_chk(&argvars[0]);
8143
8144 if (server_name != NULL)
8145 serverForeground(server_name);
8146 }
8147# else
8148 /* Send a foreground() expression to the server. */
8149 argvars[1].v_type = VAR_STRING;
8150 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8151 argvars[2].v_type = VAR_UNKNOWN;
8152 remote_common(argvars, rettv, TRUE);
8153 vim_free(argvars[1].vval.v_string);
8154# endif
8155#endif
8156}
8157
8158 static void
8159f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8160{
8161#ifdef FEAT_CLIENTSERVER
8162 dictitem_T v;
8163 char_u *s = NULL;
8164# ifdef WIN32
8165 long_u n = 0;
8166# endif
8167 char_u *serverid;
8168
8169 if (check_restricted() || check_secure())
8170 {
8171 rettv->vval.v_number = -1;
8172 return;
8173 }
8174 serverid = get_tv_string_chk(&argvars[0]);
8175 if (serverid == NULL)
8176 {
8177 rettv->vval.v_number = -1;
8178 return; /* type error; errmsg already given */
8179 }
8180# ifdef WIN32
8181 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8182 if (n == 0)
8183 rettv->vval.v_number = -1;
8184 else
8185 {
8186 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
8187 rettv->vval.v_number = (s != NULL);
8188 }
8189# else
8190 if (check_connection() == FAIL)
8191 return;
8192
8193 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8194 serverStrToWin(serverid), &s);
8195# endif
8196
8197 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8198 {
8199 char_u *retvar;
8200
8201 v.di_tv.v_type = VAR_STRING;
8202 v.di_tv.vval.v_string = vim_strsave(s);
8203 retvar = get_tv_string_chk(&argvars[1]);
8204 if (retvar != NULL)
8205 set_var(retvar, &v.di_tv, FALSE);
8206 vim_free(v.di_tv.vval.v_string);
8207 }
8208#else
8209 rettv->vval.v_number = -1;
8210#endif
8211}
8212
8213 static void
8214f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8215{
8216 char_u *r = NULL;
8217
8218#ifdef FEAT_CLIENTSERVER
8219 char_u *serverid = get_tv_string_chk(&argvars[0]);
8220
8221 if (serverid != NULL && !check_restricted() && !check_secure())
8222 {
8223# ifdef WIN32
8224 /* The server's HWND is encoded in the 'id' parameter */
8225 long_u n = 0;
8226
8227 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8228 if (n != 0)
8229 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
8230 if (r == NULL)
8231# else
8232 if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
8233 serverStrToWin(serverid), &r, FALSE) < 0)
8234# endif
8235 EMSG(_("E277: Unable to read a server reply"));
8236 }
8237#endif
8238 rettv->v_type = VAR_STRING;
8239 rettv->vval.v_string = r;
8240}
8241
8242/*
8243 * "remote_send()" function
8244 */
8245 static void
8246f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8247{
8248 rettv->v_type = VAR_STRING;
8249 rettv->vval.v_string = NULL;
8250#ifdef FEAT_CLIENTSERVER
8251 remote_common(argvars, rettv, FALSE);
8252#endif
8253}
8254
8255/*
8256 * "remove()" function
8257 */
8258 static void
8259f_remove(typval_T *argvars, typval_T *rettv)
8260{
8261 list_T *l;
8262 listitem_T *item, *item2;
8263 listitem_T *li;
8264 long idx;
8265 long end;
8266 char_u *key;
8267 dict_T *d;
8268 dictitem_T *di;
8269 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8270
8271 if (argvars[0].v_type == VAR_DICT)
8272 {
8273 if (argvars[2].v_type != VAR_UNKNOWN)
8274 EMSG2(_(e_toomanyarg), "remove()");
8275 else if ((d = argvars[0].vval.v_dict) != NULL
8276 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE))
8277 {
8278 key = get_tv_string_chk(&argvars[1]);
8279 if (key != NULL)
8280 {
8281 di = dict_find(d, key, -1);
8282 if (di == NULL)
8283 EMSG2(_(e_dictkey), key);
8284 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
8285 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
8286 {
8287 *rettv = di->di_tv;
8288 init_tv(&di->di_tv);
8289 dictitem_remove(d, di);
8290 }
8291 }
8292 }
8293 }
8294 else if (argvars[0].v_type != VAR_LIST)
8295 EMSG2(_(e_listdictarg), "remove()");
8296 else if ((l = argvars[0].vval.v_list) != NULL
8297 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE))
8298 {
8299 int error = FALSE;
8300
8301 idx = (long)get_tv_number_chk(&argvars[1], &error);
8302 if (error)
8303 ; /* type error: do nothing, errmsg already given */
8304 else if ((item = list_find(l, idx)) == NULL)
8305 EMSGN(_(e_listidx), idx);
8306 else
8307 {
8308 if (argvars[2].v_type == VAR_UNKNOWN)
8309 {
8310 /* Remove one item, return its value. */
8311 vimlist_remove(l, item, item);
8312 *rettv = item->li_tv;
8313 vim_free(item);
8314 }
8315 else
8316 {
8317 /* Remove range of items, return list with values. */
8318 end = (long)get_tv_number_chk(&argvars[2], &error);
8319 if (error)
8320 ; /* type error: do nothing */
8321 else if ((item2 = list_find(l, end)) == NULL)
8322 EMSGN(_(e_listidx), end);
8323 else
8324 {
8325 int cnt = 0;
8326
8327 for (li = item; li != NULL; li = li->li_next)
8328 {
8329 ++cnt;
8330 if (li == item2)
8331 break;
8332 }
8333 if (li == NULL) /* didn't find "item2" after "item" */
8334 EMSG(_(e_invrange));
8335 else
8336 {
8337 vimlist_remove(l, item, item2);
8338 if (rettv_list_alloc(rettv) == OK)
8339 {
8340 l = rettv->vval.v_list;
8341 l->lv_first = item;
8342 l->lv_last = item2;
8343 item->li_prev = NULL;
8344 item2->li_next = NULL;
8345 l->lv_len = cnt;
8346 }
8347 }
8348 }
8349 }
8350 }
8351 }
8352}
8353
8354/*
8355 * "rename({from}, {to})" function
8356 */
8357 static void
8358f_rename(typval_T *argvars, typval_T *rettv)
8359{
8360 char_u buf[NUMBUFLEN];
8361
8362 if (check_restricted() || check_secure())
8363 rettv->vval.v_number = -1;
8364 else
8365 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]),
8366 get_tv_string_buf(&argvars[1], buf));
8367}
8368
8369/*
8370 * "repeat()" function
8371 */
8372 static void
8373f_repeat(typval_T *argvars, typval_T *rettv)
8374{
8375 char_u *p;
8376 int n;
8377 int slen;
8378 int len;
8379 char_u *r;
8380 int i;
8381
8382 n = (int)get_tv_number(&argvars[1]);
8383 if (argvars[0].v_type == VAR_LIST)
8384 {
8385 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8386 while (n-- > 0)
8387 if (list_extend(rettv->vval.v_list,
8388 argvars[0].vval.v_list, NULL) == FAIL)
8389 break;
8390 }
8391 else
8392 {
8393 p = get_tv_string(&argvars[0]);
8394 rettv->v_type = VAR_STRING;
8395 rettv->vval.v_string = NULL;
8396
8397 slen = (int)STRLEN(p);
8398 len = slen * n;
8399 if (len <= 0)
8400 return;
8401
8402 r = alloc(len + 1);
8403 if (r != NULL)
8404 {
8405 for (i = 0; i < n; i++)
8406 mch_memmove(r + i * slen, p, (size_t)slen);
8407 r[len] = NUL;
8408 }
8409
8410 rettv->vval.v_string = r;
8411 }
8412}
8413
8414/*
8415 * "resolve()" function
8416 */
8417 static void
8418f_resolve(typval_T *argvars, typval_T *rettv)
8419{
8420 char_u *p;
8421#ifdef HAVE_READLINK
8422 char_u *buf = NULL;
8423#endif
8424
8425 p = get_tv_string(&argvars[0]);
8426#ifdef FEAT_SHORTCUT
8427 {
8428 char_u *v = NULL;
8429
8430 v = mch_resolve_shortcut(p);
8431 if (v != NULL)
8432 rettv->vval.v_string = v;
8433 else
8434 rettv->vval.v_string = vim_strsave(p);
8435 }
8436#else
8437# ifdef HAVE_READLINK
8438 {
8439 char_u *cpy;
8440 int len;
8441 char_u *remain = NULL;
8442 char_u *q;
8443 int is_relative_to_current = FALSE;
8444 int has_trailing_pathsep = FALSE;
8445 int limit = 100;
8446
8447 p = vim_strsave(p);
8448
8449 if (p[0] == '.' && (vim_ispathsep(p[1])
8450 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8451 is_relative_to_current = TRUE;
8452
8453 len = STRLEN(p);
8454 if (len > 0 && after_pathsep(p, p + len))
8455 {
8456 has_trailing_pathsep = TRUE;
8457 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8458 }
8459
8460 q = getnextcomp(p);
8461 if (*q != NUL)
8462 {
8463 /* Separate the first path component in "p", and keep the
8464 * remainder (beginning with the path separator). */
8465 remain = vim_strsave(q - 1);
8466 q[-1] = NUL;
8467 }
8468
8469 buf = alloc(MAXPATHL + 1);
8470 if (buf == NULL)
8471 goto fail;
8472
8473 for (;;)
8474 {
8475 for (;;)
8476 {
8477 len = readlink((char *)p, (char *)buf, MAXPATHL);
8478 if (len <= 0)
8479 break;
8480 buf[len] = NUL;
8481
8482 if (limit-- == 0)
8483 {
8484 vim_free(p);
8485 vim_free(remain);
8486 EMSG(_("E655: Too many symbolic links (cycle?)"));
8487 rettv->vval.v_string = NULL;
8488 goto fail;
8489 }
8490
8491 /* Ensure that the result will have a trailing path separator
8492 * if the argument has one. */
8493 if (remain == NULL && has_trailing_pathsep)
8494 add_pathsep(buf);
8495
8496 /* Separate the first path component in the link value and
8497 * concatenate the remainders. */
8498 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8499 if (*q != NUL)
8500 {
8501 if (remain == NULL)
8502 remain = vim_strsave(q - 1);
8503 else
8504 {
8505 cpy = concat_str(q - 1, remain);
8506 if (cpy != NULL)
8507 {
8508 vim_free(remain);
8509 remain = cpy;
8510 }
8511 }
8512 q[-1] = NUL;
8513 }
8514
8515 q = gettail(p);
8516 if (q > p && *q == NUL)
8517 {
8518 /* Ignore trailing path separator. */
8519 q[-1] = NUL;
8520 q = gettail(p);
8521 }
8522 if (q > p && !mch_isFullName(buf))
8523 {
8524 /* symlink is relative to directory of argument */
8525 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
8526 if (cpy != NULL)
8527 {
8528 STRCPY(cpy, p);
8529 STRCPY(gettail(cpy), buf);
8530 vim_free(p);
8531 p = cpy;
8532 }
8533 }
8534 else
8535 {
8536 vim_free(p);
8537 p = vim_strsave(buf);
8538 }
8539 }
8540
8541 if (remain == NULL)
8542 break;
8543
8544 /* Append the first path component of "remain" to "p". */
8545 q = getnextcomp(remain + 1);
8546 len = q - remain - (*q != NUL);
8547 cpy = vim_strnsave(p, STRLEN(p) + len);
8548 if (cpy != NULL)
8549 {
8550 STRNCAT(cpy, remain, len);
8551 vim_free(p);
8552 p = cpy;
8553 }
8554 /* Shorten "remain". */
8555 if (*q != NUL)
8556 STRMOVE(remain, q - 1);
8557 else
8558 {
8559 vim_free(remain);
8560 remain = NULL;
8561 }
8562 }
8563
8564 /* If the result is a relative path name, make it explicitly relative to
8565 * the current directory if and only if the argument had this form. */
8566 if (!vim_ispathsep(*p))
8567 {
8568 if (is_relative_to_current
8569 && *p != NUL
8570 && !(p[0] == '.'
8571 && (p[1] == NUL
8572 || vim_ispathsep(p[1])
8573 || (p[1] == '.'
8574 && (p[2] == NUL
8575 || vim_ispathsep(p[2]))))))
8576 {
8577 /* Prepend "./". */
8578 cpy = concat_str((char_u *)"./", p);
8579 if (cpy != NULL)
8580 {
8581 vim_free(p);
8582 p = cpy;
8583 }
8584 }
8585 else if (!is_relative_to_current)
8586 {
8587 /* Strip leading "./". */
8588 q = p;
8589 while (q[0] == '.' && vim_ispathsep(q[1]))
8590 q += 2;
8591 if (q > p)
8592 STRMOVE(p, p + 2);
8593 }
8594 }
8595
8596 /* Ensure that the result will have no trailing path separator
8597 * if the argument had none. But keep "/" or "//". */
8598 if (!has_trailing_pathsep)
8599 {
8600 q = p + STRLEN(p);
8601 if (after_pathsep(p, q))
8602 *gettail_sep(p) = NUL;
8603 }
8604
8605 rettv->vval.v_string = p;
8606 }
8607# else
8608 rettv->vval.v_string = vim_strsave(p);
8609# endif
8610#endif
8611
8612 simplify_filename(rettv->vval.v_string);
8613
8614#ifdef HAVE_READLINK
8615fail:
8616 vim_free(buf);
8617#endif
8618 rettv->v_type = VAR_STRING;
8619}
8620
8621/*
8622 * "reverse({list})" function
8623 */
8624 static void
8625f_reverse(typval_T *argvars, typval_T *rettv)
8626{
8627 list_T *l;
8628 listitem_T *li, *ni;
8629
8630 if (argvars[0].v_type != VAR_LIST)
8631 EMSG2(_(e_listarg), "reverse()");
8632 else if ((l = argvars[0].vval.v_list) != NULL
8633 && !tv_check_lock(l->lv_lock,
8634 (char_u *)N_("reverse() argument"), TRUE))
8635 {
8636 li = l->lv_last;
8637 l->lv_first = l->lv_last = NULL;
8638 l->lv_len = 0;
8639 while (li != NULL)
8640 {
8641 ni = li->li_prev;
8642 list_append(l, li);
8643 li = ni;
8644 }
8645 rettv->vval.v_list = l;
8646 rettv->v_type = VAR_LIST;
8647 ++l->lv_refcount;
8648 l->lv_idx = l->lv_len - l->lv_idx - 1;
8649 }
8650}
8651
8652#define SP_NOMOVE 0x01 /* don't move cursor */
8653#define SP_REPEAT 0x02 /* repeat to find outer pair */
8654#define SP_RETCOUNT 0x04 /* return matchcount */
8655#define SP_SETPCMARK 0x08 /* set previous context mark */
8656#define SP_START 0x10 /* accept match at start position */
8657#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
8658#define SP_END 0x40 /* leave cursor at end of match */
8659#define SP_COLUMN 0x80 /* start at cursor column */
8660
8661static int get_search_arg(typval_T *varp, int *flagsp);
8662
8663/*
8664 * Get flags for a search function.
8665 * Possibly sets "p_ws".
8666 * Returns BACKWARD, FORWARD or zero (for an error).
8667 */
8668 static int
8669get_search_arg(typval_T *varp, int *flagsp)
8670{
8671 int dir = FORWARD;
8672 char_u *flags;
8673 char_u nbuf[NUMBUFLEN];
8674 int mask;
8675
8676 if (varp->v_type != VAR_UNKNOWN)
8677 {
8678 flags = get_tv_string_buf_chk(varp, nbuf);
8679 if (flags == NULL)
8680 return 0; /* type error; errmsg already given */
8681 while (*flags != NUL)
8682 {
8683 switch (*flags)
8684 {
8685 case 'b': dir = BACKWARD; break;
8686 case 'w': p_ws = TRUE; break;
8687 case 'W': p_ws = FALSE; break;
8688 default: mask = 0;
8689 if (flagsp != NULL)
8690 switch (*flags)
8691 {
8692 case 'c': mask = SP_START; break;
8693 case 'e': mask = SP_END; break;
8694 case 'm': mask = SP_RETCOUNT; break;
8695 case 'n': mask = SP_NOMOVE; break;
8696 case 'p': mask = SP_SUBPAT; break;
8697 case 'r': mask = SP_REPEAT; break;
8698 case 's': mask = SP_SETPCMARK; break;
8699 case 'z': mask = SP_COLUMN; break;
8700 }
8701 if (mask == 0)
8702 {
8703 EMSG2(_(e_invarg2), flags);
8704 dir = 0;
8705 }
8706 else
8707 *flagsp |= mask;
8708 }
8709 if (dir == 0)
8710 break;
8711 ++flags;
8712 }
8713 }
8714 return dir;
8715}
8716
8717/*
8718 * Shared by search() and searchpos() functions.
8719 */
8720 static int
8721search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8722{
8723 int flags;
8724 char_u *pat;
8725 pos_T pos;
8726 pos_T save_cursor;
8727 int save_p_ws = p_ws;
8728 int dir;
8729 int retval = 0; /* default: FAIL */
8730 long lnum_stop = 0;
8731 proftime_T tm;
8732#ifdef FEAT_RELTIME
8733 long time_limit = 0;
8734#endif
8735 int options = SEARCH_KEEP;
8736 int subpatnum;
8737
8738 pat = get_tv_string(&argvars[0]);
8739 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
8740 if (dir == 0)
8741 goto theend;
8742 flags = *flagsp;
8743 if (flags & SP_START)
8744 options |= SEARCH_START;
8745 if (flags & SP_END)
8746 options |= SEARCH_END;
8747 if (flags & SP_COLUMN)
8748 options |= SEARCH_COL;
8749
8750 /* Optional arguments: line number to stop searching and timeout. */
8751 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
8752 {
8753 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL);
8754 if (lnum_stop < 0)
8755 goto theend;
8756#ifdef FEAT_RELTIME
8757 if (argvars[3].v_type != VAR_UNKNOWN)
8758 {
8759 time_limit = (long)get_tv_number_chk(&argvars[3], NULL);
8760 if (time_limit < 0)
8761 goto theend;
8762 }
8763#endif
8764 }
8765
8766#ifdef FEAT_RELTIME
8767 /* Set the time limit, if there is one. */
8768 profile_setlimit(time_limit, &tm);
8769#endif
8770
8771 /*
8772 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
8773 * Check to make sure only those flags are set.
8774 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
8775 * flags cannot be set. Check for that condition also.
8776 */
8777 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
8778 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8779 {
8780 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
8781 goto theend;
8782 }
8783
8784 pos = save_cursor = curwin->w_cursor;
8785 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L,
8786 options, RE_SEARCH, (linenr_T)lnum_stop, &tm);
8787 if (subpatnum != FAIL)
8788 {
8789 if (flags & SP_SUBPAT)
8790 retval = subpatnum;
8791 else
8792 retval = pos.lnum;
8793 if (flags & SP_SETPCMARK)
8794 setpcmark();
8795 curwin->w_cursor = pos;
8796 if (match_pos != NULL)
8797 {
8798 /* Store the match cursor position */
8799 match_pos->lnum = pos.lnum;
8800 match_pos->col = pos.col + 1;
8801 }
8802 /* "/$" will put the cursor after the end of the line, may need to
8803 * correct that here */
8804 check_cursor();
8805 }
8806
8807 /* If 'n' flag is used: restore cursor position. */
8808 if (flags & SP_NOMOVE)
8809 curwin->w_cursor = save_cursor;
8810 else
8811 curwin->w_set_curswant = TRUE;
8812theend:
8813 p_ws = save_p_ws;
8814
8815 return retval;
8816}
8817
8818#ifdef FEAT_FLOAT
8819
8820/*
8821 * round() is not in C90, use ceil() or floor() instead.
8822 */
8823 float_T
8824vim_round(float_T f)
8825{
8826 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
8827}
8828
8829/*
8830 * "round({float})" function
8831 */
8832 static void
8833f_round(typval_T *argvars, typval_T *rettv)
8834{
8835 float_T f = 0.0;
8836
8837 rettv->v_type = VAR_FLOAT;
8838 if (get_float_arg(argvars, &f) == OK)
8839 rettv->vval.v_float = vim_round(f);
8840 else
8841 rettv->vval.v_float = 0.0;
8842}
8843#endif
8844
8845/*
8846 * "screenattr()" function
8847 */
8848 static void
8849f_screenattr(typval_T *argvars, typval_T *rettv)
8850{
8851 int row;
8852 int col;
8853 int c;
8854
8855 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
8856 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
8857 if (row < 0 || row >= screen_Rows
8858 || col < 0 || col >= screen_Columns)
8859 c = -1;
8860 else
8861 c = ScreenAttrs[LineOffset[row] + col];
8862 rettv->vval.v_number = c;
8863}
8864
8865/*
8866 * "screenchar()" function
8867 */
8868 static void
8869f_screenchar(typval_T *argvars, typval_T *rettv)
8870{
8871 int row;
8872 int col;
8873 int off;
8874 int c;
8875
8876 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1;
8877 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1;
8878 if (row < 0 || row >= screen_Rows
8879 || col < 0 || col >= screen_Columns)
8880 c = -1;
8881 else
8882 {
8883 off = LineOffset[row] + col;
8884#ifdef FEAT_MBYTE
8885 if (enc_utf8 && ScreenLinesUC[off] != 0)
8886 c = ScreenLinesUC[off];
8887 else
8888#endif
8889 c = ScreenLines[off];
8890 }
8891 rettv->vval.v_number = c;
8892}
8893
8894/*
8895 * "screencol()" function
8896 *
8897 * First column is 1 to be consistent with virtcol().
8898 */
8899 static void
8900f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
8901{
8902 rettv->vval.v_number = screen_screencol() + 1;
8903}
8904
8905/*
8906 * "screenrow()" function
8907 */
8908 static void
8909f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
8910{
8911 rettv->vval.v_number = screen_screenrow() + 1;
8912}
8913
8914/*
8915 * "search()" function
8916 */
8917 static void
8918f_search(typval_T *argvars, typval_T *rettv)
8919{
8920 int flags = 0;
8921
8922 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
8923}
8924
8925/*
8926 * "searchdecl()" function
8927 */
8928 static void
8929f_searchdecl(typval_T *argvars, typval_T *rettv)
8930{
8931 int locally = 1;
8932 int thisblock = 0;
8933 int error = FALSE;
8934 char_u *name;
8935
8936 rettv->vval.v_number = 1; /* default: FAIL */
8937
8938 name = get_tv_string_chk(&argvars[0]);
8939 if (argvars[1].v_type != VAR_UNKNOWN)
8940 {
8941 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0;
8942 if (!error && argvars[2].v_type != VAR_UNKNOWN)
8943 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0;
8944 }
8945 if (!error && name != NULL)
8946 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
8947 locally, thisblock, SEARCH_KEEP) == FAIL;
8948}
8949
8950/*
8951 * Used by searchpair() and searchpairpos()
8952 */
8953 static int
8954searchpair_cmn(typval_T *argvars, pos_T *match_pos)
8955{
8956 char_u *spat, *mpat, *epat;
8957 char_u *skip;
8958 int save_p_ws = p_ws;
8959 int dir;
8960 int flags = 0;
8961 char_u nbuf1[NUMBUFLEN];
8962 char_u nbuf2[NUMBUFLEN];
8963 char_u nbuf3[NUMBUFLEN];
8964 int retval = 0; /* default: FAIL */
8965 long lnum_stop = 0;
8966 long time_limit = 0;
8967
8968 /* Get the three pattern arguments: start, middle, end. */
8969 spat = get_tv_string_chk(&argvars[0]);
8970 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1);
8971 epat = get_tv_string_buf_chk(&argvars[2], nbuf2);
8972 if (spat == NULL || mpat == NULL || epat == NULL)
8973 goto theend; /* type error */
8974
8975 /* Handle the optional fourth argument: flags */
8976 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
8977 if (dir == 0)
8978 goto theend;
8979
8980 /* Don't accept SP_END or SP_SUBPAT.
8981 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
8982 */
8983 if ((flags & (SP_END | SP_SUBPAT)) != 0
8984 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8985 {
8986 EMSG2(_(e_invarg2), get_tv_string(&argvars[3]));
8987 goto theend;
8988 }
8989
8990 /* Using 'r' implies 'W', otherwise it doesn't work. */
8991 if (flags & SP_REPEAT)
8992 p_ws = FALSE;
8993
8994 /* Optional fifth argument: skip expression */
8995 if (argvars[3].v_type == VAR_UNKNOWN
8996 || argvars[4].v_type == VAR_UNKNOWN)
8997 skip = (char_u *)"";
8998 else
8999 {
9000 skip = get_tv_string_buf_chk(&argvars[4], nbuf3);
9001 if (argvars[5].v_type != VAR_UNKNOWN)
9002 {
9003 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL);
9004 if (lnum_stop < 0)
9005 goto theend;
9006#ifdef FEAT_RELTIME
9007 if (argvars[6].v_type != VAR_UNKNOWN)
9008 {
9009 time_limit = (long)get_tv_number_chk(&argvars[6], NULL);
9010 if (time_limit < 0)
9011 goto theend;
9012 }
9013#endif
9014 }
9015 }
9016 if (skip == NULL)
9017 goto theend; /* type error */
9018
9019 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9020 match_pos, lnum_stop, time_limit);
9021
9022theend:
9023 p_ws = save_p_ws;
9024
9025 return retval;
9026}
9027
9028/*
9029 * "searchpair()" function
9030 */
9031 static void
9032f_searchpair(typval_T *argvars, typval_T *rettv)
9033{
9034 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9035}
9036
9037/*
9038 * "searchpairpos()" function
9039 */
9040 static void
9041f_searchpairpos(typval_T *argvars, typval_T *rettv)
9042{
9043 pos_T match_pos;
9044 int lnum = 0;
9045 int col = 0;
9046
9047 if (rettv_list_alloc(rettv) == FAIL)
9048 return;
9049
9050 if (searchpair_cmn(argvars, &match_pos) > 0)
9051 {
9052 lnum = match_pos.lnum;
9053 col = match_pos.col;
9054 }
9055
9056 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9057 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9058}
9059
9060/*
9061 * Search for a start/middle/end thing.
9062 * Used by searchpair(), see its documentation for the details.
9063 * Returns 0 or -1 for no match,
9064 */
9065 long
9066do_searchpair(
9067 char_u *spat, /* start pattern */
9068 char_u *mpat, /* middle pattern */
9069 char_u *epat, /* end pattern */
9070 int dir, /* BACKWARD or FORWARD */
9071 char_u *skip, /* skip expression */
9072 int flags, /* SP_SETPCMARK and other SP_ values */
9073 pos_T *match_pos,
9074 linenr_T lnum_stop, /* stop at this line if not zero */
9075 long time_limit UNUSED) /* stop after this many msec */
9076{
9077 char_u *save_cpo;
9078 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9079 long retval = 0;
9080 pos_T pos;
9081 pos_T firstpos;
9082 pos_T foundpos;
9083 pos_T save_cursor;
9084 pos_T save_pos;
9085 int n;
9086 int r;
9087 int nest = 1;
9088 int err;
9089 int options = SEARCH_KEEP;
9090 proftime_T tm;
9091
9092 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9093 save_cpo = p_cpo;
9094 p_cpo = empty_option;
9095
9096#ifdef FEAT_RELTIME
9097 /* Set the time limit, if there is one. */
9098 profile_setlimit(time_limit, &tm);
9099#endif
9100
9101 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9102 * start/middle/end (pat3, for the top pair). */
9103 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15));
9104 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23));
9105 if (pat2 == NULL || pat3 == NULL)
9106 goto theend;
9107 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
9108 if (*mpat == NUL)
9109 STRCPY(pat3, pat2);
9110 else
9111 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
9112 spat, epat, mpat);
9113 if (flags & SP_START)
9114 options |= SEARCH_START;
9115
9116 save_cursor = curwin->w_cursor;
9117 pos = curwin->w_cursor;
9118 clearpos(&firstpos);
9119 clearpos(&foundpos);
9120 pat = pat3;
9121 for (;;)
9122 {
9123 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
9124 options, RE_SEARCH, lnum_stop, &tm);
9125 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
9126 /* didn't find it or found the first match again: FAIL */
9127 break;
9128
9129 if (firstpos.lnum == 0)
9130 firstpos = pos;
9131 if (equalpos(pos, foundpos))
9132 {
9133 /* Found the same position again. Can happen with a pattern that
9134 * has "\zs" at the end and searching backwards. Advance one
9135 * character and try again. */
9136 if (dir == BACKWARD)
9137 decl(&pos);
9138 else
9139 incl(&pos);
9140 }
9141 foundpos = pos;
9142
9143 /* clear the start flag to avoid getting stuck here */
9144 options &= ~SEARCH_START;
9145
9146 /* If the skip pattern matches, ignore this match. */
9147 if (*skip != NUL)
9148 {
9149 save_pos = curwin->w_cursor;
9150 curwin->w_cursor = pos;
9151 r = eval_to_bool(skip, &err, NULL, FALSE);
9152 curwin->w_cursor = save_pos;
9153 if (err)
9154 {
9155 /* Evaluating {skip} caused an error, break here. */
9156 curwin->w_cursor = save_cursor;
9157 retval = -1;
9158 break;
9159 }
9160 if (r)
9161 continue;
9162 }
9163
9164 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9165 {
9166 /* Found end when searching backwards or start when searching
9167 * forward: nested pair. */
9168 ++nest;
9169 pat = pat2; /* nested, don't search for middle */
9170 }
9171 else
9172 {
9173 /* Found end when searching forward or start when searching
9174 * backward: end of (nested) pair; or found middle in outer pair. */
9175 if (--nest == 1)
9176 pat = pat3; /* outer level, search for middle */
9177 }
9178
9179 if (nest == 0)
9180 {
9181 /* Found the match: return matchcount or line number. */
9182 if (flags & SP_RETCOUNT)
9183 ++retval;
9184 else
9185 retval = pos.lnum;
9186 if (flags & SP_SETPCMARK)
9187 setpcmark();
9188 curwin->w_cursor = pos;
9189 if (!(flags & SP_REPEAT))
9190 break;
9191 nest = 1; /* search for next unmatched */
9192 }
9193 }
9194
9195 if (match_pos != NULL)
9196 {
9197 /* Store the match cursor position */
9198 match_pos->lnum = curwin->w_cursor.lnum;
9199 match_pos->col = curwin->w_cursor.col + 1;
9200 }
9201
9202 /* If 'n' flag is used or search failed: restore cursor position. */
9203 if ((flags & SP_NOMOVE) || retval == 0)
9204 curwin->w_cursor = save_cursor;
9205
9206theend:
9207 vim_free(pat2);
9208 vim_free(pat3);
9209 if (p_cpo == empty_option)
9210 p_cpo = save_cpo;
9211 else
9212 /* Darn, evaluating the {skip} expression changed the value. */
9213 free_string_option(save_cpo);
9214
9215 return retval;
9216}
9217
9218/*
9219 * "searchpos()" function
9220 */
9221 static void
9222f_searchpos(typval_T *argvars, typval_T *rettv)
9223{
9224 pos_T match_pos;
9225 int lnum = 0;
9226 int col = 0;
9227 int n;
9228 int flags = 0;
9229
9230 if (rettv_list_alloc(rettv) == FAIL)
9231 return;
9232
9233 n = search_cmn(argvars, &match_pos, &flags);
9234 if (n > 0)
9235 {
9236 lnum = match_pos.lnum;
9237 col = match_pos.col;
9238 }
9239
9240 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9241 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9242 if (flags & SP_SUBPAT)
9243 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9244}
9245
9246 static void
9247f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9248{
9249#ifdef FEAT_CLIENTSERVER
9250 char_u buf[NUMBUFLEN];
9251 char_u *server = get_tv_string_chk(&argvars[0]);
9252 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf);
9253
9254 rettv->vval.v_number = -1;
9255 if (server == NULL || reply == NULL)
9256 return;
9257 if (check_restricted() || check_secure())
9258 return;
9259# ifdef FEAT_X11
9260 if (check_connection() == FAIL)
9261 return;
9262# endif
9263
9264 if (serverSendReply(server, reply) < 0)
9265 {
9266 EMSG(_("E258: Unable to send to client"));
9267 return;
9268 }
9269 rettv->vval.v_number = 0;
9270#else
9271 rettv->vval.v_number = -1;
9272#endif
9273}
9274
9275 static void
9276f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9277{
9278 char_u *r = NULL;
9279
9280#ifdef FEAT_CLIENTSERVER
9281# ifdef WIN32
9282 r = serverGetVimNames();
9283# else
9284 make_connection();
9285 if (X_DISPLAY != NULL)
9286 r = serverGetVimNames(X_DISPLAY);
9287# endif
9288#endif
9289 rettv->v_type = VAR_STRING;
9290 rettv->vval.v_string = r;
9291}
9292
9293/*
9294 * "setbufvar()" function
9295 */
9296 static void
9297f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9298{
9299 buf_T *buf;
9300 char_u *varname, *bufvarname;
9301 typval_T *varp;
9302 char_u nbuf[NUMBUFLEN];
9303
9304 if (check_restricted() || check_secure())
9305 return;
9306 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
9307 varname = get_tv_string_chk(&argvars[1]);
9308 buf = get_buf_tv(&argvars[0], FALSE);
9309 varp = &argvars[2];
9310
9311 if (buf != NULL && varname != NULL && varp != NULL)
9312 {
9313 if (*varname == '&')
9314 {
9315 long numval;
9316 char_u *strval;
9317 int error = FALSE;
9318 aco_save_T aco;
9319
9320 /* set curbuf to be our buf, temporarily */
9321 aucmd_prepbuf(&aco, buf);
9322
9323 ++varname;
9324 numval = (long)get_tv_number_chk(varp, &error);
9325 strval = get_tv_string_buf_chk(varp, nbuf);
9326 if (!error && strval != NULL)
9327 set_option_value(varname, numval, strval, OPT_LOCAL);
9328
9329 /* reset notion of buffer */
9330 aucmd_restbuf(&aco);
9331 }
9332 else
9333 {
9334 buf_T *save_curbuf = curbuf;
9335
9336 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
9337 if (bufvarname != NULL)
9338 {
9339 curbuf = buf;
9340 STRCPY(bufvarname, "b:");
9341 STRCPY(bufvarname + 2, varname);
9342 set_var(bufvarname, varp, TRUE);
9343 vim_free(bufvarname);
9344 curbuf = save_curbuf;
9345 }
9346 }
9347 }
9348}
9349
9350 static void
9351f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9352{
9353 dict_T *d;
9354 dictitem_T *di;
9355 char_u *csearch;
9356
9357 if (argvars[0].v_type != VAR_DICT)
9358 {
9359 EMSG(_(e_dictreq));
9360 return;
9361 }
9362
9363 if ((d = argvars[0].vval.v_dict) != NULL)
9364 {
9365 csearch = get_dict_string(d, (char_u *)"char", FALSE);
9366 if (csearch != NULL)
9367 {
9368#ifdef FEAT_MBYTE
9369 if (enc_utf8)
9370 {
9371 int pcc[MAX_MCO];
9372 int c = utfc_ptr2char(csearch, pcc);
9373
9374 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9375 }
9376 else
9377#endif
9378 set_last_csearch(PTR2CHAR(csearch),
9379 csearch, MB_PTR2LEN(csearch));
9380 }
9381
9382 di = dict_find(d, (char_u *)"forward", -1);
9383 if (di != NULL)
9384 set_csearch_direction((int)get_tv_number(&di->di_tv)
9385 ? FORWARD : BACKWARD);
9386
9387 di = dict_find(d, (char_u *)"until", -1);
9388 if (di != NULL)
9389 set_csearch_until(!!get_tv_number(&di->di_tv));
9390 }
9391}
9392
9393/*
9394 * "setcmdpos()" function
9395 */
9396 static void
9397f_setcmdpos(typval_T *argvars, typval_T *rettv)
9398{
9399 int pos = (int)get_tv_number(&argvars[0]) - 1;
9400
9401 if (pos >= 0)
9402 rettv->vval.v_number = set_cmdline_pos(pos);
9403}
9404
9405/*
9406 * "setfperm({fname}, {mode})" function
9407 */
9408 static void
9409f_setfperm(typval_T *argvars, typval_T *rettv)
9410{
9411 char_u *fname;
9412 char_u modebuf[NUMBUFLEN];
9413 char_u *mode_str;
9414 int i;
9415 int mask;
9416 int mode = 0;
9417
9418 rettv->vval.v_number = 0;
9419 fname = get_tv_string_chk(&argvars[0]);
9420 if (fname == NULL)
9421 return;
9422 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf);
9423 if (mode_str == NULL)
9424 return;
9425 if (STRLEN(mode_str) != 9)
9426 {
9427 EMSG2(_(e_invarg2), mode_str);
9428 return;
9429 }
9430
9431 mask = 1;
9432 for (i = 8; i >= 0; --i)
9433 {
9434 if (mode_str[i] != '-')
9435 mode |= mask;
9436 mask = mask << 1;
9437 }
9438 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9439}
9440
9441/*
9442 * "setline()" function
9443 */
9444 static void
9445f_setline(typval_T *argvars, typval_T *rettv)
9446{
9447 linenr_T lnum;
9448 char_u *line = NULL;
9449 list_T *l = NULL;
9450 listitem_T *li = NULL;
9451 long added = 0;
9452 linenr_T lcount = curbuf->b_ml.ml_line_count;
9453
9454 lnum = get_tv_lnum(&argvars[0]);
9455 if (argvars[1].v_type == VAR_LIST)
9456 {
9457 l = argvars[1].vval.v_list;
9458 li = l->lv_first;
9459 }
9460 else
9461 line = get_tv_string_chk(&argvars[1]);
9462
9463 /* default result is zero == OK */
9464 for (;;)
9465 {
9466 if (l != NULL)
9467 {
9468 /* list argument, get next string */
9469 if (li == NULL)
9470 break;
9471 line = get_tv_string_chk(&li->li_tv);
9472 li = li->li_next;
9473 }
9474
9475 rettv->vval.v_number = 1; /* FAIL */
9476 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
9477 break;
9478
9479 /* When coming here from Insert mode, sync undo, so that this can be
9480 * undone separately from what was previously inserted. */
9481 if (u_sync_once == 2)
9482 {
9483 u_sync_once = 1; /* notify that u_sync() was called */
9484 u_sync(TRUE);
9485 }
9486
9487 if (lnum <= curbuf->b_ml.ml_line_count)
9488 {
9489 /* existing line, replace it */
9490 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK)
9491 {
9492 changed_bytes(lnum, 0);
9493 if (lnum == curwin->w_cursor.lnum)
9494 check_cursor_col();
9495 rettv->vval.v_number = 0; /* OK */
9496 }
9497 }
9498 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
9499 {
9500 /* lnum is one past the last line, append the line */
9501 ++added;
9502 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
9503 rettv->vval.v_number = 0; /* OK */
9504 }
9505
9506 if (l == NULL) /* only one string argument */
9507 break;
9508 ++lnum;
9509 }
9510
9511 if (added > 0)
9512 appended_lines_mark(lcount, added);
9513}
9514
9515static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv);
9516
9517/*
9518 * Used by "setqflist()" and "setloclist()" functions
9519 */
9520 static void
9521set_qf_ll_list(
9522 win_T *wp UNUSED,
9523 typval_T *list_arg UNUSED,
9524 typval_T *action_arg UNUSED,
9525 typval_T *rettv)
9526{
9527#ifdef FEAT_QUICKFIX
9528 static char *e_invact = N_("E927: Invalid action: '%s'");
9529 char_u *act;
9530 int action = 0;
9531#endif
9532
9533 rettv->vval.v_number = -1;
9534
9535#ifdef FEAT_QUICKFIX
9536 if (list_arg->v_type != VAR_LIST)
9537 EMSG(_(e_listreq));
9538 else
9539 {
9540 list_T *l = list_arg->vval.v_list;
9541
9542 if (action_arg->v_type == VAR_STRING)
9543 {
9544 act = get_tv_string_chk(action_arg);
9545 if (act == NULL)
9546 return; /* type error; errmsg already given */
9547 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL)
9548 action = *act;
9549 else
9550 EMSG2(_(e_invact), act);
9551 }
9552 else if (action_arg->v_type == VAR_UNKNOWN)
9553 action = ' ';
9554 else
9555 EMSG(_(e_stringreq));
9556
9557 if (l != NULL && action && set_errorlist(wp, l, action,
9558 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK)
9559 rettv->vval.v_number = 0;
9560 }
9561#endif
9562}
9563
9564/*
9565 * "setloclist()" function
9566 */
9567 static void
9568f_setloclist(typval_T *argvars, typval_T *rettv)
9569{
9570 win_T *win;
9571
9572 rettv->vval.v_number = -1;
9573
9574 win = find_win_by_nr(&argvars[0], NULL);
9575 if (win != NULL)
9576 set_qf_ll_list(win, &argvars[1], &argvars[2], rettv);
9577}
9578
9579/*
9580 * "setmatches()" function
9581 */
9582 static void
9583f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9584{
9585#ifdef FEAT_SEARCH_EXTRA
9586 list_T *l;
9587 listitem_T *li;
9588 dict_T *d;
9589 list_T *s = NULL;
9590
9591 rettv->vval.v_number = -1;
9592 if (argvars[0].v_type != VAR_LIST)
9593 {
9594 EMSG(_(e_listreq));
9595 return;
9596 }
9597 if ((l = argvars[0].vval.v_list) != NULL)
9598 {
9599
9600 /* To some extent make sure that we are dealing with a list from
9601 * "getmatches()". */
9602 li = l->lv_first;
9603 while (li != NULL)
9604 {
9605 if (li->li_tv.v_type != VAR_DICT
9606 || (d = li->li_tv.vval.v_dict) == NULL)
9607 {
9608 EMSG(_(e_invarg));
9609 return;
9610 }
9611 if (!(dict_find(d, (char_u *)"group", -1) != NULL
9612 && (dict_find(d, (char_u *)"pattern", -1) != NULL
9613 || dict_find(d, (char_u *)"pos1", -1) != NULL)
9614 && dict_find(d, (char_u *)"priority", -1) != NULL
9615 && dict_find(d, (char_u *)"id", -1) != NULL))
9616 {
9617 EMSG(_(e_invarg));
9618 return;
9619 }
9620 li = li->li_next;
9621 }
9622
9623 clear_matches(curwin);
9624 li = l->lv_first;
9625 while (li != NULL)
9626 {
9627 int i = 0;
9628 char_u buf[5];
9629 dictitem_T *di;
9630 char_u *group;
9631 int priority;
9632 int id;
9633 char_u *conceal;
9634
9635 d = li->li_tv.vval.v_dict;
9636 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
9637 {
9638 if (s == NULL)
9639 {
9640 s = list_alloc();
9641 if (s == NULL)
9642 return;
9643 }
9644
9645 /* match from matchaddpos() */
9646 for (i = 1; i < 9; i++)
9647 {
9648 sprintf((char *)buf, (char *)"pos%d", i);
9649 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
9650 {
9651 if (di->di_tv.v_type != VAR_LIST)
9652 return;
9653
9654 list_append_tv(s, &di->di_tv);
9655 s->lv_refcount++;
9656 }
9657 else
9658 break;
9659 }
9660 }
9661
9662 group = get_dict_string(d, (char_u *)"group", FALSE);
9663 priority = (int)get_dict_number(d, (char_u *)"priority");
9664 id = (int)get_dict_number(d, (char_u *)"id");
9665 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
9666 ? get_dict_string(d, (char_u *)"conceal", FALSE)
9667 : NULL;
9668 if (i == 0)
9669 {
9670 match_add(curwin, group,
9671 get_dict_string(d, (char_u *)"pattern", FALSE),
9672 priority, id, NULL, conceal);
9673 }
9674 else
9675 {
9676 match_add(curwin, group, NULL, priority, id, s, conceal);
9677 list_unref(s);
9678 s = NULL;
9679 }
9680
9681 li = li->li_next;
9682 }
9683 rettv->vval.v_number = 0;
9684 }
9685#endif
9686}
9687
9688/*
9689 * "setpos()" function
9690 */
9691 static void
9692f_setpos(typval_T *argvars, typval_T *rettv)
9693{
9694 pos_T pos;
9695 int fnum;
9696 char_u *name;
9697 colnr_T curswant = -1;
9698
9699 rettv->vval.v_number = -1;
9700 name = get_tv_string_chk(argvars);
9701 if (name != NULL)
9702 {
9703 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
9704 {
9705 if (--pos.col < 0)
9706 pos.col = 0;
9707 if (name[0] == '.' && name[1] == NUL)
9708 {
9709 /* set cursor */
9710 if (fnum == curbuf->b_fnum)
9711 {
9712 curwin->w_cursor = pos;
9713 if (curswant >= 0)
9714 {
9715 curwin->w_curswant = curswant - 1;
9716 curwin->w_set_curswant = FALSE;
9717 }
9718 check_cursor();
9719 rettv->vval.v_number = 0;
9720 }
9721 else
9722 EMSG(_(e_invarg));
9723 }
9724 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
9725 {
9726 /* set mark */
9727 if (setmark_pos(name[1], &pos, fnum) == OK)
9728 rettv->vval.v_number = 0;
9729 }
9730 else
9731 EMSG(_(e_invarg));
9732 }
9733 }
9734}
9735
9736/*
9737 * "setqflist()" function
9738 */
9739 static void
9740f_setqflist(typval_T *argvars, typval_T *rettv)
9741{
9742 set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv);
9743}
9744
9745/*
9746 * "setreg()" function
9747 */
9748 static void
9749f_setreg(typval_T *argvars, typval_T *rettv)
9750{
9751 int regname;
9752 char_u *strregname;
9753 char_u *stropt;
9754 char_u *strval;
9755 int append;
9756 char_u yank_type;
9757 long block_len;
9758
9759 block_len = -1;
9760 yank_type = MAUTO;
9761 append = FALSE;
9762
9763 strregname = get_tv_string_chk(argvars);
9764 rettv->vval.v_number = 1; /* FAIL is default */
9765
9766 if (strregname == NULL)
9767 return; /* type error; errmsg already given */
9768 regname = *strregname;
9769 if (regname == 0 || regname == '@')
9770 regname = '"';
9771
9772 if (argvars[2].v_type != VAR_UNKNOWN)
9773 {
9774 stropt = get_tv_string_chk(&argvars[2]);
9775 if (stropt == NULL)
9776 return; /* type error */
9777 for (; *stropt != NUL; ++stropt)
9778 switch (*stropt)
9779 {
9780 case 'a': case 'A': /* append */
9781 append = TRUE;
9782 break;
9783 case 'v': case 'c': /* character-wise selection */
9784 yank_type = MCHAR;
9785 break;
9786 case 'V': case 'l': /* line-wise selection */
9787 yank_type = MLINE;
9788 break;
9789 case 'b': case Ctrl_V: /* block-wise selection */
9790 yank_type = MBLOCK;
9791 if (VIM_ISDIGIT(stropt[1]))
9792 {
9793 ++stropt;
9794 block_len = getdigits(&stropt) - 1;
9795 --stropt;
9796 }
9797 break;
9798 }
9799 }
9800
9801 if (argvars[1].v_type == VAR_LIST)
9802 {
9803 char_u **lstval;
9804 char_u **allocval;
9805 char_u buf[NUMBUFLEN];
9806 char_u **curval;
9807 char_u **curallocval;
9808 list_T *ll = argvars[1].vval.v_list;
9809 listitem_T *li;
9810 int len;
9811
9812 /* If the list is NULL handle like an empty list. */
9813 len = ll == NULL ? 0 : ll->lv_len;
9814
9815 /* First half: use for pointers to result lines; second half: use for
9816 * pointers to allocated copies. */
9817 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
9818 if (lstval == NULL)
9819 return;
9820 curval = lstval;
9821 allocval = lstval + len + 2;
9822 curallocval = allocval;
9823
9824 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
9825 li = li->li_next)
9826 {
9827 strval = get_tv_string_buf_chk(&li->li_tv, buf);
9828 if (strval == NULL)
9829 goto free_lstval;
9830 if (strval == buf)
9831 {
9832 /* Need to make a copy, next get_tv_string_buf_chk() will
9833 * overwrite the string. */
9834 strval = vim_strsave(buf);
9835 if (strval == NULL)
9836 goto free_lstval;
9837 *curallocval++ = strval;
9838 }
9839 *curval++ = strval;
9840 }
9841 *curval++ = NULL;
9842
9843 write_reg_contents_lst(regname, lstval, -1,
9844 append, yank_type, block_len);
9845free_lstval:
9846 while (curallocval > allocval)
9847 vim_free(*--curallocval);
9848 vim_free(lstval);
9849 }
9850 else
9851 {
9852 strval = get_tv_string_chk(&argvars[1]);
9853 if (strval == NULL)
9854 return;
9855 write_reg_contents_ex(regname, strval, -1,
9856 append, yank_type, block_len);
9857 }
9858 rettv->vval.v_number = 0;
9859}
9860
9861/*
9862 * "settabvar()" function
9863 */
9864 static void
9865f_settabvar(typval_T *argvars, typval_T *rettv)
9866{
9867#ifdef FEAT_WINDOWS
9868 tabpage_T *save_curtab;
9869 tabpage_T *tp;
9870#endif
9871 char_u *varname, *tabvarname;
9872 typval_T *varp;
9873
9874 rettv->vval.v_number = 0;
9875
9876 if (check_restricted() || check_secure())
9877 return;
9878
9879#ifdef FEAT_WINDOWS
9880 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
9881#endif
9882 varname = get_tv_string_chk(&argvars[1]);
9883 varp = &argvars[2];
9884
9885 if (varname != NULL && varp != NULL
9886#ifdef FEAT_WINDOWS
9887 && tp != NULL
9888#endif
9889 )
9890 {
9891#ifdef FEAT_WINDOWS
9892 save_curtab = curtab;
9893 goto_tabpage_tp(tp, FALSE, FALSE);
9894#endif
9895
9896 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
9897 if (tabvarname != NULL)
9898 {
9899 STRCPY(tabvarname, "t:");
9900 STRCPY(tabvarname + 2, varname);
9901 set_var(tabvarname, varp, TRUE);
9902 vim_free(tabvarname);
9903 }
9904
9905#ifdef FEAT_WINDOWS
9906 /* Restore current tabpage */
9907 if (valid_tabpage(save_curtab))
9908 goto_tabpage_tp(save_curtab, FALSE, FALSE);
9909#endif
9910 }
9911}
9912
9913/*
9914 * "settabwinvar()" function
9915 */
9916 static void
9917f_settabwinvar(typval_T *argvars, typval_T *rettv)
9918{
9919 setwinvar(argvars, rettv, 1);
9920}
9921
9922/*
9923 * "setwinvar()" function
9924 */
9925 static void
9926f_setwinvar(typval_T *argvars, typval_T *rettv)
9927{
9928 setwinvar(argvars, rettv, 0);
9929}
9930
9931#ifdef FEAT_CRYPT
9932/*
9933 * "sha256({string})" function
9934 */
9935 static void
9936f_sha256(typval_T *argvars, typval_T *rettv)
9937{
9938 char_u *p;
9939
9940 p = get_tv_string(&argvars[0]);
9941 rettv->vval.v_string = vim_strsave(
9942 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
9943 rettv->v_type = VAR_STRING;
9944}
9945#endif /* FEAT_CRYPT */
9946
9947/*
9948 * "shellescape({string})" function
9949 */
9950 static void
9951f_shellescape(typval_T *argvars, typval_T *rettv)
9952{
9953 rettv->vval.v_string = vim_strsave_shellescape(
9954 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE);
9955 rettv->v_type = VAR_STRING;
9956}
9957
9958/*
9959 * shiftwidth() function
9960 */
9961 static void
9962f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
9963{
9964 rettv->vval.v_number = get_sw_value(curbuf);
9965}
9966
9967/*
9968 * "simplify()" function
9969 */
9970 static void
9971f_simplify(typval_T *argvars, typval_T *rettv)
9972{
9973 char_u *p;
9974
9975 p = get_tv_string(&argvars[0]);
9976 rettv->vval.v_string = vim_strsave(p);
9977 simplify_filename(rettv->vval.v_string); /* simplify in place */
9978 rettv->v_type = VAR_STRING;
9979}
9980
9981#ifdef FEAT_FLOAT
9982/*
9983 * "sin()" function
9984 */
9985 static void
9986f_sin(typval_T *argvars, typval_T *rettv)
9987{
9988 float_T f = 0.0;
9989
9990 rettv->v_type = VAR_FLOAT;
9991 if (get_float_arg(argvars, &f) == OK)
9992 rettv->vval.v_float = sin(f);
9993 else
9994 rettv->vval.v_float = 0.0;
9995}
9996
9997/*
9998 * "sinh()" function
9999 */
10000 static void
10001f_sinh(typval_T *argvars, typval_T *rettv)
10002{
10003 float_T f = 0.0;
10004
10005 rettv->v_type = VAR_FLOAT;
10006 if (get_float_arg(argvars, &f) == OK)
10007 rettv->vval.v_float = sinh(f);
10008 else
10009 rettv->vval.v_float = 0.0;
10010}
10011#endif
10012
10013static int
10014#ifdef __BORLANDC__
10015 _RTLENTRYF
10016#endif
10017 item_compare(const void *s1, const void *s2);
10018static int
10019#ifdef __BORLANDC__
10020 _RTLENTRYF
10021#endif
10022 item_compare2(const void *s1, const void *s2);
10023
10024/* struct used in the array that's given to qsort() */
10025typedef struct
10026{
10027 listitem_T *item;
10028 int idx;
10029} sortItem_T;
10030
10031/* struct storing information about current sort */
10032typedef struct
10033{
10034 int item_compare_ic;
10035 int item_compare_numeric;
10036 int item_compare_numbers;
10037#ifdef FEAT_FLOAT
10038 int item_compare_float;
10039#endif
10040 char_u *item_compare_func;
10041 partial_T *item_compare_partial;
10042 dict_T *item_compare_selfdict;
10043 int item_compare_func_err;
10044 int item_compare_keep_zero;
10045} sortinfo_T;
10046static sortinfo_T *sortinfo = NULL;
10047static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort);
10048#define ITEM_COMPARE_FAIL 999
10049
10050/*
10051 * Compare functions for f_sort() and f_uniq() below.
10052 */
10053 static int
10054#ifdef __BORLANDC__
10055_RTLENTRYF
10056#endif
10057item_compare(const void *s1, const void *s2)
10058{
10059 sortItem_T *si1, *si2;
10060 typval_T *tv1, *tv2;
10061 char_u *p1, *p2;
10062 char_u *tofree1 = NULL, *tofree2 = NULL;
10063 int res;
10064 char_u numbuf1[NUMBUFLEN];
10065 char_u numbuf2[NUMBUFLEN];
10066
10067 si1 = (sortItem_T *)s1;
10068 si2 = (sortItem_T *)s2;
10069 tv1 = &si1->item->li_tv;
10070 tv2 = &si2->item->li_tv;
10071
10072 if (sortinfo->item_compare_numbers)
10073 {
10074 varnumber_T v1 = get_tv_number(tv1);
10075 varnumber_T v2 = get_tv_number(tv2);
10076
10077 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10078 }
10079
10080#ifdef FEAT_FLOAT
10081 if (sortinfo->item_compare_float)
10082 {
10083 float_T v1 = get_tv_float(tv1);
10084 float_T v2 = get_tv_float(tv2);
10085
10086 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
10087 }
10088#endif
10089
10090 /* tv2string() puts quotes around a string and allocates memory. Don't do
10091 * that for string variables. Use a single quote when comparing with a
10092 * non-string to do what the docs promise. */
10093 if (tv1->v_type == VAR_STRING)
10094 {
10095 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10096 p1 = (char_u *)"'";
10097 else
10098 p1 = tv1->vval.v_string;
10099 }
10100 else
10101 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
10102 if (tv2->v_type == VAR_STRING)
10103 {
10104 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
10105 p2 = (char_u *)"'";
10106 else
10107 p2 = tv2->vval.v_string;
10108 }
10109 else
10110 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
10111 if (p1 == NULL)
10112 p1 = (char_u *)"";
10113 if (p2 == NULL)
10114 p2 = (char_u *)"";
10115 if (!sortinfo->item_compare_numeric)
10116 {
10117 if (sortinfo->item_compare_ic)
10118 res = STRICMP(p1, p2);
10119 else
10120 res = STRCMP(p1, p2);
10121 }
10122 else
10123 {
10124 double n1, n2;
10125 n1 = strtod((char *)p1, (char **)&p1);
10126 n2 = strtod((char *)p2, (char **)&p2);
10127 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
10128 }
10129
10130 /* When the result would be zero, compare the item indexes. Makes the
10131 * sort stable. */
10132 if (res == 0 && !sortinfo->item_compare_keep_zero)
10133 res = si1->idx > si2->idx ? 1 : -1;
10134
10135 vim_free(tofree1);
10136 vim_free(tofree2);
10137 return res;
10138}
10139
10140 static int
10141#ifdef __BORLANDC__
10142_RTLENTRYF
10143#endif
10144item_compare2(const void *s1, const void *s2)
10145{
10146 sortItem_T *si1, *si2;
10147 int res;
10148 typval_T rettv;
10149 typval_T argv[3];
10150 int dummy;
10151 char_u *func_name;
10152 partial_T *partial = sortinfo->item_compare_partial;
10153
10154 /* shortcut after failure in previous call; compare all items equal */
10155 if (sortinfo->item_compare_func_err)
10156 return 0;
10157
10158 si1 = (sortItem_T *)s1;
10159 si2 = (sortItem_T *)s2;
10160
10161 if (partial == NULL)
10162 func_name = sortinfo->item_compare_func;
10163 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020010164 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010165
10166 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
10167 * in the copy without changing the original list items. */
10168 copy_tv(&si1->item->li_tv, &argv[0]);
10169 copy_tv(&si2->item->li_tv, &argv[1]);
10170
10171 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
10172 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020010173 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010174 partial, sortinfo->item_compare_selfdict);
10175 clear_tv(&argv[0]);
10176 clear_tv(&argv[1]);
10177
10178 if (res == FAIL)
10179 res = ITEM_COMPARE_FAIL;
10180 else
10181 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err);
10182 if (sortinfo->item_compare_func_err)
10183 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
10184 clear_tv(&rettv);
10185
10186 /* When the result would be zero, compare the pointers themselves. Makes
10187 * the sort stable. */
10188 if (res == 0 && !sortinfo->item_compare_keep_zero)
10189 res = si1->idx > si2->idx ? 1 : -1;
10190
10191 return res;
10192}
10193
10194/*
10195 * "sort({list})" function
10196 */
10197 static void
10198do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
10199{
10200 list_T *l;
10201 listitem_T *li;
10202 sortItem_T *ptrs;
10203 sortinfo_T *old_sortinfo;
10204 sortinfo_T info;
10205 long len;
10206 long i;
10207
10208 /* Pointer to current info struct used in compare function. Save and
10209 * restore the current one for nested calls. */
10210 old_sortinfo = sortinfo;
10211 sortinfo = &info;
10212
10213 if (argvars[0].v_type != VAR_LIST)
10214 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
10215 else
10216 {
10217 l = argvars[0].vval.v_list;
10218 if (l == NULL || tv_check_lock(l->lv_lock,
10219 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
10220 TRUE))
10221 goto theend;
10222 rettv->vval.v_list = l;
10223 rettv->v_type = VAR_LIST;
10224 ++l->lv_refcount;
10225
10226 len = list_len(l);
10227 if (len <= 1)
10228 goto theend; /* short list sorts pretty quickly */
10229
10230 info.item_compare_ic = FALSE;
10231 info.item_compare_numeric = FALSE;
10232 info.item_compare_numbers = FALSE;
10233#ifdef FEAT_FLOAT
10234 info.item_compare_float = FALSE;
10235#endif
10236 info.item_compare_func = NULL;
10237 info.item_compare_partial = NULL;
10238 info.item_compare_selfdict = NULL;
10239 if (argvars[1].v_type != VAR_UNKNOWN)
10240 {
10241 /* optional second argument: {func} */
10242 if (argvars[1].v_type == VAR_FUNC)
10243 info.item_compare_func = argvars[1].vval.v_string;
10244 else if (argvars[1].v_type == VAR_PARTIAL)
10245 info.item_compare_partial = argvars[1].vval.v_partial;
10246 else
10247 {
10248 int error = FALSE;
10249
10250 i = (long)get_tv_number_chk(&argvars[1], &error);
10251 if (error)
10252 goto theend; /* type error; errmsg already given */
10253 if (i == 1)
10254 info.item_compare_ic = TRUE;
10255 else if (argvars[1].v_type != VAR_NUMBER)
10256 info.item_compare_func = get_tv_string(&argvars[1]);
10257 else if (i != 0)
10258 {
10259 EMSG(_(e_invarg));
10260 goto theend;
10261 }
10262 if (info.item_compare_func != NULL)
10263 {
10264 if (*info.item_compare_func == NUL)
10265 {
10266 /* empty string means default sort */
10267 info.item_compare_func = NULL;
10268 }
10269 else if (STRCMP(info.item_compare_func, "n") == 0)
10270 {
10271 info.item_compare_func = NULL;
10272 info.item_compare_numeric = TRUE;
10273 }
10274 else if (STRCMP(info.item_compare_func, "N") == 0)
10275 {
10276 info.item_compare_func = NULL;
10277 info.item_compare_numbers = TRUE;
10278 }
10279#ifdef FEAT_FLOAT
10280 else if (STRCMP(info.item_compare_func, "f") == 0)
10281 {
10282 info.item_compare_func = NULL;
10283 info.item_compare_float = TRUE;
10284 }
10285#endif
10286 else if (STRCMP(info.item_compare_func, "i") == 0)
10287 {
10288 info.item_compare_func = NULL;
10289 info.item_compare_ic = TRUE;
10290 }
10291 }
10292 }
10293
10294 if (argvars[2].v_type != VAR_UNKNOWN)
10295 {
10296 /* optional third argument: {dict} */
10297 if (argvars[2].v_type != VAR_DICT)
10298 {
10299 EMSG(_(e_dictreq));
10300 goto theend;
10301 }
10302 info.item_compare_selfdict = argvars[2].vval.v_dict;
10303 }
10304 }
10305
10306 /* Make an array with each entry pointing to an item in the List. */
10307 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
10308 if (ptrs == NULL)
10309 goto theend;
10310
10311 i = 0;
10312 if (sort)
10313 {
10314 /* sort(): ptrs will be the list to sort */
10315 for (li = l->lv_first; li != NULL; li = li->li_next)
10316 {
10317 ptrs[i].item = li;
10318 ptrs[i].idx = i;
10319 ++i;
10320 }
10321
10322 info.item_compare_func_err = FALSE;
10323 info.item_compare_keep_zero = FALSE;
10324 /* test the compare function */
10325 if ((info.item_compare_func != NULL
10326 || info.item_compare_partial != NULL)
10327 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
10328 == ITEM_COMPARE_FAIL)
10329 EMSG(_("E702: Sort compare function failed"));
10330 else
10331 {
10332 /* Sort the array with item pointers. */
10333 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
10334 info.item_compare_func == NULL
10335 && info.item_compare_partial == NULL
10336 ? item_compare : item_compare2);
10337
10338 if (!info.item_compare_func_err)
10339 {
10340 /* Clear the List and append the items in sorted order. */
10341 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
10342 l->lv_len = 0;
10343 for (i = 0; i < len; ++i)
10344 list_append(l, ptrs[i].item);
10345 }
10346 }
10347 }
10348 else
10349 {
10350 int (*item_compare_func_ptr)(const void *, const void *);
10351
10352 /* f_uniq(): ptrs will be a stack of items to remove */
10353 info.item_compare_func_err = FALSE;
10354 info.item_compare_keep_zero = TRUE;
10355 item_compare_func_ptr = info.item_compare_func != NULL
10356 || info.item_compare_partial != NULL
10357 ? item_compare2 : item_compare;
10358
10359 for (li = l->lv_first; li != NULL && li->li_next != NULL;
10360 li = li->li_next)
10361 {
10362 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
10363 == 0)
10364 ptrs[i++].item = li;
10365 if (info.item_compare_func_err)
10366 {
10367 EMSG(_("E882: Uniq compare function failed"));
10368 break;
10369 }
10370 }
10371
10372 if (!info.item_compare_func_err)
10373 {
10374 while (--i >= 0)
10375 {
10376 li = ptrs[i].item->li_next;
10377 ptrs[i].item->li_next = li->li_next;
10378 if (li->li_next != NULL)
10379 li->li_next->li_prev = ptrs[i].item;
10380 else
10381 l->lv_last = ptrs[i].item;
10382 list_fix_watch(l, li);
10383 listitem_free(li);
10384 l->lv_len--;
10385 }
10386 }
10387 }
10388
10389 vim_free(ptrs);
10390 }
10391theend:
10392 sortinfo = old_sortinfo;
10393}
10394
10395/*
10396 * "sort({list})" function
10397 */
10398 static void
10399f_sort(typval_T *argvars, typval_T *rettv)
10400{
10401 do_sort_uniq(argvars, rettv, TRUE);
10402}
10403
10404/*
10405 * "uniq({list})" function
10406 */
10407 static void
10408f_uniq(typval_T *argvars, typval_T *rettv)
10409{
10410 do_sort_uniq(argvars, rettv, FALSE);
10411}
10412
10413/*
10414 * "soundfold({word})" function
10415 */
10416 static void
10417f_soundfold(typval_T *argvars, typval_T *rettv)
10418{
10419 char_u *s;
10420
10421 rettv->v_type = VAR_STRING;
10422 s = get_tv_string(&argvars[0]);
10423#ifdef FEAT_SPELL
10424 rettv->vval.v_string = eval_soundfold(s);
10425#else
10426 rettv->vval.v_string = vim_strsave(s);
10427#endif
10428}
10429
10430/*
10431 * "spellbadword()" function
10432 */
10433 static void
10434f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10435{
10436 char_u *word = (char_u *)"";
10437 hlf_T attr = HLF_COUNT;
10438 int len = 0;
10439
10440 if (rettv_list_alloc(rettv) == FAIL)
10441 return;
10442
10443#ifdef FEAT_SPELL
10444 if (argvars[0].v_type == VAR_UNKNOWN)
10445 {
10446 /* Find the start and length of the badly spelled word. */
10447 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10448 if (len != 0)
10449 word = ml_get_cursor();
10450 }
10451 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10452 {
10453 char_u *str = get_tv_string_chk(&argvars[0]);
10454 int capcol = -1;
10455
10456 if (str != NULL)
10457 {
10458 /* Check the argument for spelling. */
10459 while (*str != NUL)
10460 {
10461 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10462 if (attr != HLF_COUNT)
10463 {
10464 word = str;
10465 break;
10466 }
10467 str += len;
10468 }
10469 }
10470 }
10471#endif
10472
10473 list_append_string(rettv->vval.v_list, word, len);
10474 list_append_string(rettv->vval.v_list, (char_u *)(
10475 attr == HLF_SPB ? "bad" :
10476 attr == HLF_SPR ? "rare" :
10477 attr == HLF_SPL ? "local" :
10478 attr == HLF_SPC ? "caps" :
10479 ""), -1);
10480}
10481
10482/*
10483 * "spellsuggest()" function
10484 */
10485 static void
10486f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10487{
10488#ifdef FEAT_SPELL
10489 char_u *str;
10490 int typeerr = FALSE;
10491 int maxcount;
10492 garray_T ga;
10493 int i;
10494 listitem_T *li;
10495 int need_capital = FALSE;
10496#endif
10497
10498 if (rettv_list_alloc(rettv) == FAIL)
10499 return;
10500
10501#ifdef FEAT_SPELL
10502 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10503 {
10504 str = get_tv_string(&argvars[0]);
10505 if (argvars[1].v_type != VAR_UNKNOWN)
10506 {
10507 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr);
10508 if (maxcount <= 0)
10509 return;
10510 if (argvars[2].v_type != VAR_UNKNOWN)
10511 {
10512 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr);
10513 if (typeerr)
10514 return;
10515 }
10516 }
10517 else
10518 maxcount = 25;
10519
10520 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10521
10522 for (i = 0; i < ga.ga_len; ++i)
10523 {
10524 str = ((char_u **)ga.ga_data)[i];
10525
10526 li = listitem_alloc();
10527 if (li == NULL)
10528 vim_free(str);
10529 else
10530 {
10531 li->li_tv.v_type = VAR_STRING;
10532 li->li_tv.v_lock = 0;
10533 li->li_tv.vval.v_string = str;
10534 list_append(rettv->vval.v_list, li);
10535 }
10536 }
10537 ga_clear(&ga);
10538 }
10539#endif
10540}
10541
10542 static void
10543f_split(typval_T *argvars, typval_T *rettv)
10544{
10545 char_u *str;
10546 char_u *end;
10547 char_u *pat = NULL;
10548 regmatch_T regmatch;
10549 char_u patbuf[NUMBUFLEN];
10550 char_u *save_cpo;
10551 int match;
10552 colnr_T col = 0;
10553 int keepempty = FALSE;
10554 int typeerr = FALSE;
10555
10556 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10557 save_cpo = p_cpo;
10558 p_cpo = (char_u *)"";
10559
10560 str = get_tv_string(&argvars[0]);
10561 if (argvars[1].v_type != VAR_UNKNOWN)
10562 {
10563 pat = get_tv_string_buf_chk(&argvars[1], patbuf);
10564 if (pat == NULL)
10565 typeerr = TRUE;
10566 if (argvars[2].v_type != VAR_UNKNOWN)
10567 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr);
10568 }
10569 if (pat == NULL || *pat == NUL)
10570 pat = (char_u *)"[\\x01- ]\\+";
10571
10572 if (rettv_list_alloc(rettv) == FAIL)
10573 return;
10574 if (typeerr)
10575 return;
10576
10577 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10578 if (regmatch.regprog != NULL)
10579 {
10580 regmatch.rm_ic = FALSE;
10581 while (*str != NUL || keepempty)
10582 {
10583 if (*str == NUL)
10584 match = FALSE; /* empty item at the end */
10585 else
10586 match = vim_regexec_nl(&regmatch, str, col);
10587 if (match)
10588 end = regmatch.startp[0];
10589 else
10590 end = str + STRLEN(str);
10591 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10592 && *str != NUL && match && end < regmatch.endp[0]))
10593 {
10594 if (list_append_string(rettv->vval.v_list, str,
10595 (int)(end - str)) == FAIL)
10596 break;
10597 }
10598 if (!match)
10599 break;
10600 /* Advance to just after the match. */
10601 if (regmatch.endp[0] > str)
10602 col = 0;
10603 else
10604 {
10605 /* Don't get stuck at the same match. */
10606#ifdef FEAT_MBYTE
10607 col = (*mb_ptr2len)(regmatch.endp[0]);
10608#else
10609 col = 1;
10610#endif
10611 }
10612 str = regmatch.endp[0];
10613 }
10614
10615 vim_regfree(regmatch.regprog);
10616 }
10617
10618 p_cpo = save_cpo;
10619}
10620
10621#ifdef FEAT_FLOAT
10622/*
10623 * "sqrt()" function
10624 */
10625 static void
10626f_sqrt(typval_T *argvars, typval_T *rettv)
10627{
10628 float_T f = 0.0;
10629
10630 rettv->v_type = VAR_FLOAT;
10631 if (get_float_arg(argvars, &f) == OK)
10632 rettv->vval.v_float = sqrt(f);
10633 else
10634 rettv->vval.v_float = 0.0;
10635}
10636
10637/*
10638 * "str2float()" function
10639 */
10640 static void
10641f_str2float(typval_T *argvars, typval_T *rettv)
10642{
10643 char_u *p = skipwhite(get_tv_string(&argvars[0]));
10644
10645 if (*p == '+')
10646 p = skipwhite(p + 1);
10647 (void)string2float(p, &rettv->vval.v_float);
10648 rettv->v_type = VAR_FLOAT;
10649}
10650#endif
10651
10652/*
10653 * "str2nr()" function
10654 */
10655 static void
10656f_str2nr(typval_T *argvars, typval_T *rettv)
10657{
10658 int base = 10;
10659 char_u *p;
10660 varnumber_T n;
10661 int what;
10662
10663 if (argvars[1].v_type != VAR_UNKNOWN)
10664 {
10665 base = (int)get_tv_number(&argvars[1]);
10666 if (base != 2 && base != 8 && base != 10 && base != 16)
10667 {
10668 EMSG(_(e_invarg));
10669 return;
10670 }
10671 }
10672
10673 p = skipwhite(get_tv_string(&argvars[0]));
10674 if (*p == '+')
10675 p = skipwhite(p + 1);
10676 switch (base)
10677 {
10678 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10679 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10680 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10681 default: what = 0;
10682 }
10683 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
10684 rettv->vval.v_number = n;
10685}
10686
10687#ifdef HAVE_STRFTIME
10688/*
10689 * "strftime({format}[, {time}])" function
10690 */
10691 static void
10692f_strftime(typval_T *argvars, typval_T *rettv)
10693{
10694 char_u result_buf[256];
10695 struct tm *curtime;
10696 time_t seconds;
10697 char_u *p;
10698
10699 rettv->v_type = VAR_STRING;
10700
10701 p = get_tv_string(&argvars[0]);
10702 if (argvars[1].v_type == VAR_UNKNOWN)
10703 seconds = time(NULL);
10704 else
10705 seconds = (time_t)get_tv_number(&argvars[1]);
10706 curtime = localtime(&seconds);
10707 /* MSVC returns NULL for an invalid value of seconds. */
10708 if (curtime == NULL)
10709 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10710 else
10711 {
10712# ifdef FEAT_MBYTE
10713 vimconv_T conv;
10714 char_u *enc;
10715
10716 conv.vc_type = CONV_NONE;
10717 enc = enc_locale();
10718 convert_setup(&conv, p_enc, enc);
10719 if (conv.vc_type != CONV_NONE)
10720 p = string_convert(&conv, p, NULL);
10721# endif
10722 if (p != NULL)
10723 (void)strftime((char *)result_buf, sizeof(result_buf),
10724 (char *)p, curtime);
10725 else
10726 result_buf[0] = NUL;
10727
10728# ifdef FEAT_MBYTE
10729 if (conv.vc_type != CONV_NONE)
10730 vim_free(p);
10731 convert_setup(&conv, enc, p_enc);
10732 if (conv.vc_type != CONV_NONE)
10733 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10734 else
10735# endif
10736 rettv->vval.v_string = vim_strsave(result_buf);
10737
10738# ifdef FEAT_MBYTE
10739 /* Release conversion descriptors */
10740 convert_setup(&conv, NULL, NULL);
10741 vim_free(enc);
10742# endif
10743 }
10744}
10745#endif
10746
10747/*
10748 * "strgetchar()" function
10749 */
10750 static void
10751f_strgetchar(typval_T *argvars, typval_T *rettv)
10752{
10753 char_u *str;
10754 int len;
10755 int error = FALSE;
10756 int charidx;
10757
10758 rettv->vval.v_number = -1;
10759 str = get_tv_string_chk(&argvars[0]);
10760 if (str == NULL)
10761 return;
10762 len = (int)STRLEN(str);
10763 charidx = (int)get_tv_number_chk(&argvars[1], &error);
10764 if (error)
10765 return;
10766#ifdef FEAT_MBYTE
10767 {
10768 int byteidx = 0;
10769
10770 while (charidx >= 0 && byteidx < len)
10771 {
10772 if (charidx == 0)
10773 {
10774 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10775 break;
10776 }
10777 --charidx;
10778 byteidx += mb_cptr2len(str + byteidx);
10779 }
10780 }
10781#else
10782 if (charidx < len)
10783 rettv->vval.v_number = str[charidx];
10784#endif
10785}
10786
10787/*
10788 * "stridx()" function
10789 */
10790 static void
10791f_stridx(typval_T *argvars, typval_T *rettv)
10792{
10793 char_u buf[NUMBUFLEN];
10794 char_u *needle;
10795 char_u *haystack;
10796 char_u *save_haystack;
10797 char_u *pos;
10798 int start_idx;
10799
10800 needle = get_tv_string_chk(&argvars[1]);
10801 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf);
10802 rettv->vval.v_number = -1;
10803 if (needle == NULL || haystack == NULL)
10804 return; /* type error; errmsg already given */
10805
10806 if (argvars[2].v_type != VAR_UNKNOWN)
10807 {
10808 int error = FALSE;
10809
10810 start_idx = (int)get_tv_number_chk(&argvars[2], &error);
10811 if (error || start_idx >= (int)STRLEN(haystack))
10812 return;
10813 if (start_idx >= 0)
10814 haystack += start_idx;
10815 }
10816
10817 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10818 if (pos != NULL)
10819 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10820}
10821
10822/*
10823 * "string()" function
10824 */
10825 static void
10826f_string(typval_T *argvars, typval_T *rettv)
10827{
10828 char_u *tofree;
10829 char_u numbuf[NUMBUFLEN];
10830
10831 rettv->v_type = VAR_STRING;
10832 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10833 get_copyID());
10834 /* Make a copy if we have a value but it's not in allocated memory. */
10835 if (rettv->vval.v_string != NULL && tofree == NULL)
10836 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10837}
10838
10839/*
10840 * "strlen()" function
10841 */
10842 static void
10843f_strlen(typval_T *argvars, typval_T *rettv)
10844{
10845 rettv->vval.v_number = (varnumber_T)(STRLEN(
10846 get_tv_string(&argvars[0])));
10847}
10848
10849/*
10850 * "strchars()" function
10851 */
10852 static void
10853f_strchars(typval_T *argvars, typval_T *rettv)
10854{
10855 char_u *s = get_tv_string(&argvars[0]);
10856 int skipcc = 0;
10857#ifdef FEAT_MBYTE
10858 varnumber_T len = 0;
10859 int (*func_mb_ptr2char_adv)(char_u **pp);
10860#endif
10861
10862 if (argvars[1].v_type != VAR_UNKNOWN)
10863 skipcc = (int)get_tv_number_chk(&argvars[1], NULL);
10864 if (skipcc < 0 || skipcc > 1)
10865 EMSG(_(e_invarg));
10866 else
10867 {
10868#ifdef FEAT_MBYTE
10869 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10870 while (*s != NUL)
10871 {
10872 func_mb_ptr2char_adv(&s);
10873 ++len;
10874 }
10875 rettv->vval.v_number = len;
10876#else
10877 rettv->vval.v_number = (varnumber_T)(STRLEN(s));
10878#endif
10879 }
10880}
10881
10882/*
10883 * "strdisplaywidth()" function
10884 */
10885 static void
10886f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10887{
10888 char_u *s = get_tv_string(&argvars[0]);
10889 int col = 0;
10890
10891 if (argvars[1].v_type != VAR_UNKNOWN)
10892 col = (int)get_tv_number(&argvars[1]);
10893
10894 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10895}
10896
10897/*
10898 * "strwidth()" function
10899 */
10900 static void
10901f_strwidth(typval_T *argvars, typval_T *rettv)
10902{
10903 char_u *s = get_tv_string(&argvars[0]);
10904
10905 rettv->vval.v_number = (varnumber_T)(
10906#ifdef FEAT_MBYTE
10907 mb_string2cells(s, -1)
10908#else
10909 STRLEN(s)
10910#endif
10911 );
10912}
10913
10914/*
10915 * "strcharpart()" function
10916 */
10917 static void
10918f_strcharpart(typval_T *argvars, typval_T *rettv)
10919{
10920#ifdef FEAT_MBYTE
10921 char_u *p;
10922 int nchar;
10923 int nbyte = 0;
10924 int charlen;
10925 int len = 0;
10926 int slen;
10927 int error = FALSE;
10928
10929 p = get_tv_string(&argvars[0]);
10930 slen = (int)STRLEN(p);
10931
10932 nchar = (int)get_tv_number_chk(&argvars[1], &error);
10933 if (!error)
10934 {
10935 if (nchar > 0)
10936 while (nchar > 0 && nbyte < slen)
10937 {
10938 nbyte += mb_cptr2len(p + nbyte);
10939 --nchar;
10940 }
10941 else
10942 nbyte = nchar;
10943 if (argvars[2].v_type != VAR_UNKNOWN)
10944 {
10945 charlen = (int)get_tv_number(&argvars[2]);
10946 while (charlen > 0 && nbyte + len < slen)
10947 {
10948 int off = nbyte + len;
10949
10950 if (off < 0)
10951 len += 1;
10952 else
10953 len += mb_cptr2len(p + off);
10954 --charlen;
10955 }
10956 }
10957 else
10958 len = slen - nbyte; /* default: all bytes that are available. */
10959 }
10960
10961 /*
10962 * Only return the overlap between the specified part and the actual
10963 * string.
10964 */
10965 if (nbyte < 0)
10966 {
10967 len += nbyte;
10968 nbyte = 0;
10969 }
10970 else if (nbyte > slen)
10971 nbyte = slen;
10972 if (len < 0)
10973 len = 0;
10974 else if (nbyte + len > slen)
10975 len = slen - nbyte;
10976
10977 rettv->v_type = VAR_STRING;
10978 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
10979#else
10980 f_strpart(argvars, rettv);
10981#endif
10982}
10983
10984/*
10985 * "strpart()" function
10986 */
10987 static void
10988f_strpart(typval_T *argvars, typval_T *rettv)
10989{
10990 char_u *p;
10991 int n;
10992 int len;
10993 int slen;
10994 int error = FALSE;
10995
10996 p = get_tv_string(&argvars[0]);
10997 slen = (int)STRLEN(p);
10998
10999 n = (int)get_tv_number_chk(&argvars[1], &error);
11000 if (error)
11001 len = 0;
11002 else if (argvars[2].v_type != VAR_UNKNOWN)
11003 len = (int)get_tv_number(&argvars[2]);
11004 else
11005 len = slen - n; /* default len: all bytes that are available. */
11006
11007 /*
11008 * Only return the overlap between the specified part and the actual
11009 * string.
11010 */
11011 if (n < 0)
11012 {
11013 len += n;
11014 n = 0;
11015 }
11016 else if (n > slen)
11017 n = slen;
11018 if (len < 0)
11019 len = 0;
11020 else if (n + len > slen)
11021 len = slen - n;
11022
11023 rettv->v_type = VAR_STRING;
11024 rettv->vval.v_string = vim_strnsave(p + n, len);
11025}
11026
11027/*
11028 * "strridx()" function
11029 */
11030 static void
11031f_strridx(typval_T *argvars, typval_T *rettv)
11032{
11033 char_u buf[NUMBUFLEN];
11034 char_u *needle;
11035 char_u *haystack;
11036 char_u *rest;
11037 char_u *lastmatch = NULL;
11038 int haystack_len, end_idx;
11039
11040 needle = get_tv_string_chk(&argvars[1]);
11041 haystack = get_tv_string_buf_chk(&argvars[0], buf);
11042
11043 rettv->vval.v_number = -1;
11044 if (needle == NULL || haystack == NULL)
11045 return; /* type error; errmsg already given */
11046
11047 haystack_len = (int)STRLEN(haystack);
11048 if (argvars[2].v_type != VAR_UNKNOWN)
11049 {
11050 /* Third argument: upper limit for index */
11051 end_idx = (int)get_tv_number_chk(&argvars[2], NULL);
11052 if (end_idx < 0)
11053 return; /* can never find a match */
11054 }
11055 else
11056 end_idx = haystack_len;
11057
11058 if (*needle == NUL)
11059 {
11060 /* Empty string matches past the end. */
11061 lastmatch = haystack + end_idx;
11062 }
11063 else
11064 {
11065 for (rest = haystack; *rest != '\0'; ++rest)
11066 {
11067 rest = (char_u *)strstr((char *)rest, (char *)needle);
11068 if (rest == NULL || rest > haystack + end_idx)
11069 break;
11070 lastmatch = rest;
11071 }
11072 }
11073
11074 if (lastmatch == NULL)
11075 rettv->vval.v_number = -1;
11076 else
11077 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11078}
11079
11080/*
11081 * "strtrans()" function
11082 */
11083 static void
11084f_strtrans(typval_T *argvars, typval_T *rettv)
11085{
11086 rettv->v_type = VAR_STRING;
11087 rettv->vval.v_string = transstr(get_tv_string(&argvars[0]));
11088}
11089
11090/*
11091 * "submatch()" function
11092 */
11093 static void
11094f_submatch(typval_T *argvars, typval_T *rettv)
11095{
11096 int error = FALSE;
11097 int no;
11098 int retList = 0;
11099
11100 no = (int)get_tv_number_chk(&argvars[0], &error);
11101 if (error)
11102 return;
11103 error = FALSE;
11104 if (argvars[1].v_type != VAR_UNKNOWN)
11105 retList = (int)get_tv_number_chk(&argvars[1], &error);
11106 if (error)
11107 return;
11108
11109 if (retList == 0)
11110 {
11111 rettv->v_type = VAR_STRING;
11112 rettv->vval.v_string = reg_submatch(no);
11113 }
11114 else
11115 {
11116 rettv->v_type = VAR_LIST;
11117 rettv->vval.v_list = reg_submatch_list(no);
11118 }
11119}
11120
11121/*
11122 * "substitute()" function
11123 */
11124 static void
11125f_substitute(typval_T *argvars, typval_T *rettv)
11126{
11127 char_u patbuf[NUMBUFLEN];
11128 char_u subbuf[NUMBUFLEN];
11129 char_u flagsbuf[NUMBUFLEN];
11130
11131 char_u *str = get_tv_string_chk(&argvars[0]);
11132 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011133 char_u *sub = NULL;
11134 typval_T *expr = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011135 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf);
11136
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011137 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11138 expr = &argvars[2];
11139 else
11140 sub = get_tv_string_buf_chk(&argvars[2], subbuf);
11141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011142 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011143 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11144 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011145 rettv->vval.v_string = NULL;
11146 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011147 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011148}
11149
11150/*
11151 * "synID(lnum, col, trans)" function
11152 */
11153 static void
11154f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11155{
11156 int id = 0;
11157#ifdef FEAT_SYN_HL
11158 linenr_T lnum;
11159 colnr_T col;
11160 int trans;
11161 int transerr = FALSE;
11162
11163 lnum = get_tv_lnum(argvars); /* -1 on type error */
11164 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11165 trans = (int)get_tv_number_chk(&argvars[2], &transerr);
11166
11167 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11168 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11169 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11170#endif
11171
11172 rettv->vval.v_number = id;
11173}
11174
11175/*
11176 * "synIDattr(id, what [, mode])" function
11177 */
11178 static void
11179f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11180{
11181 char_u *p = NULL;
11182#ifdef FEAT_SYN_HL
11183 int id;
11184 char_u *what;
11185 char_u *mode;
11186 char_u modebuf[NUMBUFLEN];
11187 int modec;
11188
11189 id = (int)get_tv_number(&argvars[0]);
11190 what = get_tv_string(&argvars[1]);
11191 if (argvars[2].v_type != VAR_UNKNOWN)
11192 {
11193 mode = get_tv_string_buf(&argvars[2], modebuf);
11194 modec = TOLOWER_ASC(mode[0]);
11195 if (modec != 't' && modec != 'c' && modec != 'g')
11196 modec = 0; /* replace invalid with current */
11197 }
11198 else
11199 {
11200#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11201 if (USE_24BIT)
11202 modec = 'g';
11203 else
11204#endif
11205 if (t_colors > 1)
11206 modec = 'c';
11207 else
11208 modec = 't';
11209 }
11210
11211
11212 switch (TOLOWER_ASC(what[0]))
11213 {
11214 case 'b':
11215 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11216 p = highlight_color(id, what, modec);
11217 else /* bold */
11218 p = highlight_has_attr(id, HL_BOLD, modec);
11219 break;
11220
11221 case 'f': /* fg[#] or font */
11222 p = highlight_color(id, what, modec);
11223 break;
11224
11225 case 'i':
11226 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11227 p = highlight_has_attr(id, HL_INVERSE, modec);
11228 else /* italic */
11229 p = highlight_has_attr(id, HL_ITALIC, modec);
11230 break;
11231
11232 case 'n': /* name */
11233 p = get_highlight_name(NULL, id - 1);
11234 break;
11235
11236 case 'r': /* reverse */
11237 p = highlight_has_attr(id, HL_INVERSE, modec);
11238 break;
11239
11240 case 's':
11241 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11242 p = highlight_color(id, what, modec);
11243 else /* standout */
11244 p = highlight_has_attr(id, HL_STANDOUT, modec);
11245 break;
11246
11247 case 'u':
11248 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11249 /* underline */
11250 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11251 else
11252 /* undercurl */
11253 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11254 break;
11255 }
11256
11257 if (p != NULL)
11258 p = vim_strsave(p);
11259#endif
11260 rettv->v_type = VAR_STRING;
11261 rettv->vval.v_string = p;
11262}
11263
11264/*
11265 * "synIDtrans(id)" function
11266 */
11267 static void
11268f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11269{
11270 int id;
11271
11272#ifdef FEAT_SYN_HL
11273 id = (int)get_tv_number(&argvars[0]);
11274
11275 if (id > 0)
11276 id = syn_get_final_id(id);
11277 else
11278#endif
11279 id = 0;
11280
11281 rettv->vval.v_number = id;
11282}
11283
11284/*
11285 * "synconcealed(lnum, col)" function
11286 */
11287 static void
11288f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11289{
11290#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11291 linenr_T lnum;
11292 colnr_T col;
11293 int syntax_flags = 0;
11294 int cchar;
11295 int matchid = 0;
11296 char_u str[NUMBUFLEN];
11297#endif
11298
11299 rettv->v_type = VAR_LIST;
11300 rettv->vval.v_list = NULL;
11301
11302#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11303 lnum = get_tv_lnum(argvars); /* -1 on type error */
11304 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11305
11306 vim_memset(str, NUL, sizeof(str));
11307
11308 if (rettv_list_alloc(rettv) != FAIL)
11309 {
11310 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11311 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11312 && curwin->w_p_cole > 0)
11313 {
11314 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11315 syntax_flags = get_syntax_info(&matchid);
11316
11317 /* get the conceal character */
11318 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11319 {
11320 cchar = syn_get_sub_char();
11321 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL)
11322 cchar = lcs_conceal;
11323 if (cchar != NUL)
11324 {
11325# ifdef FEAT_MBYTE
11326 if (has_mbyte)
11327 (*mb_char2bytes)(cchar, str);
11328 else
11329# endif
11330 str[0] = cchar;
11331 }
11332 }
11333 }
11334
11335 list_append_number(rettv->vval.v_list,
11336 (syntax_flags & HL_CONCEAL) != 0);
11337 /* -1 to auto-determine strlen */
11338 list_append_string(rettv->vval.v_list, str, -1);
11339 list_append_number(rettv->vval.v_list, matchid);
11340 }
11341#endif
11342}
11343
11344/*
11345 * "synstack(lnum, col)" function
11346 */
11347 static void
11348f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11349{
11350#ifdef FEAT_SYN_HL
11351 linenr_T lnum;
11352 colnr_T col;
11353 int i;
11354 int id;
11355#endif
11356
11357 rettv->v_type = VAR_LIST;
11358 rettv->vval.v_list = NULL;
11359
11360#ifdef FEAT_SYN_HL
11361 lnum = get_tv_lnum(argvars); /* -1 on type error */
11362 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */
11363
11364 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11365 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11366 && rettv_list_alloc(rettv) != FAIL)
11367 {
11368 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11369 for (i = 0; ; ++i)
11370 {
11371 id = syn_get_stack_item(i);
11372 if (id < 0)
11373 break;
11374 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11375 break;
11376 }
11377 }
11378#endif
11379}
11380
11381 static void
11382get_cmd_output_as_rettv(
11383 typval_T *argvars,
11384 typval_T *rettv,
11385 int retlist)
11386{
11387 char_u *res = NULL;
11388 char_u *p;
11389 char_u *infile = NULL;
11390 char_u buf[NUMBUFLEN];
11391 int err = FALSE;
11392 FILE *fd;
11393 list_T *list = NULL;
11394 int flags = SHELL_SILENT;
11395
11396 rettv->v_type = VAR_STRING;
11397 rettv->vval.v_string = NULL;
11398 if (check_restricted() || check_secure())
11399 goto errret;
11400
11401 if (argvars[1].v_type != VAR_UNKNOWN)
11402 {
11403 /*
11404 * Write the string to a temp file, to be used for input of the shell
11405 * command.
11406 */
11407 if ((infile = vim_tempname('i', TRUE)) == NULL)
11408 {
11409 EMSG(_(e_notmp));
11410 goto errret;
11411 }
11412
11413 fd = mch_fopen((char *)infile, WRITEBIN);
11414 if (fd == NULL)
11415 {
11416 EMSG2(_(e_notopen), infile);
11417 goto errret;
11418 }
11419 if (argvars[1].v_type == VAR_LIST)
11420 {
11421 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11422 err = TRUE;
11423 }
11424 else
11425 {
11426 size_t len;
11427
11428 p = get_tv_string_buf_chk(&argvars[1], buf);
11429 if (p == NULL)
11430 {
11431 fclose(fd);
11432 goto errret; /* type error; errmsg already given */
11433 }
11434 len = STRLEN(p);
11435 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11436 err = TRUE;
11437 }
11438 if (fclose(fd) != 0)
11439 err = TRUE;
11440 if (err)
11441 {
11442 EMSG(_("E677: Error writing temp file"));
11443 goto errret;
11444 }
11445 }
11446
11447 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11448 * echoes typeahead, that messes up the display. */
11449 if (!msg_silent)
11450 flags += SHELL_COOKED;
11451
11452 if (retlist)
11453 {
11454 int len;
11455 listitem_T *li;
11456 char_u *s = NULL;
11457 char_u *start;
11458 char_u *end;
11459 int i;
11460
11461 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len);
11462 if (res == NULL)
11463 goto errret;
11464
11465 list = list_alloc();
11466 if (list == NULL)
11467 goto errret;
11468
11469 for (i = 0; i < len; ++i)
11470 {
11471 start = res + i;
11472 while (i < len && res[i] != NL)
11473 ++i;
11474 end = res + i;
11475
11476 s = alloc((unsigned)(end - start + 1));
11477 if (s == NULL)
11478 goto errret;
11479
11480 for (p = s; start < end; ++p, ++start)
11481 *p = *start == NUL ? NL : *start;
11482 *p = NUL;
11483
11484 li = listitem_alloc();
11485 if (li == NULL)
11486 {
11487 vim_free(s);
11488 goto errret;
11489 }
11490 li->li_tv.v_type = VAR_STRING;
11491 li->li_tv.v_lock = 0;
11492 li->li_tv.vval.v_string = s;
11493 list_append(list, li);
11494 }
11495
11496 ++list->lv_refcount;
11497 rettv->v_type = VAR_LIST;
11498 rettv->vval.v_list = list;
11499 list = NULL;
11500 }
11501 else
11502 {
11503 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL);
11504#ifdef USE_CR
11505 /* translate <CR> into <NL> */
11506 if (res != NULL)
11507 {
11508 char_u *s;
11509
11510 for (s = res; *s; ++s)
11511 {
11512 if (*s == CAR)
11513 *s = NL;
11514 }
11515 }
11516#else
11517# ifdef USE_CRNL
11518 /* translate <CR><NL> into <NL> */
11519 if (res != NULL)
11520 {
11521 char_u *s, *d;
11522
11523 d = res;
11524 for (s = res; *s; ++s)
11525 {
11526 if (s[0] == CAR && s[1] == NL)
11527 ++s;
11528 *d++ = *s;
11529 }
11530 *d = NUL;
11531 }
11532# endif
11533#endif
11534 rettv->vval.v_string = res;
11535 res = NULL;
11536 }
11537
11538errret:
11539 if (infile != NULL)
11540 {
11541 mch_remove(infile);
11542 vim_free(infile);
11543 }
11544 if (res != NULL)
11545 vim_free(res);
11546 if (list != NULL)
11547 list_free(list);
11548}
11549
11550/*
11551 * "system()" function
11552 */
11553 static void
11554f_system(typval_T *argvars, typval_T *rettv)
11555{
11556 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11557}
11558
11559/*
11560 * "systemlist()" function
11561 */
11562 static void
11563f_systemlist(typval_T *argvars, typval_T *rettv)
11564{
11565 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11566}
11567
11568/*
11569 * "tabpagebuflist()" function
11570 */
11571 static void
11572f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11573{
11574#ifdef FEAT_WINDOWS
11575 tabpage_T *tp;
11576 win_T *wp = NULL;
11577
11578 if (argvars[0].v_type == VAR_UNKNOWN)
11579 wp = firstwin;
11580 else
11581 {
11582 tp = find_tabpage((int)get_tv_number(&argvars[0]));
11583 if (tp != NULL)
11584 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11585 }
11586 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11587 {
11588 for (; wp != NULL; wp = wp->w_next)
11589 if (list_append_number(rettv->vval.v_list,
11590 wp->w_buffer->b_fnum) == FAIL)
11591 break;
11592 }
11593#endif
11594}
11595
11596
11597/*
11598 * "tabpagenr()" function
11599 */
11600 static void
11601f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11602{
11603 int nr = 1;
11604#ifdef FEAT_WINDOWS
11605 char_u *arg;
11606
11607 if (argvars[0].v_type != VAR_UNKNOWN)
11608 {
11609 arg = get_tv_string_chk(&argvars[0]);
11610 nr = 0;
11611 if (arg != NULL)
11612 {
11613 if (STRCMP(arg, "$") == 0)
11614 nr = tabpage_index(NULL) - 1;
11615 else
11616 EMSG2(_(e_invexpr2), arg);
11617 }
11618 }
11619 else
11620 nr = tabpage_index(curtab);
11621#endif
11622 rettv->vval.v_number = nr;
11623}
11624
11625
11626#ifdef FEAT_WINDOWS
11627static int get_winnr(tabpage_T *tp, typval_T *argvar);
11628
11629/*
11630 * Common code for tabpagewinnr() and winnr().
11631 */
11632 static int
11633get_winnr(tabpage_T *tp, typval_T *argvar)
11634{
11635 win_T *twin;
11636 int nr = 1;
11637 win_T *wp;
11638 char_u *arg;
11639
11640 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11641 if (argvar->v_type != VAR_UNKNOWN)
11642 {
11643 arg = get_tv_string_chk(argvar);
11644 if (arg == NULL)
11645 nr = 0; /* type error; errmsg already given */
11646 else if (STRCMP(arg, "$") == 0)
11647 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11648 else if (STRCMP(arg, "#") == 0)
11649 {
11650 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11651 if (twin == NULL)
11652 nr = 0;
11653 }
11654 else
11655 {
11656 EMSG2(_(e_invexpr2), arg);
11657 nr = 0;
11658 }
11659 }
11660
11661 if (nr > 0)
11662 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11663 wp != twin; wp = wp->w_next)
11664 {
11665 if (wp == NULL)
11666 {
11667 /* didn't find it in this tabpage */
11668 nr = 0;
11669 break;
11670 }
11671 ++nr;
11672 }
11673 return nr;
11674}
11675#endif
11676
11677/*
11678 * "tabpagewinnr()" function
11679 */
11680 static void
11681f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11682{
11683 int nr = 1;
11684#ifdef FEAT_WINDOWS
11685 tabpage_T *tp;
11686
11687 tp = find_tabpage((int)get_tv_number(&argvars[0]));
11688 if (tp == NULL)
11689 nr = 0;
11690 else
11691 nr = get_winnr(tp, &argvars[1]);
11692#endif
11693 rettv->vval.v_number = nr;
11694}
11695
11696
11697/*
11698 * "tagfiles()" function
11699 */
11700 static void
11701f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11702{
11703 char_u *fname;
11704 tagname_T tn;
11705 int first;
11706
11707 if (rettv_list_alloc(rettv) == FAIL)
11708 return;
11709 fname = alloc(MAXPATHL);
11710 if (fname == NULL)
11711 return;
11712
11713 for (first = TRUE; ; first = FALSE)
11714 if (get_tagfname(&tn, first, fname) == FAIL
11715 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11716 break;
11717 tagname_free(&tn);
11718 vim_free(fname);
11719}
11720
11721/*
11722 * "taglist()" function
11723 */
11724 static void
11725f_taglist(typval_T *argvars, typval_T *rettv)
11726{
11727 char_u *tag_pattern;
11728
11729 tag_pattern = get_tv_string(&argvars[0]);
11730
11731 rettv->vval.v_number = FALSE;
11732 if (*tag_pattern == NUL)
11733 return;
11734
11735 if (rettv_list_alloc(rettv) == OK)
11736 (void)get_tags(rettv->vval.v_list, tag_pattern);
11737}
11738
11739/*
11740 * "tempname()" function
11741 */
11742 static void
11743f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11744{
11745 static int x = 'A';
11746
11747 rettv->v_type = VAR_STRING;
11748 rettv->vval.v_string = vim_tempname(x, FALSE);
11749
11750 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11751 * names. Skip 'I' and 'O', they are used for shell redirection. */
11752 do
11753 {
11754 if (x == 'Z')
11755 x = '0';
11756 else if (x == '9')
11757 x = 'A';
11758 else
11759 {
11760#ifdef EBCDIC
11761 if (x == 'I')
11762 x = 'J';
11763 else if (x == 'R')
11764 x = 'S';
11765 else
11766#endif
11767 ++x;
11768 }
11769 } while (x == 'I' || x == 'O');
11770}
11771
11772#ifdef FEAT_FLOAT
11773/*
11774 * "tan()" function
11775 */
11776 static void
11777f_tan(typval_T *argvars, typval_T *rettv)
11778{
11779 float_T f = 0.0;
11780
11781 rettv->v_type = VAR_FLOAT;
11782 if (get_float_arg(argvars, &f) == OK)
11783 rettv->vval.v_float = tan(f);
11784 else
11785 rettv->vval.v_float = 0.0;
11786}
11787
11788/*
11789 * "tanh()" function
11790 */
11791 static void
11792f_tanh(typval_T *argvars, typval_T *rettv)
11793{
11794 float_T f = 0.0;
11795
11796 rettv->v_type = VAR_FLOAT;
11797 if (get_float_arg(argvars, &f) == OK)
11798 rettv->vval.v_float = tanh(f);
11799 else
11800 rettv->vval.v_float = 0.0;
11801}
11802#endif
11803
11804/*
11805 * "test_alloc_fail(id, countdown, repeat)" function
11806 */
11807 static void
11808f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
11809{
11810 if (argvars[0].v_type != VAR_NUMBER
11811 || argvars[0].vval.v_number <= 0
11812 || argvars[1].v_type != VAR_NUMBER
11813 || argvars[1].vval.v_number < 0
11814 || argvars[2].v_type != VAR_NUMBER)
11815 EMSG(_(e_invarg));
11816 else
11817 {
11818 alloc_fail_id = argvars[0].vval.v_number;
11819 if (alloc_fail_id >= aid_last)
11820 EMSG(_(e_invarg));
11821 alloc_fail_countdown = argvars[1].vval.v_number;
11822 alloc_fail_repeat = argvars[2].vval.v_number;
11823 did_outofmem_msg = FALSE;
11824 }
11825}
11826
11827/*
11828 * "test_autochdir()"
11829 */
11830 static void
11831f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11832{
11833#if defined(FEAT_AUTOCHDIR)
11834 test_autochdir = TRUE;
11835#endif
11836}
11837
11838/*
11839 * "test_disable_char_avail({expr})" function
11840 */
11841 static void
11842f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED)
11843{
11844 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]);
11845}
11846
11847/*
11848 * "test_garbagecollect_now()" function
11849 */
11850 static void
11851f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11852{
11853 /* This is dangerous, any Lists and Dicts used internally may be freed
11854 * while still in use. */
11855 garbage_collect(TRUE);
11856}
11857
11858#ifdef FEAT_JOB_CHANNEL
11859 static void
11860f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
11861{
11862 rettv->v_type = VAR_CHANNEL;
11863 rettv->vval.v_channel = NULL;
11864}
11865#endif
11866
11867 static void
11868f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
11869{
11870 rettv->v_type = VAR_DICT;
11871 rettv->vval.v_dict = NULL;
11872}
11873
11874#ifdef FEAT_JOB_CHANNEL
11875 static void
11876f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
11877{
11878 rettv->v_type = VAR_JOB;
11879 rettv->vval.v_job = NULL;
11880}
11881#endif
11882
11883 static void
11884f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
11885{
11886 rettv->v_type = VAR_LIST;
11887 rettv->vval.v_list = NULL;
11888}
11889
11890 static void
11891f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
11892{
11893 rettv->v_type = VAR_PARTIAL;
11894 rettv->vval.v_partial = NULL;
11895}
11896
11897 static void
11898f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
11899{
11900 rettv->v_type = VAR_STRING;
11901 rettv->vval.v_string = NULL;
11902}
11903
11904 static void
11905f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
11906{
11907 time_for_testing = (time_t)get_tv_number(&argvars[0]);
11908}
11909
11910#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
11911/*
11912 * Get a callback from "arg". It can be a Funcref or a function name.
11913 * When "arg" is zero return an empty string.
11914 * Return NULL for an invalid argument.
11915 */
11916 char_u *
11917get_callback(typval_T *arg, partial_T **pp)
11918{
11919 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11920 {
11921 *pp = arg->vval.v_partial;
11922 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011923 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011924 }
11925 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020011926 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011927 {
11928 func_ref(arg->vval.v_string);
11929 return arg->vval.v_string;
11930 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011931 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11932 return (char_u *)"";
11933 EMSG(_("E921: Invalid callback argument"));
11934 return NULL;
11935}
11936
11937/*
11938 * Unref/free "callback" and "partial" retured by get_callback().
11939 */
11940 void
11941free_callback(char_u *callback, partial_T *partial)
11942{
11943 if (partial != NULL)
11944 partial_unref(partial);
11945 else if (callback != NULL)
11946 {
11947 func_unref(callback);
11948 vim_free(callback);
11949 }
11950}
11951#endif
11952
11953#ifdef FEAT_TIMERS
11954/*
11955 * "timer_start(time, callback [, options])" function
11956 */
11957 static void
11958f_timer_start(typval_T *argvars, typval_T *rettv)
11959{
11960 long msec = (long)get_tv_number(&argvars[0]);
11961 timer_T *timer;
11962 int repeat = 0;
11963 char_u *callback;
11964 dict_T *dict;
11965
11966 if (check_secure())
11967 return;
11968 if (argvars[2].v_type != VAR_UNKNOWN)
11969 {
11970 if (argvars[2].v_type != VAR_DICT
11971 || (dict = argvars[2].vval.v_dict) == NULL)
11972 {
11973 EMSG2(_(e_invarg2), get_tv_string(&argvars[2]));
11974 return;
11975 }
11976 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
11977 repeat = get_dict_number(dict, (char_u *)"repeat");
11978 }
11979
11980 timer = create_timer(msec, repeat);
11981 callback = get_callback(&argvars[1], &timer->tr_partial);
11982 if (callback == NULL)
11983 {
11984 stop_timer(timer);
11985 rettv->vval.v_number = -1;
11986 }
11987 else
11988 {
Bram Moolenaar3ab14352016-07-30 22:32:11 +020011989 if (timer->tr_partial == NULL)
11990 timer->tr_callback = vim_strsave(callback);
11991 else
11992 /* pointer into the partial */
11993 timer->tr_callback = callback;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011994 rettv->vval.v_number = timer->tr_id;
11995 }
11996}
11997
11998/*
11999 * "timer_stop(timer)" function
12000 */
12001 static void
12002f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12003{
12004 timer_T *timer;
12005
12006 if (argvars[0].v_type != VAR_NUMBER)
12007 {
12008 EMSG(_(e_number_exp));
12009 return;
12010 }
12011 timer = find_timer((int)get_tv_number(&argvars[0]));
12012 if (timer != NULL)
12013 stop_timer(timer);
12014}
12015#endif
12016
12017/*
12018 * "tolower(string)" function
12019 */
12020 static void
12021f_tolower(typval_T *argvars, typval_T *rettv)
12022{
12023 char_u *p;
12024
12025 p = vim_strsave(get_tv_string(&argvars[0]));
12026 rettv->v_type = VAR_STRING;
12027 rettv->vval.v_string = p;
12028
12029 if (p != NULL)
12030 while (*p != NUL)
12031 {
12032#ifdef FEAT_MBYTE
12033 int l;
12034
12035 if (enc_utf8)
12036 {
12037 int c, lc;
12038
12039 c = utf_ptr2char(p);
12040 lc = utf_tolower(c);
12041 l = utf_ptr2len(p);
12042 /* TODO: reallocate string when byte count changes. */
12043 if (utf_char2len(lc) == l)
12044 utf_char2bytes(lc, p);
12045 p += l;
12046 }
12047 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
12048 p += l; /* skip multi-byte character */
12049 else
12050#endif
12051 {
12052 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
12053 ++p;
12054 }
12055 }
12056}
12057
12058/*
12059 * "toupper(string)" function
12060 */
12061 static void
12062f_toupper(typval_T *argvars, typval_T *rettv)
12063{
12064 rettv->v_type = VAR_STRING;
12065 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0]));
12066}
12067
12068/*
12069 * "tr(string, fromstr, tostr)" function
12070 */
12071 static void
12072f_tr(typval_T *argvars, typval_T *rettv)
12073{
12074 char_u *in_str;
12075 char_u *fromstr;
12076 char_u *tostr;
12077 char_u *p;
12078#ifdef FEAT_MBYTE
12079 int inlen;
12080 int fromlen;
12081 int tolen;
12082 int idx;
12083 char_u *cpstr;
12084 int cplen;
12085 int first = TRUE;
12086#endif
12087 char_u buf[NUMBUFLEN];
12088 char_u buf2[NUMBUFLEN];
12089 garray_T ga;
12090
12091 in_str = get_tv_string(&argvars[0]);
12092 fromstr = get_tv_string_buf_chk(&argvars[1], buf);
12093 tostr = get_tv_string_buf_chk(&argvars[2], buf2);
12094
12095 /* Default return value: empty string. */
12096 rettv->v_type = VAR_STRING;
12097 rettv->vval.v_string = NULL;
12098 if (fromstr == NULL || tostr == NULL)
12099 return; /* type error; errmsg already given */
12100 ga_init2(&ga, (int)sizeof(char), 80);
12101
12102#ifdef FEAT_MBYTE
12103 if (!has_mbyte)
12104#endif
12105 /* not multi-byte: fromstr and tostr must be the same length */
12106 if (STRLEN(fromstr) != STRLEN(tostr))
12107 {
12108#ifdef FEAT_MBYTE
12109error:
12110#endif
12111 EMSG2(_(e_invarg2), fromstr);
12112 ga_clear(&ga);
12113 return;
12114 }
12115
12116 /* fromstr and tostr have to contain the same number of chars */
12117 while (*in_str != NUL)
12118 {
12119#ifdef FEAT_MBYTE
12120 if (has_mbyte)
12121 {
12122 inlen = (*mb_ptr2len)(in_str);
12123 cpstr = in_str;
12124 cplen = inlen;
12125 idx = 0;
12126 for (p = fromstr; *p != NUL; p += fromlen)
12127 {
12128 fromlen = (*mb_ptr2len)(p);
12129 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12130 {
12131 for (p = tostr; *p != NUL; p += tolen)
12132 {
12133 tolen = (*mb_ptr2len)(p);
12134 if (idx-- == 0)
12135 {
12136 cplen = tolen;
12137 cpstr = p;
12138 break;
12139 }
12140 }
12141 if (*p == NUL) /* tostr is shorter than fromstr */
12142 goto error;
12143 break;
12144 }
12145 ++idx;
12146 }
12147
12148 if (first && cpstr == in_str)
12149 {
12150 /* Check that fromstr and tostr have the same number of
12151 * (multi-byte) characters. Done only once when a character
12152 * of in_str doesn't appear in fromstr. */
12153 first = FALSE;
12154 for (p = tostr; *p != NUL; p += tolen)
12155 {
12156 tolen = (*mb_ptr2len)(p);
12157 --idx;
12158 }
12159 if (idx != 0)
12160 goto error;
12161 }
12162
12163 (void)ga_grow(&ga, cplen);
12164 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12165 ga.ga_len += cplen;
12166
12167 in_str += inlen;
12168 }
12169 else
12170#endif
12171 {
12172 /* When not using multi-byte chars we can do it faster. */
12173 p = vim_strchr(fromstr, *in_str);
12174 if (p != NULL)
12175 ga_append(&ga, tostr[p - fromstr]);
12176 else
12177 ga_append(&ga, *in_str);
12178 ++in_str;
12179 }
12180 }
12181
12182 /* add a terminating NUL */
12183 (void)ga_grow(&ga, 1);
12184 ga_append(&ga, NUL);
12185
12186 rettv->vval.v_string = ga.ga_data;
12187}
12188
12189#ifdef FEAT_FLOAT
12190/*
12191 * "trunc({float})" function
12192 */
12193 static void
12194f_trunc(typval_T *argvars, typval_T *rettv)
12195{
12196 float_T f = 0.0;
12197
12198 rettv->v_type = VAR_FLOAT;
12199 if (get_float_arg(argvars, &f) == OK)
12200 /* trunc() is not in C90, use floor() or ceil() instead. */
12201 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12202 else
12203 rettv->vval.v_float = 0.0;
12204}
12205#endif
12206
12207/*
12208 * "type(expr)" function
12209 */
12210 static void
12211f_type(typval_T *argvars, typval_T *rettv)
12212{
12213 int n = -1;
12214
12215 switch (argvars[0].v_type)
12216 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012217 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12218 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012219 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012220 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12221 case VAR_LIST: n = VAR_TYPE_LIST; break;
12222 case VAR_DICT: n = VAR_TYPE_DICT; break;
12223 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012224 case VAR_SPECIAL:
12225 if (argvars[0].vval.v_number == VVAL_FALSE
12226 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012227 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012228 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012229 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012230 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012231 case VAR_JOB: n = VAR_TYPE_JOB; break;
12232 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012233 case VAR_UNKNOWN:
12234 EMSG2(_(e_intern2), "f_type(UNKNOWN)");
12235 n = -1;
12236 break;
12237 }
12238 rettv->vval.v_number = n;
12239}
12240
12241/*
12242 * "undofile(name)" function
12243 */
12244 static void
12245f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12246{
12247 rettv->v_type = VAR_STRING;
12248#ifdef FEAT_PERSISTENT_UNDO
12249 {
12250 char_u *fname = get_tv_string(&argvars[0]);
12251
12252 if (*fname == NUL)
12253 {
12254 /* If there is no file name there will be no undo file. */
12255 rettv->vval.v_string = NULL;
12256 }
12257 else
12258 {
12259 char_u *ffname = FullName_save(fname, FALSE);
12260
12261 if (ffname != NULL)
12262 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12263 vim_free(ffname);
12264 }
12265 }
12266#else
12267 rettv->vval.v_string = NULL;
12268#endif
12269}
12270
12271/*
12272 * "undotree()" function
12273 */
12274 static void
12275f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12276{
12277 if (rettv_dict_alloc(rettv) == OK)
12278 {
12279 dict_T *dict = rettv->vval.v_dict;
12280 list_T *list;
12281
12282 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL);
12283 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL);
12284 dict_add_nr_str(dict, "save_last",
12285 (long)curbuf->b_u_save_nr_last, NULL);
12286 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL);
12287 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL);
12288 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL);
12289
12290 list = list_alloc();
12291 if (list != NULL)
12292 {
12293 u_eval_tree(curbuf->b_u_oldhead, list);
12294 dict_add_list(dict, "entries", list);
12295 }
12296 }
12297}
12298
12299/*
12300 * "values(dict)" function
12301 */
12302 static void
12303f_values(typval_T *argvars, typval_T *rettv)
12304{
12305 dict_list(argvars, rettv, 1);
12306}
12307
12308/*
12309 * "virtcol(string)" function
12310 */
12311 static void
12312f_virtcol(typval_T *argvars, typval_T *rettv)
12313{
12314 colnr_T vcol = 0;
12315 pos_T *fp;
12316 int fnum = curbuf->b_fnum;
12317
12318 fp = var2fpos(&argvars[0], FALSE, &fnum);
12319 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12320 && fnum == curbuf->b_fnum)
12321 {
12322 getvvcol(curwin, fp, NULL, NULL, &vcol);
12323 ++vcol;
12324 }
12325
12326 rettv->vval.v_number = vcol;
12327}
12328
12329/*
12330 * "visualmode()" function
12331 */
12332 static void
12333f_visualmode(typval_T *argvars, typval_T *rettv)
12334{
12335 char_u str[2];
12336
12337 rettv->v_type = VAR_STRING;
12338 str[0] = curbuf->b_visual_mode_eval;
12339 str[1] = NUL;
12340 rettv->vval.v_string = vim_strsave(str);
12341
12342 /* A non-zero number or non-empty string argument: reset mode. */
12343 if (non_zero_arg(&argvars[0]))
12344 curbuf->b_visual_mode_eval = NUL;
12345}
12346
12347/*
12348 * "wildmenumode()" function
12349 */
12350 static void
12351f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12352{
12353#ifdef FEAT_WILDMENU
12354 if (wild_menu_showing)
12355 rettv->vval.v_number = 1;
12356#endif
12357}
12358
12359/*
12360 * "winbufnr(nr)" function
12361 */
12362 static void
12363f_winbufnr(typval_T *argvars, typval_T *rettv)
12364{
12365 win_T *wp;
12366
12367 wp = find_win_by_nr(&argvars[0], NULL);
12368 if (wp == NULL)
12369 rettv->vval.v_number = -1;
12370 else
12371 rettv->vval.v_number = wp->w_buffer->b_fnum;
12372}
12373
12374/*
12375 * "wincol()" function
12376 */
12377 static void
12378f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12379{
12380 validate_cursor();
12381 rettv->vval.v_number = curwin->w_wcol + 1;
12382}
12383
12384/*
12385 * "winheight(nr)" function
12386 */
12387 static void
12388f_winheight(typval_T *argvars, typval_T *rettv)
12389{
12390 win_T *wp;
12391
12392 wp = find_win_by_nr(&argvars[0], NULL);
12393 if (wp == NULL)
12394 rettv->vval.v_number = -1;
12395 else
12396 rettv->vval.v_number = wp->w_height;
12397}
12398
12399/*
12400 * "winline()" function
12401 */
12402 static void
12403f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12404{
12405 validate_cursor();
12406 rettv->vval.v_number = curwin->w_wrow + 1;
12407}
12408
12409/*
12410 * "winnr()" function
12411 */
12412 static void
12413f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12414{
12415 int nr = 1;
12416
12417#ifdef FEAT_WINDOWS
12418 nr = get_winnr(curtab, &argvars[0]);
12419#endif
12420 rettv->vval.v_number = nr;
12421}
12422
12423/*
12424 * "winrestcmd()" function
12425 */
12426 static void
12427f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12428{
12429#ifdef FEAT_WINDOWS
12430 win_T *wp;
12431 int winnr = 1;
12432 garray_T ga;
12433 char_u buf[50];
12434
12435 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012436 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012437 {
12438 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12439 ga_concat(&ga, buf);
12440 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12441 ga_concat(&ga, buf);
12442 ++winnr;
12443 }
12444 ga_append(&ga, NUL);
12445
12446 rettv->vval.v_string = ga.ga_data;
12447#else
12448 rettv->vval.v_string = NULL;
12449#endif
12450 rettv->v_type = VAR_STRING;
12451}
12452
12453/*
12454 * "winrestview()" function
12455 */
12456 static void
12457f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12458{
12459 dict_T *dict;
12460
12461 if (argvars[0].v_type != VAR_DICT
12462 || (dict = argvars[0].vval.v_dict) == NULL)
12463 EMSG(_(e_invarg));
12464 else
12465 {
12466 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
12467 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum");
12468 if (dict_find(dict, (char_u *)"col", -1) != NULL)
12469 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col");
12470#ifdef FEAT_VIRTUALEDIT
12471 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
12472 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd");
12473#endif
12474 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12475 {
12476 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant");
12477 curwin->w_set_curswant = FALSE;
12478 }
12479
12480 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
12481 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline"));
12482#ifdef FEAT_DIFF
12483 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
12484 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill");
12485#endif
12486 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
12487 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol");
12488 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
12489 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol");
12490
12491 check_cursor();
12492 win_new_height(curwin, curwin->w_height);
12493# ifdef FEAT_WINDOWS
12494 win_new_width(curwin, W_WIDTH(curwin));
12495# endif
12496 changed_window_setting();
12497
12498 if (curwin->w_topline <= 0)
12499 curwin->w_topline = 1;
12500 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12501 curwin->w_topline = curbuf->b_ml.ml_line_count;
12502#ifdef FEAT_DIFF
12503 check_topfill(curwin, TRUE);
12504#endif
12505 }
12506}
12507
12508/*
12509 * "winsaveview()" function
12510 */
12511 static void
12512f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12513{
12514 dict_T *dict;
12515
12516 if (rettv_dict_alloc(rettv) == FAIL)
12517 return;
12518 dict = rettv->vval.v_dict;
12519
12520 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL);
12521 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL);
12522#ifdef FEAT_VIRTUALEDIT
12523 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL);
12524#endif
12525 update_curswant();
12526 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL);
12527
12528 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL);
12529#ifdef FEAT_DIFF
12530 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL);
12531#endif
12532 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL);
12533 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL);
12534}
12535
12536/*
12537 * "winwidth(nr)" function
12538 */
12539 static void
12540f_winwidth(typval_T *argvars, typval_T *rettv)
12541{
12542 win_T *wp;
12543
12544 wp = find_win_by_nr(&argvars[0], NULL);
12545 if (wp == NULL)
12546 rettv->vval.v_number = -1;
12547 else
12548#ifdef FEAT_WINDOWS
12549 rettv->vval.v_number = wp->w_width;
12550#else
12551 rettv->vval.v_number = Columns;
12552#endif
12553}
12554
12555/*
12556 * "wordcount()" function
12557 */
12558 static void
12559f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12560{
12561 if (rettv_dict_alloc(rettv) == FAIL)
12562 return;
12563 cursor_pos_info(rettv->vval.v_dict);
12564}
12565
12566/*
12567 * "writefile()" function
12568 */
12569 static void
12570f_writefile(typval_T *argvars, typval_T *rettv)
12571{
12572 int binary = FALSE;
12573 int append = FALSE;
12574 char_u *fname;
12575 FILE *fd;
12576 int ret = 0;
12577
12578 if (check_restricted() || check_secure())
12579 return;
12580
12581 if (argvars[0].v_type != VAR_LIST)
12582 {
12583 EMSG2(_(e_listarg), "writefile()");
12584 return;
12585 }
12586 if (argvars[0].vval.v_list == NULL)
12587 return;
12588
12589 if (argvars[2].v_type != VAR_UNKNOWN)
12590 {
12591 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL)
12592 binary = TRUE;
12593 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL)
12594 append = TRUE;
12595 }
12596
12597 /* Always open the file in binary mode, library functions have a mind of
12598 * their own about CR-LF conversion. */
12599 fname = get_tv_string(&argvars[1]);
12600 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12601 append ? APPENDBIN : WRITEBIN)) == NULL)
12602 {
12603 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
12604 ret = -1;
12605 }
12606 else
12607 {
12608 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL)
12609 ret = -1;
12610 fclose(fd);
12611 }
12612
12613 rettv->vval.v_number = ret;
12614}
12615
12616/*
12617 * "xor(expr, expr)" function
12618 */
12619 static void
12620f_xor(typval_T *argvars, typval_T *rettv)
12621{
12622 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL)
12623 ^ get_tv_number_chk(&argvars[1], NULL);
12624}
12625
12626
12627#endif /* FEAT_EVAL */