Mercurial > vim
comparison src/evalfunc.c @ 9571:5eaa708ab50d v7.4.2063
commit https://github.com/vim/vim/commit/73dad1e64cb42842d8259cb1a255a6fa59822f76
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jul 17 22:13:49 2016 +0200
patch 7.4.2063
Problem: eval.c is still too big.
Solution: Split off internal functions to evalfunc.c.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 17 Jul 2016 22:30:06 +0200 |
parents | |
children | 7ee1c83e3ddf |
comparison
equal
deleted
inserted
replaced
9570:695186e11daa | 9571:5eaa708ab50d |
---|---|
1 /* 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 | |
31 static char *e_listarg = N_("E686: Argument of %s must be a List"); | |
32 #ifdef FEAT_QUICKFIX | |
33 static char *e_stringreq = N_("E928: String required"); | |
34 #endif | |
35 | |
36 #ifdef FEAT_FLOAT | |
37 static void f_abs(typval_T *argvars, typval_T *rettv); | |
38 static void f_acos(typval_T *argvars, typval_T *rettv); | |
39 #endif | |
40 static void f_add(typval_T *argvars, typval_T *rettv); | |
41 static void f_and(typval_T *argvars, typval_T *rettv); | |
42 static void f_append(typval_T *argvars, typval_T *rettv); | |
43 static void f_argc(typval_T *argvars, typval_T *rettv); | |
44 static void f_argidx(typval_T *argvars, typval_T *rettv); | |
45 static void f_arglistid(typval_T *argvars, typval_T *rettv); | |
46 static void f_argv(typval_T *argvars, typval_T *rettv); | |
47 static void f_assert_equal(typval_T *argvars, typval_T *rettv); | |
48 static void f_assert_exception(typval_T *argvars, typval_T *rettv); | |
49 static void f_assert_fails(typval_T *argvars, typval_T *rettv); | |
50 static void f_assert_false(typval_T *argvars, typval_T *rettv); | |
51 static void f_assert_match(typval_T *argvars, typval_T *rettv); | |
52 static void f_assert_notequal(typval_T *argvars, typval_T *rettv); | |
53 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv); | |
54 static void f_assert_true(typval_T *argvars, typval_T *rettv); | |
55 #ifdef FEAT_FLOAT | |
56 static void f_asin(typval_T *argvars, typval_T *rettv); | |
57 static void f_atan(typval_T *argvars, typval_T *rettv); | |
58 static void f_atan2(typval_T *argvars, typval_T *rettv); | |
59 #endif | |
60 static void f_browse(typval_T *argvars, typval_T *rettv); | |
61 static void f_browsedir(typval_T *argvars, typval_T *rettv); | |
62 static void f_bufexists(typval_T *argvars, typval_T *rettv); | |
63 static void f_buflisted(typval_T *argvars, typval_T *rettv); | |
64 static void f_bufloaded(typval_T *argvars, typval_T *rettv); | |
65 static void f_bufname(typval_T *argvars, typval_T *rettv); | |
66 static void f_bufnr(typval_T *argvars, typval_T *rettv); | |
67 static void f_bufwinid(typval_T *argvars, typval_T *rettv); | |
68 static void f_bufwinnr(typval_T *argvars, typval_T *rettv); | |
69 static void f_byte2line(typval_T *argvars, typval_T *rettv); | |
70 static void byteidx(typval_T *argvars, typval_T *rettv, int comp); | |
71 static void f_byteidx(typval_T *argvars, typval_T *rettv); | |
72 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); | |
73 static void f_call(typval_T *argvars, typval_T *rettv); | |
74 #ifdef FEAT_FLOAT | |
75 static void f_ceil(typval_T *argvars, typval_T *rettv); | |
76 #endif | |
77 #ifdef FEAT_JOB_CHANNEL | |
78 static void f_ch_close(typval_T *argvars, typval_T *rettv); | |
79 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv); | |
80 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv); | |
81 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv); | |
82 static void f_ch_getjob(typval_T *argvars, typval_T *rettv); | |
83 static void f_ch_info(typval_T *argvars, typval_T *rettv); | |
84 static void f_ch_log(typval_T *argvars, typval_T *rettv); | |
85 static void f_ch_logfile(typval_T *argvars, typval_T *rettv); | |
86 static void f_ch_open(typval_T *argvars, typval_T *rettv); | |
87 static void f_ch_read(typval_T *argvars, typval_T *rettv); | |
88 static void f_ch_readraw(typval_T *argvars, typval_T *rettv); | |
89 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); | |
90 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); | |
91 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv); | |
92 static void f_ch_status(typval_T *argvars, typval_T *rettv); | |
93 #endif | |
94 static void f_changenr(typval_T *argvars, typval_T *rettv); | |
95 static void f_char2nr(typval_T *argvars, typval_T *rettv); | |
96 static void f_cindent(typval_T *argvars, typval_T *rettv); | |
97 static void f_clearmatches(typval_T *argvars, typval_T *rettv); | |
98 static void f_col(typval_T *argvars, typval_T *rettv); | |
99 #if defined(FEAT_INS_EXPAND) | |
100 static void f_complete(typval_T *argvars, typval_T *rettv); | |
101 static void f_complete_add(typval_T *argvars, typval_T *rettv); | |
102 static void f_complete_check(typval_T *argvars, typval_T *rettv); | |
103 #endif | |
104 static void f_confirm(typval_T *argvars, typval_T *rettv); | |
105 static void f_copy(typval_T *argvars, typval_T *rettv); | |
106 #ifdef FEAT_FLOAT | |
107 static void f_cos(typval_T *argvars, typval_T *rettv); | |
108 static void f_cosh(typval_T *argvars, typval_T *rettv); | |
109 #endif | |
110 static void f_count(typval_T *argvars, typval_T *rettv); | |
111 static void f_cscope_connection(typval_T *argvars, typval_T *rettv); | |
112 static void f_cursor(typval_T *argsvars, typval_T *rettv); | |
113 static void f_deepcopy(typval_T *argvars, typval_T *rettv); | |
114 static void f_delete(typval_T *argvars, typval_T *rettv); | |
115 static void f_did_filetype(typval_T *argvars, typval_T *rettv); | |
116 static void f_diff_filler(typval_T *argvars, typval_T *rettv); | |
117 static void f_diff_hlID(typval_T *argvars, typval_T *rettv); | |
118 static void f_empty(typval_T *argvars, typval_T *rettv); | |
119 static void f_escape(typval_T *argvars, typval_T *rettv); | |
120 static void f_eval(typval_T *argvars, typval_T *rettv); | |
121 static void f_eventhandler(typval_T *argvars, typval_T *rettv); | |
122 static void f_executable(typval_T *argvars, typval_T *rettv); | |
123 static void f_execute(typval_T *argvars, typval_T *rettv); | |
124 static void f_exepath(typval_T *argvars, typval_T *rettv); | |
125 static void f_exists(typval_T *argvars, typval_T *rettv); | |
126 #ifdef FEAT_FLOAT | |
127 static void f_exp(typval_T *argvars, typval_T *rettv); | |
128 #endif | |
129 static void f_expand(typval_T *argvars, typval_T *rettv); | |
130 static void f_extend(typval_T *argvars, typval_T *rettv); | |
131 static void f_feedkeys(typval_T *argvars, typval_T *rettv); | |
132 static void f_filereadable(typval_T *argvars, typval_T *rettv); | |
133 static void f_filewritable(typval_T *argvars, typval_T *rettv); | |
134 static void f_filter(typval_T *argvars, typval_T *rettv); | |
135 static void f_finddir(typval_T *argvars, typval_T *rettv); | |
136 static void f_findfile(typval_T *argvars, typval_T *rettv); | |
137 #ifdef FEAT_FLOAT | |
138 static void f_float2nr(typval_T *argvars, typval_T *rettv); | |
139 static void f_floor(typval_T *argvars, typval_T *rettv); | |
140 static void f_fmod(typval_T *argvars, typval_T *rettv); | |
141 #endif | |
142 static void f_fnameescape(typval_T *argvars, typval_T *rettv); | |
143 static void f_fnamemodify(typval_T *argvars, typval_T *rettv); | |
144 static void f_foldclosed(typval_T *argvars, typval_T *rettv); | |
145 static void f_foldclosedend(typval_T *argvars, typval_T *rettv); | |
146 static void f_foldlevel(typval_T *argvars, typval_T *rettv); | |
147 static void f_foldtext(typval_T *argvars, typval_T *rettv); | |
148 static void f_foldtextresult(typval_T *argvars, typval_T *rettv); | |
149 static void f_foreground(typval_T *argvars, typval_T *rettv); | |
150 static void f_function(typval_T *argvars, typval_T *rettv); | |
151 static void f_garbagecollect(typval_T *argvars, typval_T *rettv); | |
152 static void f_get(typval_T *argvars, typval_T *rettv); | |
153 static void f_getbufline(typval_T *argvars, typval_T *rettv); | |
154 static void f_getbufvar(typval_T *argvars, typval_T *rettv); | |
155 static void f_getchar(typval_T *argvars, typval_T *rettv); | |
156 static void f_getcharmod(typval_T *argvars, typval_T *rettv); | |
157 static void f_getcharsearch(typval_T *argvars, typval_T *rettv); | |
158 static void f_getcmdline(typval_T *argvars, typval_T *rettv); | |
159 #if defined(FEAT_CMDL_COMPL) | |
160 static void f_getcompletion(typval_T *argvars, typval_T *rettv); | |
161 #endif | |
162 static void f_getcmdpos(typval_T *argvars, typval_T *rettv); | |
163 static void f_getcmdtype(typval_T *argvars, typval_T *rettv); | |
164 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); | |
165 static void f_getcwd(typval_T *argvars, typval_T *rettv); | |
166 static void f_getfontname(typval_T *argvars, typval_T *rettv); | |
167 static void f_getfperm(typval_T *argvars, typval_T *rettv); | |
168 static void f_getfsize(typval_T *argvars, typval_T *rettv); | |
169 static void f_getftime(typval_T *argvars, typval_T *rettv); | |
170 static void f_getftype(typval_T *argvars, typval_T *rettv); | |
171 static void f_getline(typval_T *argvars, typval_T *rettv); | |
172 static void f_getmatches(typval_T *argvars, typval_T *rettv); | |
173 static void f_getpid(typval_T *argvars, typval_T *rettv); | |
174 static void f_getcurpos(typval_T *argvars, typval_T *rettv); | |
175 static void f_getpos(typval_T *argvars, typval_T *rettv); | |
176 static void f_getqflist(typval_T *argvars, typval_T *rettv); | |
177 static void f_getreg(typval_T *argvars, typval_T *rettv); | |
178 static void f_getregtype(typval_T *argvars, typval_T *rettv); | |
179 static void f_gettabvar(typval_T *argvars, typval_T *rettv); | |
180 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv); | |
181 static void f_getwinposx(typval_T *argvars, typval_T *rettv); | |
182 static void f_getwinposy(typval_T *argvars, typval_T *rettv); | |
183 static void f_getwinvar(typval_T *argvars, typval_T *rettv); | |
184 static void f_glob(typval_T *argvars, typval_T *rettv); | |
185 static void f_globpath(typval_T *argvars, typval_T *rettv); | |
186 static void f_glob2regpat(typval_T *argvars, typval_T *rettv); | |
187 static void f_has(typval_T *argvars, typval_T *rettv); | |
188 static void f_has_key(typval_T *argvars, typval_T *rettv); | |
189 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); | |
190 static void f_hasmapto(typval_T *argvars, typval_T *rettv); | |
191 static void f_histadd(typval_T *argvars, typval_T *rettv); | |
192 static void f_histdel(typval_T *argvars, typval_T *rettv); | |
193 static void f_histget(typval_T *argvars, typval_T *rettv); | |
194 static void f_histnr(typval_T *argvars, typval_T *rettv); | |
195 static void f_hlID(typval_T *argvars, typval_T *rettv); | |
196 static void f_hlexists(typval_T *argvars, typval_T *rettv); | |
197 static void f_hostname(typval_T *argvars, typval_T *rettv); | |
198 static void f_iconv(typval_T *argvars, typval_T *rettv); | |
199 static void f_indent(typval_T *argvars, typval_T *rettv); | |
200 static void f_index(typval_T *argvars, typval_T *rettv); | |
201 static void f_input(typval_T *argvars, typval_T *rettv); | |
202 static void f_inputdialog(typval_T *argvars, typval_T *rettv); | |
203 static void f_inputlist(typval_T *argvars, typval_T *rettv); | |
204 static void f_inputrestore(typval_T *argvars, typval_T *rettv); | |
205 static void f_inputsave(typval_T *argvars, typval_T *rettv); | |
206 static void f_inputsecret(typval_T *argvars, typval_T *rettv); | |
207 static void f_insert(typval_T *argvars, typval_T *rettv); | |
208 static void f_invert(typval_T *argvars, typval_T *rettv); | |
209 static void f_isdirectory(typval_T *argvars, typval_T *rettv); | |
210 static void f_islocked(typval_T *argvars, typval_T *rettv); | |
211 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | |
212 static void f_isnan(typval_T *argvars, typval_T *rettv); | |
213 #endif | |
214 static void f_items(typval_T *argvars, typval_T *rettv); | |
215 #ifdef FEAT_JOB_CHANNEL | |
216 static void f_job_getchannel(typval_T *argvars, typval_T *rettv); | |
217 static void f_job_info(typval_T *argvars, typval_T *rettv); | |
218 static void f_job_setoptions(typval_T *argvars, typval_T *rettv); | |
219 static void f_job_start(typval_T *argvars, typval_T *rettv); | |
220 static void f_job_stop(typval_T *argvars, typval_T *rettv); | |
221 static void f_job_status(typval_T *argvars, typval_T *rettv); | |
222 #endif | |
223 static void f_join(typval_T *argvars, typval_T *rettv); | |
224 static void f_js_decode(typval_T *argvars, typval_T *rettv); | |
225 static void f_js_encode(typval_T *argvars, typval_T *rettv); | |
226 static void f_json_decode(typval_T *argvars, typval_T *rettv); | |
227 static void f_json_encode(typval_T *argvars, typval_T *rettv); | |
228 static void f_keys(typval_T *argvars, typval_T *rettv); | |
229 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); | |
230 static void f_len(typval_T *argvars, typval_T *rettv); | |
231 static void f_libcall(typval_T *argvars, typval_T *rettv); | |
232 static void f_libcallnr(typval_T *argvars, typval_T *rettv); | |
233 static void f_line(typval_T *argvars, typval_T *rettv); | |
234 static void f_line2byte(typval_T *argvars, typval_T *rettv); | |
235 static void f_lispindent(typval_T *argvars, typval_T *rettv); | |
236 static void f_localtime(typval_T *argvars, typval_T *rettv); | |
237 #ifdef FEAT_FLOAT | |
238 static void f_log(typval_T *argvars, typval_T *rettv); | |
239 static void f_log10(typval_T *argvars, typval_T *rettv); | |
240 #endif | |
241 #ifdef FEAT_LUA | |
242 static void f_luaeval(typval_T *argvars, typval_T *rettv); | |
243 #endif | |
244 static void f_map(typval_T *argvars, typval_T *rettv); | |
245 static void f_maparg(typval_T *argvars, typval_T *rettv); | |
246 static void f_mapcheck(typval_T *argvars, typval_T *rettv); | |
247 static void f_match(typval_T *argvars, typval_T *rettv); | |
248 static void f_matchadd(typval_T *argvars, typval_T *rettv); | |
249 static void f_matchaddpos(typval_T *argvars, typval_T *rettv); | |
250 static void f_matcharg(typval_T *argvars, typval_T *rettv); | |
251 static void f_matchdelete(typval_T *argvars, typval_T *rettv); | |
252 static void f_matchend(typval_T *argvars, typval_T *rettv); | |
253 static void f_matchlist(typval_T *argvars, typval_T *rettv); | |
254 static void f_matchstr(typval_T *argvars, typval_T *rettv); | |
255 static void f_matchstrpos(typval_T *argvars, typval_T *rettv); | |
256 static void f_max(typval_T *argvars, typval_T *rettv); | |
257 static void f_min(typval_T *argvars, typval_T *rettv); | |
258 #ifdef vim_mkdir | |
259 static void f_mkdir(typval_T *argvars, typval_T *rettv); | |
260 #endif | |
261 static void f_mode(typval_T *argvars, typval_T *rettv); | |
262 #ifdef FEAT_MZSCHEME | |
263 static void f_mzeval(typval_T *argvars, typval_T *rettv); | |
264 #endif | |
265 static void f_nextnonblank(typval_T *argvars, typval_T *rettv); | |
266 static void f_nr2char(typval_T *argvars, typval_T *rettv); | |
267 static void f_or(typval_T *argvars, typval_T *rettv); | |
268 static void f_pathshorten(typval_T *argvars, typval_T *rettv); | |
269 #ifdef FEAT_PERL | |
270 static void f_perleval(typval_T *argvars, typval_T *rettv); | |
271 #endif | |
272 #ifdef FEAT_FLOAT | |
273 static void f_pow(typval_T *argvars, typval_T *rettv); | |
274 #endif | |
275 static void f_prevnonblank(typval_T *argvars, typval_T *rettv); | |
276 static void f_printf(typval_T *argvars, typval_T *rettv); | |
277 static void f_pumvisible(typval_T *argvars, typval_T *rettv); | |
278 #ifdef FEAT_PYTHON3 | |
279 static void f_py3eval(typval_T *argvars, typval_T *rettv); | |
280 #endif | |
281 #ifdef FEAT_PYTHON | |
282 static void f_pyeval(typval_T *argvars, typval_T *rettv); | |
283 #endif | |
284 static void f_range(typval_T *argvars, typval_T *rettv); | |
285 static void f_readfile(typval_T *argvars, typval_T *rettv); | |
286 static void f_reltime(typval_T *argvars, typval_T *rettv); | |
287 #ifdef FEAT_FLOAT | |
288 static void f_reltimefloat(typval_T *argvars, typval_T *rettv); | |
289 #endif | |
290 static void f_reltimestr(typval_T *argvars, typval_T *rettv); | |
291 static void f_remote_expr(typval_T *argvars, typval_T *rettv); | |
292 static void f_remote_foreground(typval_T *argvars, typval_T *rettv); | |
293 static void f_remote_peek(typval_T *argvars, typval_T *rettv); | |
294 static void f_remote_read(typval_T *argvars, typval_T *rettv); | |
295 static void f_remote_send(typval_T *argvars, typval_T *rettv); | |
296 static void f_remove(typval_T *argvars, typval_T *rettv); | |
297 static void f_rename(typval_T *argvars, typval_T *rettv); | |
298 static void f_repeat(typval_T *argvars, typval_T *rettv); | |
299 static void f_resolve(typval_T *argvars, typval_T *rettv); | |
300 static void f_reverse(typval_T *argvars, typval_T *rettv); | |
301 #ifdef FEAT_FLOAT | |
302 static void f_round(typval_T *argvars, typval_T *rettv); | |
303 #endif | |
304 static void f_screenattr(typval_T *argvars, typval_T *rettv); | |
305 static void f_screenchar(typval_T *argvars, typval_T *rettv); | |
306 static void f_screencol(typval_T *argvars, typval_T *rettv); | |
307 static void f_screenrow(typval_T *argvars, typval_T *rettv); | |
308 static void f_search(typval_T *argvars, typval_T *rettv); | |
309 static void f_searchdecl(typval_T *argvars, typval_T *rettv); | |
310 static void f_searchpair(typval_T *argvars, typval_T *rettv); | |
311 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); | |
312 static void f_searchpos(typval_T *argvars, typval_T *rettv); | |
313 static void f_server2client(typval_T *argvars, typval_T *rettv); | |
314 static void f_serverlist(typval_T *argvars, typval_T *rettv); | |
315 static void f_setbufvar(typval_T *argvars, typval_T *rettv); | |
316 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); | |
317 static void f_setcmdpos(typval_T *argvars, typval_T *rettv); | |
318 static void f_setfperm(typval_T *argvars, typval_T *rettv); | |
319 static void f_setline(typval_T *argvars, typval_T *rettv); | |
320 static void f_setloclist(typval_T *argvars, typval_T *rettv); | |
321 static void f_setmatches(typval_T *argvars, typval_T *rettv); | |
322 static void f_setpos(typval_T *argvars, typval_T *rettv); | |
323 static void f_setqflist(typval_T *argvars, typval_T *rettv); | |
324 static void f_setreg(typval_T *argvars, typval_T *rettv); | |
325 static void f_settabvar(typval_T *argvars, typval_T *rettv); | |
326 static void f_settabwinvar(typval_T *argvars, typval_T *rettv); | |
327 static void f_setwinvar(typval_T *argvars, typval_T *rettv); | |
328 #ifdef FEAT_CRYPT | |
329 static void f_sha256(typval_T *argvars, typval_T *rettv); | |
330 #endif /* FEAT_CRYPT */ | |
331 static void f_shellescape(typval_T *argvars, typval_T *rettv); | |
332 static void f_shiftwidth(typval_T *argvars, typval_T *rettv); | |
333 static void f_simplify(typval_T *argvars, typval_T *rettv); | |
334 #ifdef FEAT_FLOAT | |
335 static void f_sin(typval_T *argvars, typval_T *rettv); | |
336 static void f_sinh(typval_T *argvars, typval_T *rettv); | |
337 #endif | |
338 static void f_sort(typval_T *argvars, typval_T *rettv); | |
339 static void f_soundfold(typval_T *argvars, typval_T *rettv); | |
340 static void f_spellbadword(typval_T *argvars, typval_T *rettv); | |
341 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); | |
342 static void f_split(typval_T *argvars, typval_T *rettv); | |
343 #ifdef FEAT_FLOAT | |
344 static void f_sqrt(typval_T *argvars, typval_T *rettv); | |
345 static void f_str2float(typval_T *argvars, typval_T *rettv); | |
346 #endif | |
347 static void f_str2nr(typval_T *argvars, typval_T *rettv); | |
348 static void f_strchars(typval_T *argvars, typval_T *rettv); | |
349 #ifdef HAVE_STRFTIME | |
350 static void f_strftime(typval_T *argvars, typval_T *rettv); | |
351 #endif | |
352 static void f_strgetchar(typval_T *argvars, typval_T *rettv); | |
353 static void f_stridx(typval_T *argvars, typval_T *rettv); | |
354 static void f_string(typval_T *argvars, typval_T *rettv); | |
355 static void f_strlen(typval_T *argvars, typval_T *rettv); | |
356 static void f_strcharpart(typval_T *argvars, typval_T *rettv); | |
357 static void f_strpart(typval_T *argvars, typval_T *rettv); | |
358 static void f_strridx(typval_T *argvars, typval_T *rettv); | |
359 static void f_strtrans(typval_T *argvars, typval_T *rettv); | |
360 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); | |
361 static void f_strwidth(typval_T *argvars, typval_T *rettv); | |
362 static void f_submatch(typval_T *argvars, typval_T *rettv); | |
363 static void f_substitute(typval_T *argvars, typval_T *rettv); | |
364 static void f_synID(typval_T *argvars, typval_T *rettv); | |
365 static void f_synIDattr(typval_T *argvars, typval_T *rettv); | |
366 static void f_synIDtrans(typval_T *argvars, typval_T *rettv); | |
367 static void f_synstack(typval_T *argvars, typval_T *rettv); | |
368 static void f_synconcealed(typval_T *argvars, typval_T *rettv); | |
369 static void f_system(typval_T *argvars, typval_T *rettv); | |
370 static void f_systemlist(typval_T *argvars, typval_T *rettv); | |
371 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); | |
372 static void f_tabpagenr(typval_T *argvars, typval_T *rettv); | |
373 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv); | |
374 static void f_taglist(typval_T *argvars, typval_T *rettv); | |
375 static void f_tagfiles(typval_T *argvars, typval_T *rettv); | |
376 static void f_tempname(typval_T *argvars, typval_T *rettv); | |
377 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); | |
378 static void f_test_autochdir(typval_T *argvars, typval_T *rettv); | |
379 static void f_test_disable_char_avail(typval_T *argvars, typval_T *rettv); | |
380 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv); | |
381 #ifdef FEAT_JOB_CHANNEL | |
382 static void f_test_null_channel(typval_T *argvars, typval_T *rettv); | |
383 #endif | |
384 static void f_test_null_dict(typval_T *argvars, typval_T *rettv); | |
385 #ifdef FEAT_JOB_CHANNEL | |
386 static void f_test_null_job(typval_T *argvars, typval_T *rettv); | |
387 #endif | |
388 static void f_test_null_list(typval_T *argvars, typval_T *rettv); | |
389 static void f_test_null_partial(typval_T *argvars, typval_T *rettv); | |
390 static void f_test_null_string(typval_T *argvars, typval_T *rettv); | |
391 static void f_test_settime(typval_T *argvars, typval_T *rettv); | |
392 #ifdef FEAT_FLOAT | |
393 static void f_tan(typval_T *argvars, typval_T *rettv); | |
394 static void f_tanh(typval_T *argvars, typval_T *rettv); | |
395 #endif | |
396 #ifdef FEAT_TIMERS | |
397 static void f_timer_start(typval_T *argvars, typval_T *rettv); | |
398 static void f_timer_stop(typval_T *argvars, typval_T *rettv); | |
399 #endif | |
400 static void f_tolower(typval_T *argvars, typval_T *rettv); | |
401 static void f_toupper(typval_T *argvars, typval_T *rettv); | |
402 static void f_tr(typval_T *argvars, typval_T *rettv); | |
403 #ifdef FEAT_FLOAT | |
404 static void f_trunc(typval_T *argvars, typval_T *rettv); | |
405 #endif | |
406 static void f_type(typval_T *argvars, typval_T *rettv); | |
407 static void f_undofile(typval_T *argvars, typval_T *rettv); | |
408 static void f_undotree(typval_T *argvars, typval_T *rettv); | |
409 static void f_uniq(typval_T *argvars, typval_T *rettv); | |
410 static void f_values(typval_T *argvars, typval_T *rettv); | |
411 static void f_virtcol(typval_T *argvars, typval_T *rettv); | |
412 static void f_visualmode(typval_T *argvars, typval_T *rettv); | |
413 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); | |
414 static void f_win_findbuf(typval_T *argvars, typval_T *rettv); | |
415 static void f_win_getid(typval_T *argvars, typval_T *rettv); | |
416 static void f_win_gotoid(typval_T *argvars, typval_T *rettv); | |
417 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); | |
418 static void f_win_id2win(typval_T *argvars, typval_T *rettv); | |
419 static void f_winbufnr(typval_T *argvars, typval_T *rettv); | |
420 static void f_wincol(typval_T *argvars, typval_T *rettv); | |
421 static void f_winheight(typval_T *argvars, typval_T *rettv); | |
422 static void f_winline(typval_T *argvars, typval_T *rettv); | |
423 static void f_winnr(typval_T *argvars, typval_T *rettv); | |
424 static void f_winrestcmd(typval_T *argvars, typval_T *rettv); | |
425 static void f_winrestview(typval_T *argvars, typval_T *rettv); | |
426 static void f_winsaveview(typval_T *argvars, typval_T *rettv); | |
427 static void f_winwidth(typval_T *argvars, typval_T *rettv); | |
428 static void f_writefile(typval_T *argvars, typval_T *rettv); | |
429 static void f_wordcount(typval_T *argvars, typval_T *rettv); | |
430 static void f_xor(typval_T *argvars, typval_T *rettv); | |
431 | |
432 /* | |
433 * Array with names and number of arguments of all internal functions | |
434 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! | |
435 */ | |
436 static struct fst | |
437 { | |
438 char *f_name; /* function name */ | |
439 char f_min_argc; /* minimal number of arguments */ | |
440 char f_max_argc; /* maximal number of arguments */ | |
441 void (*f_func)(typval_T *args, typval_T *rvar); | |
442 /* implementation of function */ | |
443 } functions[] = | |
444 { | |
445 #ifdef FEAT_FLOAT | |
446 {"abs", 1, 1, f_abs}, | |
447 {"acos", 1, 1, f_acos}, /* WJMc */ | |
448 #endif | |
449 {"add", 2, 2, f_add}, | |
450 {"and", 2, 2, f_and}, | |
451 {"append", 2, 2, f_append}, | |
452 {"argc", 0, 0, f_argc}, | |
453 {"argidx", 0, 0, f_argidx}, | |
454 {"arglistid", 0, 2, f_arglistid}, | |
455 {"argv", 0, 1, f_argv}, | |
456 #ifdef FEAT_FLOAT | |
457 {"asin", 1, 1, f_asin}, /* WJMc */ | |
458 #endif | |
459 {"assert_equal", 2, 3, f_assert_equal}, | |
460 {"assert_exception", 1, 2, f_assert_exception}, | |
461 {"assert_fails", 1, 2, f_assert_fails}, | |
462 {"assert_false", 1, 2, f_assert_false}, | |
463 {"assert_match", 2, 3, f_assert_match}, | |
464 {"assert_notequal", 2, 3, f_assert_notequal}, | |
465 {"assert_notmatch", 2, 3, f_assert_notmatch}, | |
466 {"assert_true", 1, 2, f_assert_true}, | |
467 #ifdef FEAT_FLOAT | |
468 {"atan", 1, 1, f_atan}, | |
469 {"atan2", 2, 2, f_atan2}, | |
470 #endif | |
471 {"browse", 4, 4, f_browse}, | |
472 {"browsedir", 2, 2, f_browsedir}, | |
473 {"bufexists", 1, 1, f_bufexists}, | |
474 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */ | |
475 {"buffer_name", 1, 1, f_bufname}, /* obsolete */ | |
476 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */ | |
477 {"buflisted", 1, 1, f_buflisted}, | |
478 {"bufloaded", 1, 1, f_bufloaded}, | |
479 {"bufname", 1, 1, f_bufname}, | |
480 {"bufnr", 1, 2, f_bufnr}, | |
481 {"bufwinid", 1, 1, f_bufwinid}, | |
482 {"bufwinnr", 1, 1, f_bufwinnr}, | |
483 {"byte2line", 1, 1, f_byte2line}, | |
484 {"byteidx", 2, 2, f_byteidx}, | |
485 {"byteidxcomp", 2, 2, f_byteidxcomp}, | |
486 {"call", 2, 3, f_call}, | |
487 #ifdef FEAT_FLOAT | |
488 {"ceil", 1, 1, f_ceil}, | |
489 #endif | |
490 #ifdef FEAT_JOB_CHANNEL | |
491 {"ch_close", 1, 1, f_ch_close}, | |
492 {"ch_evalexpr", 2, 3, f_ch_evalexpr}, | |
493 {"ch_evalraw", 2, 3, f_ch_evalraw}, | |
494 {"ch_getbufnr", 2, 2, f_ch_getbufnr}, | |
495 {"ch_getjob", 1, 1, f_ch_getjob}, | |
496 {"ch_info", 1, 1, f_ch_info}, | |
497 {"ch_log", 1, 2, f_ch_log}, | |
498 {"ch_logfile", 1, 2, f_ch_logfile}, | |
499 {"ch_open", 1, 2, f_ch_open}, | |
500 {"ch_read", 1, 2, f_ch_read}, | |
501 {"ch_readraw", 1, 2, f_ch_readraw}, | |
502 {"ch_sendexpr", 2, 3, f_ch_sendexpr}, | |
503 {"ch_sendraw", 2, 3, f_ch_sendraw}, | |
504 {"ch_setoptions", 2, 2, f_ch_setoptions}, | |
505 {"ch_status", 1, 1, f_ch_status}, | |
506 #endif | |
507 {"changenr", 0, 0, f_changenr}, | |
508 {"char2nr", 1, 2, f_char2nr}, | |
509 {"cindent", 1, 1, f_cindent}, | |
510 {"clearmatches", 0, 0, f_clearmatches}, | |
511 {"col", 1, 1, f_col}, | |
512 #if defined(FEAT_INS_EXPAND) | |
513 {"complete", 2, 2, f_complete}, | |
514 {"complete_add", 1, 1, f_complete_add}, | |
515 {"complete_check", 0, 0, f_complete_check}, | |
516 #endif | |
517 {"confirm", 1, 4, f_confirm}, | |
518 {"copy", 1, 1, f_copy}, | |
519 #ifdef FEAT_FLOAT | |
520 {"cos", 1, 1, f_cos}, | |
521 {"cosh", 1, 1, f_cosh}, | |
522 #endif | |
523 {"count", 2, 4, f_count}, | |
524 {"cscope_connection",0,3, f_cscope_connection}, | |
525 {"cursor", 1, 3, f_cursor}, | |
526 {"deepcopy", 1, 2, f_deepcopy}, | |
527 {"delete", 1, 2, f_delete}, | |
528 {"did_filetype", 0, 0, f_did_filetype}, | |
529 {"diff_filler", 1, 1, f_diff_filler}, | |
530 {"diff_hlID", 2, 2, f_diff_hlID}, | |
531 {"empty", 1, 1, f_empty}, | |
532 {"escape", 2, 2, f_escape}, | |
533 {"eval", 1, 1, f_eval}, | |
534 {"eventhandler", 0, 0, f_eventhandler}, | |
535 {"executable", 1, 1, f_executable}, | |
536 {"execute", 1, 2, f_execute}, | |
537 {"exepath", 1, 1, f_exepath}, | |
538 {"exists", 1, 1, f_exists}, | |
539 #ifdef FEAT_FLOAT | |
540 {"exp", 1, 1, f_exp}, | |
541 #endif | |
542 {"expand", 1, 3, f_expand}, | |
543 {"extend", 2, 3, f_extend}, | |
544 {"feedkeys", 1, 2, f_feedkeys}, | |
545 {"file_readable", 1, 1, f_filereadable}, /* obsolete */ | |
546 {"filereadable", 1, 1, f_filereadable}, | |
547 {"filewritable", 1, 1, f_filewritable}, | |
548 {"filter", 2, 2, f_filter}, | |
549 {"finddir", 1, 3, f_finddir}, | |
550 {"findfile", 1, 3, f_findfile}, | |
551 #ifdef FEAT_FLOAT | |
552 {"float2nr", 1, 1, f_float2nr}, | |
553 {"floor", 1, 1, f_floor}, | |
554 {"fmod", 2, 2, f_fmod}, | |
555 #endif | |
556 {"fnameescape", 1, 1, f_fnameescape}, | |
557 {"fnamemodify", 2, 2, f_fnamemodify}, | |
558 {"foldclosed", 1, 1, f_foldclosed}, | |
559 {"foldclosedend", 1, 1, f_foldclosedend}, | |
560 {"foldlevel", 1, 1, f_foldlevel}, | |
561 {"foldtext", 0, 0, f_foldtext}, | |
562 {"foldtextresult", 1, 1, f_foldtextresult}, | |
563 {"foreground", 0, 0, f_foreground}, | |
564 {"function", 1, 3, f_function}, | |
565 {"garbagecollect", 0, 1, f_garbagecollect}, | |
566 {"get", 2, 3, f_get}, | |
567 {"getbufline", 2, 3, f_getbufline}, | |
568 {"getbufvar", 2, 3, f_getbufvar}, | |
569 {"getchar", 0, 1, f_getchar}, | |
570 {"getcharmod", 0, 0, f_getcharmod}, | |
571 {"getcharsearch", 0, 0, f_getcharsearch}, | |
572 {"getcmdline", 0, 0, f_getcmdline}, | |
573 {"getcmdpos", 0, 0, f_getcmdpos}, | |
574 {"getcmdtype", 0, 0, f_getcmdtype}, | |
575 {"getcmdwintype", 0, 0, f_getcmdwintype}, | |
576 #if defined(FEAT_CMDL_COMPL) | |
577 {"getcompletion", 2, 2, f_getcompletion}, | |
578 #endif | |
579 {"getcurpos", 0, 0, f_getcurpos}, | |
580 {"getcwd", 0, 2, f_getcwd}, | |
581 {"getfontname", 0, 1, f_getfontname}, | |
582 {"getfperm", 1, 1, f_getfperm}, | |
583 {"getfsize", 1, 1, f_getfsize}, | |
584 {"getftime", 1, 1, f_getftime}, | |
585 {"getftype", 1, 1, f_getftype}, | |
586 {"getline", 1, 2, f_getline}, | |
587 {"getloclist", 1, 1, f_getqflist}, | |
588 {"getmatches", 0, 0, f_getmatches}, | |
589 {"getpid", 0, 0, f_getpid}, | |
590 {"getpos", 1, 1, f_getpos}, | |
591 {"getqflist", 0, 0, f_getqflist}, | |
592 {"getreg", 0, 3, f_getreg}, | |
593 {"getregtype", 0, 1, f_getregtype}, | |
594 {"gettabvar", 2, 3, f_gettabvar}, | |
595 {"gettabwinvar", 3, 4, f_gettabwinvar}, | |
596 {"getwinposx", 0, 0, f_getwinposx}, | |
597 {"getwinposy", 0, 0, f_getwinposy}, | |
598 {"getwinvar", 2, 3, f_getwinvar}, | |
599 {"glob", 1, 4, f_glob}, | |
600 {"glob2regpat", 1, 1, f_glob2regpat}, | |
601 {"globpath", 2, 5, f_globpath}, | |
602 {"has", 1, 1, f_has}, | |
603 {"has_key", 2, 2, f_has_key}, | |
604 {"haslocaldir", 0, 2, f_haslocaldir}, | |
605 {"hasmapto", 1, 3, f_hasmapto}, | |
606 {"highlightID", 1, 1, f_hlID}, /* obsolete */ | |
607 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */ | |
608 {"histadd", 2, 2, f_histadd}, | |
609 {"histdel", 1, 2, f_histdel}, | |
610 {"histget", 1, 2, f_histget}, | |
611 {"histnr", 1, 1, f_histnr}, | |
612 {"hlID", 1, 1, f_hlID}, | |
613 {"hlexists", 1, 1, f_hlexists}, | |
614 {"hostname", 0, 0, f_hostname}, | |
615 {"iconv", 3, 3, f_iconv}, | |
616 {"indent", 1, 1, f_indent}, | |
617 {"index", 2, 4, f_index}, | |
618 {"input", 1, 3, f_input}, | |
619 {"inputdialog", 1, 3, f_inputdialog}, | |
620 {"inputlist", 1, 1, f_inputlist}, | |
621 {"inputrestore", 0, 0, f_inputrestore}, | |
622 {"inputsave", 0, 0, f_inputsave}, | |
623 {"inputsecret", 1, 2, f_inputsecret}, | |
624 {"insert", 2, 3, f_insert}, | |
625 {"invert", 1, 1, f_invert}, | |
626 {"isdirectory", 1, 1, f_isdirectory}, | |
627 {"islocked", 1, 1, f_islocked}, | |
628 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | |
629 {"isnan", 1, 1, f_isnan}, | |
630 #endif | |
631 {"items", 1, 1, f_items}, | |
632 #ifdef FEAT_JOB_CHANNEL | |
633 {"job_getchannel", 1, 1, f_job_getchannel}, | |
634 {"job_info", 1, 1, f_job_info}, | |
635 {"job_setoptions", 2, 2, f_job_setoptions}, | |
636 {"job_start", 1, 2, f_job_start}, | |
637 {"job_status", 1, 1, f_job_status}, | |
638 {"job_stop", 1, 2, f_job_stop}, | |
639 #endif | |
640 {"join", 1, 2, f_join}, | |
641 {"js_decode", 1, 1, f_js_decode}, | |
642 {"js_encode", 1, 1, f_js_encode}, | |
643 {"json_decode", 1, 1, f_json_decode}, | |
644 {"json_encode", 1, 1, f_json_encode}, | |
645 {"keys", 1, 1, f_keys}, | |
646 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */ | |
647 {"len", 1, 1, f_len}, | |
648 {"libcall", 3, 3, f_libcall}, | |
649 {"libcallnr", 3, 3, f_libcallnr}, | |
650 {"line", 1, 1, f_line}, | |
651 {"line2byte", 1, 1, f_line2byte}, | |
652 {"lispindent", 1, 1, f_lispindent}, | |
653 {"localtime", 0, 0, f_localtime}, | |
654 #ifdef FEAT_FLOAT | |
655 {"log", 1, 1, f_log}, | |
656 {"log10", 1, 1, f_log10}, | |
657 #endif | |
658 #ifdef FEAT_LUA | |
659 {"luaeval", 1, 2, f_luaeval}, | |
660 #endif | |
661 {"map", 2, 2, f_map}, | |
662 {"maparg", 1, 4, f_maparg}, | |
663 {"mapcheck", 1, 3, f_mapcheck}, | |
664 {"match", 2, 4, f_match}, | |
665 {"matchadd", 2, 5, f_matchadd}, | |
666 {"matchaddpos", 2, 5, f_matchaddpos}, | |
667 {"matcharg", 1, 1, f_matcharg}, | |
668 {"matchdelete", 1, 1, f_matchdelete}, | |
669 {"matchend", 2, 4, f_matchend}, | |
670 {"matchlist", 2, 4, f_matchlist}, | |
671 {"matchstr", 2, 4, f_matchstr}, | |
672 {"matchstrpos", 2, 4, f_matchstrpos}, | |
673 {"max", 1, 1, f_max}, | |
674 {"min", 1, 1, f_min}, | |
675 #ifdef vim_mkdir | |
676 {"mkdir", 1, 3, f_mkdir}, | |
677 #endif | |
678 {"mode", 0, 1, f_mode}, | |
679 #ifdef FEAT_MZSCHEME | |
680 {"mzeval", 1, 1, f_mzeval}, | |
681 #endif | |
682 {"nextnonblank", 1, 1, f_nextnonblank}, | |
683 {"nr2char", 1, 2, f_nr2char}, | |
684 {"or", 2, 2, f_or}, | |
685 {"pathshorten", 1, 1, f_pathshorten}, | |
686 #ifdef FEAT_PERL | |
687 {"perleval", 1, 1, f_perleval}, | |
688 #endif | |
689 #ifdef FEAT_FLOAT | |
690 {"pow", 2, 2, f_pow}, | |
691 #endif | |
692 {"prevnonblank", 1, 1, f_prevnonblank}, | |
693 {"printf", 2, 19, f_printf}, | |
694 {"pumvisible", 0, 0, f_pumvisible}, | |
695 #ifdef FEAT_PYTHON3 | |
696 {"py3eval", 1, 1, f_py3eval}, | |
697 #endif | |
698 #ifdef FEAT_PYTHON | |
699 {"pyeval", 1, 1, f_pyeval}, | |
700 #endif | |
701 {"range", 1, 3, f_range}, | |
702 {"readfile", 1, 3, f_readfile}, | |
703 {"reltime", 0, 2, f_reltime}, | |
704 #ifdef FEAT_FLOAT | |
705 {"reltimefloat", 1, 1, f_reltimefloat}, | |
706 #endif | |
707 {"reltimestr", 1, 1, f_reltimestr}, | |
708 {"remote_expr", 2, 3, f_remote_expr}, | |
709 {"remote_foreground", 1, 1, f_remote_foreground}, | |
710 {"remote_peek", 1, 2, f_remote_peek}, | |
711 {"remote_read", 1, 1, f_remote_read}, | |
712 {"remote_send", 2, 3, f_remote_send}, | |
713 {"remove", 2, 3, f_remove}, | |
714 {"rename", 2, 2, f_rename}, | |
715 {"repeat", 2, 2, f_repeat}, | |
716 {"resolve", 1, 1, f_resolve}, | |
717 {"reverse", 1, 1, f_reverse}, | |
718 #ifdef FEAT_FLOAT | |
719 {"round", 1, 1, f_round}, | |
720 #endif | |
721 {"screenattr", 2, 2, f_screenattr}, | |
722 {"screenchar", 2, 2, f_screenchar}, | |
723 {"screencol", 0, 0, f_screencol}, | |
724 {"screenrow", 0, 0, f_screenrow}, | |
725 {"search", 1, 4, f_search}, | |
726 {"searchdecl", 1, 3, f_searchdecl}, | |
727 {"searchpair", 3, 7, f_searchpair}, | |
728 {"searchpairpos", 3, 7, f_searchpairpos}, | |
729 {"searchpos", 1, 4, f_searchpos}, | |
730 {"server2client", 2, 2, f_server2client}, | |
731 {"serverlist", 0, 0, f_serverlist}, | |
732 {"setbufvar", 3, 3, f_setbufvar}, | |
733 {"setcharsearch", 1, 1, f_setcharsearch}, | |
734 {"setcmdpos", 1, 1, f_setcmdpos}, | |
735 {"setfperm", 2, 2, f_setfperm}, | |
736 {"setline", 2, 2, f_setline}, | |
737 {"setloclist", 2, 3, f_setloclist}, | |
738 {"setmatches", 1, 1, f_setmatches}, | |
739 {"setpos", 2, 2, f_setpos}, | |
740 {"setqflist", 1, 2, f_setqflist}, | |
741 {"setreg", 2, 3, f_setreg}, | |
742 {"settabvar", 3, 3, f_settabvar}, | |
743 {"settabwinvar", 4, 4, f_settabwinvar}, | |
744 {"setwinvar", 3, 3, f_setwinvar}, | |
745 #ifdef FEAT_CRYPT | |
746 {"sha256", 1, 1, f_sha256}, | |
747 #endif | |
748 {"shellescape", 1, 2, f_shellescape}, | |
749 {"shiftwidth", 0, 0, f_shiftwidth}, | |
750 {"simplify", 1, 1, f_simplify}, | |
751 #ifdef FEAT_FLOAT | |
752 {"sin", 1, 1, f_sin}, | |
753 {"sinh", 1, 1, f_sinh}, | |
754 #endif | |
755 {"sort", 1, 3, f_sort}, | |
756 {"soundfold", 1, 1, f_soundfold}, | |
757 {"spellbadword", 0, 1, f_spellbadword}, | |
758 {"spellsuggest", 1, 3, f_spellsuggest}, | |
759 {"split", 1, 3, f_split}, | |
760 #ifdef FEAT_FLOAT | |
761 {"sqrt", 1, 1, f_sqrt}, | |
762 {"str2float", 1, 1, f_str2float}, | |
763 #endif | |
764 {"str2nr", 1, 2, f_str2nr}, | |
765 {"strcharpart", 2, 3, f_strcharpart}, | |
766 {"strchars", 1, 2, f_strchars}, | |
767 {"strdisplaywidth", 1, 2, f_strdisplaywidth}, | |
768 #ifdef HAVE_STRFTIME | |
769 {"strftime", 1, 2, f_strftime}, | |
770 #endif | |
771 {"strgetchar", 2, 2, f_strgetchar}, | |
772 {"stridx", 2, 3, f_stridx}, | |
773 {"string", 1, 1, f_string}, | |
774 {"strlen", 1, 1, f_strlen}, | |
775 {"strpart", 2, 3, f_strpart}, | |
776 {"strridx", 2, 3, f_strridx}, | |
777 {"strtrans", 1, 1, f_strtrans}, | |
778 {"strwidth", 1, 1, f_strwidth}, | |
779 {"submatch", 1, 2, f_submatch}, | |
780 {"substitute", 4, 4, f_substitute}, | |
781 {"synID", 3, 3, f_synID}, | |
782 {"synIDattr", 2, 3, f_synIDattr}, | |
783 {"synIDtrans", 1, 1, f_synIDtrans}, | |
784 {"synconcealed", 2, 2, f_synconcealed}, | |
785 {"synstack", 2, 2, f_synstack}, | |
786 {"system", 1, 2, f_system}, | |
787 {"systemlist", 1, 2, f_systemlist}, | |
788 {"tabpagebuflist", 0, 1, f_tabpagebuflist}, | |
789 {"tabpagenr", 0, 1, f_tabpagenr}, | |
790 {"tabpagewinnr", 1, 2, f_tabpagewinnr}, | |
791 {"tagfiles", 0, 0, f_tagfiles}, | |
792 {"taglist", 1, 1, f_taglist}, | |
793 #ifdef FEAT_FLOAT | |
794 {"tan", 1, 1, f_tan}, | |
795 {"tanh", 1, 1, f_tanh}, | |
796 #endif | |
797 {"tempname", 0, 0, f_tempname}, | |
798 {"test_alloc_fail", 3, 3, f_test_alloc_fail}, | |
799 {"test_autochdir", 0, 0, f_test_autochdir}, | |
800 {"test_disable_char_avail", 1, 1, f_test_disable_char_avail}, | |
801 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now}, | |
802 #ifdef FEAT_JOB_CHANNEL | |
803 {"test_null_channel", 0, 0, f_test_null_channel}, | |
804 #endif | |
805 {"test_null_dict", 0, 0, f_test_null_dict}, | |
806 #ifdef FEAT_JOB_CHANNEL | |
807 {"test_null_job", 0, 0, f_test_null_job}, | |
808 #endif | |
809 {"test_null_list", 0, 0, f_test_null_list}, | |
810 {"test_null_partial", 0, 0, f_test_null_partial}, | |
811 {"test_null_string", 0, 0, f_test_null_string}, | |
812 {"test_settime", 1, 1, f_test_settime}, | |
813 #ifdef FEAT_TIMERS | |
814 {"timer_start", 2, 3, f_timer_start}, | |
815 {"timer_stop", 1, 1, f_timer_stop}, | |
816 #endif | |
817 {"tolower", 1, 1, f_tolower}, | |
818 {"toupper", 1, 1, f_toupper}, | |
819 {"tr", 3, 3, f_tr}, | |
820 #ifdef FEAT_FLOAT | |
821 {"trunc", 1, 1, f_trunc}, | |
822 #endif | |
823 {"type", 1, 1, f_type}, | |
824 {"undofile", 1, 1, f_undofile}, | |
825 {"undotree", 0, 0, f_undotree}, | |
826 {"uniq", 1, 3, f_uniq}, | |
827 {"values", 1, 1, f_values}, | |
828 {"virtcol", 1, 1, f_virtcol}, | |
829 {"visualmode", 0, 1, f_visualmode}, | |
830 {"wildmenumode", 0, 0, f_wildmenumode}, | |
831 {"win_findbuf", 1, 1, f_win_findbuf}, | |
832 {"win_getid", 0, 2, f_win_getid}, | |
833 {"win_gotoid", 1, 1, f_win_gotoid}, | |
834 {"win_id2tabwin", 1, 1, f_win_id2tabwin}, | |
835 {"win_id2win", 1, 1, f_win_id2win}, | |
836 {"winbufnr", 1, 1, f_winbufnr}, | |
837 {"wincol", 0, 0, f_wincol}, | |
838 {"winheight", 1, 1, f_winheight}, | |
839 {"winline", 0, 0, f_winline}, | |
840 {"winnr", 0, 1, f_winnr}, | |
841 {"winrestcmd", 0, 0, f_winrestcmd}, | |
842 {"winrestview", 1, 1, f_winrestview}, | |
843 {"winsaveview", 0, 0, f_winsaveview}, | |
844 {"winwidth", 1, 1, f_winwidth}, | |
845 {"wordcount", 0, 0, f_wordcount}, | |
846 {"writefile", 2, 3, f_writefile}, | |
847 {"xor", 2, 2, f_xor}, | |
848 }; | |
849 | |
850 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) | |
851 | |
852 /* | |
853 * Function given to ExpandGeneric() to obtain the list of internal | |
854 * or user defined function names. | |
855 */ | |
856 char_u * | |
857 get_function_name(expand_T *xp, int idx) | |
858 { | |
859 static int intidx = -1; | |
860 char_u *name; | |
861 | |
862 if (idx == 0) | |
863 intidx = -1; | |
864 if (intidx < 0) | |
865 { | |
866 name = get_user_func_name(xp, idx); | |
867 if (name != NULL) | |
868 return name; | |
869 } | |
870 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst))) | |
871 { | |
872 STRCPY(IObuff, functions[intidx].f_name); | |
873 STRCAT(IObuff, "("); | |
874 if (functions[intidx].f_max_argc == 0) | |
875 STRCAT(IObuff, ")"); | |
876 return IObuff; | |
877 } | |
878 | |
879 return NULL; | |
880 } | |
881 | |
882 /* | |
883 * Function given to ExpandGeneric() to obtain the list of internal or | |
884 * user defined variable or function names. | |
885 */ | |
886 char_u * | |
887 get_expr_name(expand_T *xp, int idx) | |
888 { | |
889 static int intidx = -1; | |
890 char_u *name; | |
891 | |
892 if (idx == 0) | |
893 intidx = -1; | |
894 if (intidx < 0) | |
895 { | |
896 name = get_function_name(xp, idx); | |
897 if (name != NULL) | |
898 return name; | |
899 } | |
900 return get_user_var_name(xp, ++intidx); | |
901 } | |
902 | |
903 #endif /* FEAT_CMDL_COMPL */ | |
904 | |
905 #if defined(EBCDIC) || defined(PROTO) | |
906 /* | |
907 * Compare struct fst by function name. | |
908 */ | |
909 static int | |
910 compare_func_name(const void *s1, const void *s2) | |
911 { | |
912 struct fst *p1 = (struct fst *)s1; | |
913 struct fst *p2 = (struct fst *)s2; | |
914 | |
915 return STRCMP(p1->f_name, p2->f_name); | |
916 } | |
917 | |
918 /* | |
919 * Sort the function table by function name. | |
920 * The sorting of the table above is ASCII dependant. | |
921 * On machines using EBCDIC we have to sort it. | |
922 */ | |
923 static void | |
924 sortFunctions(void) | |
925 { | |
926 int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1; | |
927 | |
928 qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name); | |
929 } | |
930 #endif | |
931 | |
932 | |
933 /* | |
934 * Find internal function in table above. | |
935 * Return index, or -1 if not found | |
936 */ | |
937 int | |
938 find_internal_func( | |
939 char_u *name) /* name of the function */ | |
940 { | |
941 int first = 0; | |
942 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1; | |
943 int cmp; | |
944 int x; | |
945 | |
946 /* | |
947 * Find the function name in the table. Binary search. | |
948 */ | |
949 while (first <= last) | |
950 { | |
951 x = first + ((unsigned)(last - first) >> 1); | |
952 cmp = STRCMP(name, functions[x].f_name); | |
953 if (cmp < 0) | |
954 last = x - 1; | |
955 else if (cmp > 0) | |
956 first = x + 1; | |
957 else | |
958 return x; | |
959 } | |
960 return -1; | |
961 } | |
962 | |
963 int | |
964 call_internal_func( | |
965 char_u *name, | |
966 int argcount, | |
967 typval_T *argvars, | |
968 typval_T *rettv) | |
969 { | |
970 int i; | |
971 | |
972 i = find_internal_func(name); | |
973 if (i < 0) | |
974 return ERROR_UNKNOWN; | |
975 if (argcount < functions[i].f_min_argc) | |
976 return ERROR_TOOFEW; | |
977 if (argcount > functions[i].f_max_argc) | |
978 return ERROR_TOOMANY; | |
979 argvars[argcount].v_type = VAR_UNKNOWN; | |
980 functions[i].f_func(argvars, rettv); | |
981 return ERROR_NONE; | |
982 } | |
983 | |
984 /* | |
985 * Return TRUE for a non-zero Number and a non-empty String. | |
986 */ | |
987 static int | |
988 non_zero_arg(typval_T *argvars) | |
989 { | |
990 return ((argvars[0].v_type == VAR_NUMBER | |
991 && argvars[0].vval.v_number != 0) | |
992 || (argvars[0].v_type == VAR_SPECIAL | |
993 && argvars[0].vval.v_number == VVAL_TRUE) | |
994 || (argvars[0].v_type == VAR_STRING | |
995 && argvars[0].vval.v_string != NULL | |
996 && *argvars[0].vval.v_string != NUL)); | |
997 } | |
998 | |
999 /* | |
1000 * Get the lnum from the first argument. | |
1001 * Also accepts ".", "$", etc., but that only works for the current buffer. | |
1002 * Returns -1 on error. | |
1003 */ | |
1004 static linenr_T | |
1005 get_tv_lnum(typval_T *argvars) | |
1006 { | |
1007 typval_T rettv; | |
1008 linenr_T lnum; | |
1009 | |
1010 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL); | |
1011 if (lnum == 0) /* no valid number, try using line() */ | |
1012 { | |
1013 rettv.v_type = VAR_NUMBER; | |
1014 f_line(argvars, &rettv); | |
1015 lnum = (linenr_T)rettv.vval.v_number; | |
1016 clear_tv(&rettv); | |
1017 } | |
1018 return lnum; | |
1019 } | |
1020 | |
1021 #ifdef FEAT_FLOAT | |
1022 static int get_float_arg(typval_T *argvars, float_T *f); | |
1023 | |
1024 /* | |
1025 * Get the float value of "argvars[0]" into "f". | |
1026 * Returns FAIL when the argument is not a Number or Float. | |
1027 */ | |
1028 static int | |
1029 get_float_arg(typval_T *argvars, float_T *f) | |
1030 { | |
1031 if (argvars[0].v_type == VAR_FLOAT) | |
1032 { | |
1033 *f = argvars[0].vval.v_float; | |
1034 return OK; | |
1035 } | |
1036 if (argvars[0].v_type == VAR_NUMBER) | |
1037 { | |
1038 *f = (float_T)argvars[0].vval.v_number; | |
1039 return OK; | |
1040 } | |
1041 EMSG(_("E808: Number or Float required")); | |
1042 return FAIL; | |
1043 } | |
1044 | |
1045 /* | |
1046 * "abs(expr)" function | |
1047 */ | |
1048 static void | |
1049 f_abs(typval_T *argvars, typval_T *rettv) | |
1050 { | |
1051 if (argvars[0].v_type == VAR_FLOAT) | |
1052 { | |
1053 rettv->v_type = VAR_FLOAT; | |
1054 rettv->vval.v_float = fabs(argvars[0].vval.v_float); | |
1055 } | |
1056 else | |
1057 { | |
1058 varnumber_T n; | |
1059 int error = FALSE; | |
1060 | |
1061 n = get_tv_number_chk(&argvars[0], &error); | |
1062 if (error) | |
1063 rettv->vval.v_number = -1; | |
1064 else if (n > 0) | |
1065 rettv->vval.v_number = n; | |
1066 else | |
1067 rettv->vval.v_number = -n; | |
1068 } | |
1069 } | |
1070 | |
1071 /* | |
1072 * "acos()" function | |
1073 */ | |
1074 static void | |
1075 f_acos(typval_T *argvars, typval_T *rettv) | |
1076 { | |
1077 float_T f = 0.0; | |
1078 | |
1079 rettv->v_type = VAR_FLOAT; | |
1080 if (get_float_arg(argvars, &f) == OK) | |
1081 rettv->vval.v_float = acos(f); | |
1082 else | |
1083 rettv->vval.v_float = 0.0; | |
1084 } | |
1085 #endif | |
1086 | |
1087 /* | |
1088 * "add(list, item)" function | |
1089 */ | |
1090 static void | |
1091 f_add(typval_T *argvars, typval_T *rettv) | |
1092 { | |
1093 list_T *l; | |
1094 | |
1095 rettv->vval.v_number = 1; /* Default: Failed */ | |
1096 if (argvars[0].v_type == VAR_LIST) | |
1097 { | |
1098 if ((l = argvars[0].vval.v_list) != NULL | |
1099 && !tv_check_lock(l->lv_lock, | |
1100 (char_u *)N_("add() argument"), TRUE) | |
1101 && list_append_tv(l, &argvars[1]) == OK) | |
1102 copy_tv(&argvars[0], rettv); | |
1103 } | |
1104 else | |
1105 EMSG(_(e_listreq)); | |
1106 } | |
1107 | |
1108 /* | |
1109 * "and(expr, expr)" function | |
1110 */ | |
1111 static void | |
1112 f_and(typval_T *argvars, typval_T *rettv) | |
1113 { | |
1114 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | |
1115 & get_tv_number_chk(&argvars[1], NULL); | |
1116 } | |
1117 | |
1118 /* | |
1119 * "append(lnum, string/list)" function | |
1120 */ | |
1121 static void | |
1122 f_append(typval_T *argvars, typval_T *rettv) | |
1123 { | |
1124 long lnum; | |
1125 char_u *line; | |
1126 list_T *l = NULL; | |
1127 listitem_T *li = NULL; | |
1128 typval_T *tv; | |
1129 long added = 0; | |
1130 | |
1131 /* When coming here from Insert mode, sync undo, so that this can be | |
1132 * undone separately from what was previously inserted. */ | |
1133 if (u_sync_once == 2) | |
1134 { | |
1135 u_sync_once = 1; /* notify that u_sync() was called */ | |
1136 u_sync(TRUE); | |
1137 } | |
1138 | |
1139 lnum = get_tv_lnum(argvars); | |
1140 if (lnum >= 0 | |
1141 && lnum <= curbuf->b_ml.ml_line_count | |
1142 && u_save(lnum, lnum + 1) == OK) | |
1143 { | |
1144 if (argvars[1].v_type == VAR_LIST) | |
1145 { | |
1146 l = argvars[1].vval.v_list; | |
1147 if (l == NULL) | |
1148 return; | |
1149 li = l->lv_first; | |
1150 } | |
1151 for (;;) | |
1152 { | |
1153 if (l == NULL) | |
1154 tv = &argvars[1]; /* append a string */ | |
1155 else if (li == NULL) | |
1156 break; /* end of list */ | |
1157 else | |
1158 tv = &li->li_tv; /* append item from list */ | |
1159 line = get_tv_string_chk(tv); | |
1160 if (line == NULL) /* type error */ | |
1161 { | |
1162 rettv->vval.v_number = 1; /* Failed */ | |
1163 break; | |
1164 } | |
1165 ml_append(lnum + added, line, (colnr_T)0, FALSE); | |
1166 ++added; | |
1167 if (l == NULL) | |
1168 break; | |
1169 li = li->li_next; | |
1170 } | |
1171 | |
1172 appended_lines_mark(lnum, added); | |
1173 if (curwin->w_cursor.lnum > lnum) | |
1174 curwin->w_cursor.lnum += added; | |
1175 } | |
1176 else | |
1177 rettv->vval.v_number = 1; /* Failed */ | |
1178 } | |
1179 | |
1180 /* | |
1181 * "argc()" function | |
1182 */ | |
1183 static void | |
1184 f_argc(typval_T *argvars UNUSED, typval_T *rettv) | |
1185 { | |
1186 rettv->vval.v_number = ARGCOUNT; | |
1187 } | |
1188 | |
1189 /* | |
1190 * "argidx()" function | |
1191 */ | |
1192 static void | |
1193 f_argidx(typval_T *argvars UNUSED, typval_T *rettv) | |
1194 { | |
1195 rettv->vval.v_number = curwin->w_arg_idx; | |
1196 } | |
1197 | |
1198 /* | |
1199 * "arglistid()" function | |
1200 */ | |
1201 static void | |
1202 f_arglistid(typval_T *argvars, typval_T *rettv) | |
1203 { | |
1204 win_T *wp; | |
1205 | |
1206 rettv->vval.v_number = -1; | |
1207 wp = find_tabwin(&argvars[0], &argvars[1]); | |
1208 if (wp != NULL) | |
1209 rettv->vval.v_number = wp->w_alist->id; | |
1210 } | |
1211 | |
1212 /* | |
1213 * "argv(nr)" function | |
1214 */ | |
1215 static void | |
1216 f_argv(typval_T *argvars, typval_T *rettv) | |
1217 { | |
1218 int idx; | |
1219 | |
1220 if (argvars[0].v_type != VAR_UNKNOWN) | |
1221 { | |
1222 idx = (int)get_tv_number_chk(&argvars[0], NULL); | |
1223 if (idx >= 0 && idx < ARGCOUNT) | |
1224 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx])); | |
1225 else | |
1226 rettv->vval.v_string = NULL; | |
1227 rettv->v_type = VAR_STRING; | |
1228 } | |
1229 else if (rettv_list_alloc(rettv) == OK) | |
1230 for (idx = 0; idx < ARGCOUNT; ++idx) | |
1231 list_append_string(rettv->vval.v_list, | |
1232 alist_name(&ARGLIST[idx]), -1); | |
1233 } | |
1234 | |
1235 /* | |
1236 * "assert_equal(expected, actual[, msg])" function | |
1237 */ | |
1238 static void | |
1239 f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED) | |
1240 { | |
1241 assert_equal_common(argvars, ASSERT_EQUAL); | |
1242 } | |
1243 | |
1244 /* | |
1245 * "assert_notequal(expected, actual[, msg])" function | |
1246 */ | |
1247 static void | |
1248 f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED) | |
1249 { | |
1250 assert_equal_common(argvars, ASSERT_NOTEQUAL); | |
1251 } | |
1252 | |
1253 /* | |
1254 * "assert_exception(string[, msg])" function | |
1255 */ | |
1256 static void | |
1257 f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED) | |
1258 { | |
1259 assert_exception(argvars); | |
1260 } | |
1261 | |
1262 /* | |
1263 * "assert_fails(cmd [, error])" function | |
1264 */ | |
1265 static void | |
1266 f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED) | |
1267 { | |
1268 assert_fails(argvars); | |
1269 } | |
1270 | |
1271 /* | |
1272 * "assert_false(actual[, msg])" function | |
1273 */ | |
1274 static void | |
1275 f_assert_false(typval_T *argvars, typval_T *rettv UNUSED) | |
1276 { | |
1277 assert_bool(argvars, FALSE); | |
1278 } | |
1279 | |
1280 /* | |
1281 * "assert_match(pattern, actual[, msg])" function | |
1282 */ | |
1283 static void | |
1284 f_assert_match(typval_T *argvars, typval_T *rettv UNUSED) | |
1285 { | |
1286 assert_match_common(argvars, ASSERT_MATCH); | |
1287 } | |
1288 | |
1289 /* | |
1290 * "assert_notmatch(pattern, actual[, msg])" function | |
1291 */ | |
1292 static void | |
1293 f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED) | |
1294 { | |
1295 assert_match_common(argvars, ASSERT_NOTMATCH); | |
1296 } | |
1297 | |
1298 /* | |
1299 * "assert_true(actual[, msg])" function | |
1300 */ | |
1301 static void | |
1302 f_assert_true(typval_T *argvars, typval_T *rettv UNUSED) | |
1303 { | |
1304 assert_bool(argvars, TRUE); | |
1305 } | |
1306 | |
1307 #ifdef FEAT_FLOAT | |
1308 /* | |
1309 * "asin()" function | |
1310 */ | |
1311 static void | |
1312 f_asin(typval_T *argvars, typval_T *rettv) | |
1313 { | |
1314 float_T f = 0.0; | |
1315 | |
1316 rettv->v_type = VAR_FLOAT; | |
1317 if (get_float_arg(argvars, &f) == OK) | |
1318 rettv->vval.v_float = asin(f); | |
1319 else | |
1320 rettv->vval.v_float = 0.0; | |
1321 } | |
1322 | |
1323 /* | |
1324 * "atan()" function | |
1325 */ | |
1326 static void | |
1327 f_atan(typval_T *argvars, typval_T *rettv) | |
1328 { | |
1329 float_T f = 0.0; | |
1330 | |
1331 rettv->v_type = VAR_FLOAT; | |
1332 if (get_float_arg(argvars, &f) == OK) | |
1333 rettv->vval.v_float = atan(f); | |
1334 else | |
1335 rettv->vval.v_float = 0.0; | |
1336 } | |
1337 | |
1338 /* | |
1339 * "atan2()" function | |
1340 */ | |
1341 static void | |
1342 f_atan2(typval_T *argvars, typval_T *rettv) | |
1343 { | |
1344 float_T fx = 0.0, fy = 0.0; | |
1345 | |
1346 rettv->v_type = VAR_FLOAT; | |
1347 if (get_float_arg(argvars, &fx) == OK | |
1348 && get_float_arg(&argvars[1], &fy) == OK) | |
1349 rettv->vval.v_float = atan2(fx, fy); | |
1350 else | |
1351 rettv->vval.v_float = 0.0; | |
1352 } | |
1353 #endif | |
1354 | |
1355 /* | |
1356 * "browse(save, title, initdir, default)" function | |
1357 */ | |
1358 static void | |
1359 f_browse(typval_T *argvars UNUSED, typval_T *rettv) | |
1360 { | |
1361 #ifdef FEAT_BROWSE | |
1362 int save; | |
1363 char_u *title; | |
1364 char_u *initdir; | |
1365 char_u *defname; | |
1366 char_u buf[NUMBUFLEN]; | |
1367 char_u buf2[NUMBUFLEN]; | |
1368 int error = FALSE; | |
1369 | |
1370 save = (int)get_tv_number_chk(&argvars[0], &error); | |
1371 title = get_tv_string_chk(&argvars[1]); | |
1372 initdir = get_tv_string_buf_chk(&argvars[2], buf); | |
1373 defname = get_tv_string_buf_chk(&argvars[3], buf2); | |
1374 | |
1375 if (error || title == NULL || initdir == NULL || defname == NULL) | |
1376 rettv->vval.v_string = NULL; | |
1377 else | |
1378 rettv->vval.v_string = | |
1379 do_browse(save ? BROWSE_SAVE : 0, | |
1380 title, defname, NULL, initdir, NULL, curbuf); | |
1381 #else | |
1382 rettv->vval.v_string = NULL; | |
1383 #endif | |
1384 rettv->v_type = VAR_STRING; | |
1385 } | |
1386 | |
1387 /* | |
1388 * "browsedir(title, initdir)" function | |
1389 */ | |
1390 static void | |
1391 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv) | |
1392 { | |
1393 #ifdef FEAT_BROWSE | |
1394 char_u *title; | |
1395 char_u *initdir; | |
1396 char_u buf[NUMBUFLEN]; | |
1397 | |
1398 title = get_tv_string_chk(&argvars[0]); | |
1399 initdir = get_tv_string_buf_chk(&argvars[1], buf); | |
1400 | |
1401 if (title == NULL || initdir == NULL) | |
1402 rettv->vval.v_string = NULL; | |
1403 else | |
1404 rettv->vval.v_string = do_browse(BROWSE_DIR, | |
1405 title, NULL, NULL, initdir, NULL, curbuf); | |
1406 #else | |
1407 rettv->vval.v_string = NULL; | |
1408 #endif | |
1409 rettv->v_type = VAR_STRING; | |
1410 } | |
1411 | |
1412 static buf_T *find_buffer(typval_T *avar); | |
1413 | |
1414 /* | |
1415 * Find a buffer by number or exact name. | |
1416 */ | |
1417 static buf_T * | |
1418 find_buffer(typval_T *avar) | |
1419 { | |
1420 buf_T *buf = NULL; | |
1421 | |
1422 if (avar->v_type == VAR_NUMBER) | |
1423 buf = buflist_findnr((int)avar->vval.v_number); | |
1424 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) | |
1425 { | |
1426 buf = buflist_findname_exp(avar->vval.v_string); | |
1427 if (buf == NULL) | |
1428 { | |
1429 /* No full path name match, try a match with a URL or a "nofile" | |
1430 * buffer, these don't use the full path. */ | |
1431 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
1432 if (buf->b_fname != NULL | |
1433 && (path_with_url(buf->b_fname) | |
1434 #ifdef FEAT_QUICKFIX | |
1435 || bt_nofile(buf) | |
1436 #endif | |
1437 ) | |
1438 && STRCMP(buf->b_fname, avar->vval.v_string) == 0) | |
1439 break; | |
1440 } | |
1441 } | |
1442 return buf; | |
1443 } | |
1444 | |
1445 /* | |
1446 * "bufexists(expr)" function | |
1447 */ | |
1448 static void | |
1449 f_bufexists(typval_T *argvars, typval_T *rettv) | |
1450 { | |
1451 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); | |
1452 } | |
1453 | |
1454 /* | |
1455 * "buflisted(expr)" function | |
1456 */ | |
1457 static void | |
1458 f_buflisted(typval_T *argvars, typval_T *rettv) | |
1459 { | |
1460 buf_T *buf; | |
1461 | |
1462 buf = find_buffer(&argvars[0]); | |
1463 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); | |
1464 } | |
1465 | |
1466 /* | |
1467 * "bufloaded(expr)" function | |
1468 */ | |
1469 static void | |
1470 f_bufloaded(typval_T *argvars, typval_T *rettv) | |
1471 { | |
1472 buf_T *buf; | |
1473 | |
1474 buf = find_buffer(&argvars[0]); | |
1475 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); | |
1476 } | |
1477 | |
1478 buf_T * | |
1479 buflist_find_by_name(char_u *name, int curtab_only) | |
1480 { | |
1481 int save_magic; | |
1482 char_u *save_cpo; | |
1483 buf_T *buf; | |
1484 | |
1485 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */ | |
1486 save_magic = p_magic; | |
1487 p_magic = TRUE; | |
1488 save_cpo = p_cpo; | |
1489 p_cpo = (char_u *)""; | |
1490 | |
1491 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), | |
1492 TRUE, FALSE, curtab_only)); | |
1493 | |
1494 p_magic = save_magic; | |
1495 p_cpo = save_cpo; | |
1496 return buf; | |
1497 } | |
1498 | |
1499 /* | |
1500 * Get buffer by number or pattern. | |
1501 */ | |
1502 static buf_T * | |
1503 get_buf_tv(typval_T *tv, int curtab_only) | |
1504 { | |
1505 char_u *name = tv->vval.v_string; | |
1506 buf_T *buf; | |
1507 | |
1508 if (tv->v_type == VAR_NUMBER) | |
1509 return buflist_findnr((int)tv->vval.v_number); | |
1510 if (tv->v_type != VAR_STRING) | |
1511 return NULL; | |
1512 if (name == NULL || *name == NUL) | |
1513 return curbuf; | |
1514 if (name[0] == '$' && name[1] == NUL) | |
1515 return lastbuf; | |
1516 | |
1517 buf = buflist_find_by_name(name, curtab_only); | |
1518 | |
1519 /* If not found, try expanding the name, like done for bufexists(). */ | |
1520 if (buf == NULL) | |
1521 buf = find_buffer(tv); | |
1522 | |
1523 return buf; | |
1524 } | |
1525 | |
1526 /* | |
1527 * "bufname(expr)" function | |
1528 */ | |
1529 static void | |
1530 f_bufname(typval_T *argvars, typval_T *rettv) | |
1531 { | |
1532 buf_T *buf; | |
1533 | |
1534 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
1535 ++emsg_off; | |
1536 buf = get_buf_tv(&argvars[0], FALSE); | |
1537 rettv->v_type = VAR_STRING; | |
1538 if (buf != NULL && buf->b_fname != NULL) | |
1539 rettv->vval.v_string = vim_strsave(buf->b_fname); | |
1540 else | |
1541 rettv->vval.v_string = NULL; | |
1542 --emsg_off; | |
1543 } | |
1544 | |
1545 /* | |
1546 * "bufnr(expr)" function | |
1547 */ | |
1548 static void | |
1549 f_bufnr(typval_T *argvars, typval_T *rettv) | |
1550 { | |
1551 buf_T *buf; | |
1552 int error = FALSE; | |
1553 char_u *name; | |
1554 | |
1555 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
1556 ++emsg_off; | |
1557 buf = get_buf_tv(&argvars[0], FALSE); | |
1558 --emsg_off; | |
1559 | |
1560 /* If the buffer isn't found and the second argument is not zero create a | |
1561 * new buffer. */ | |
1562 if (buf == NULL | |
1563 && argvars[1].v_type != VAR_UNKNOWN | |
1564 && get_tv_number_chk(&argvars[1], &error) != 0 | |
1565 && !error | |
1566 && (name = get_tv_string_chk(&argvars[0])) != NULL | |
1567 && !error) | |
1568 buf = buflist_new(name, NULL, (linenr_T)1, 0); | |
1569 | |
1570 if (buf != NULL) | |
1571 rettv->vval.v_number = buf->b_fnum; | |
1572 else | |
1573 rettv->vval.v_number = -1; | |
1574 } | |
1575 | |
1576 static void | |
1577 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) | |
1578 { | |
1579 #ifdef FEAT_WINDOWS | |
1580 win_T *wp; | |
1581 int winnr = 0; | |
1582 #endif | |
1583 buf_T *buf; | |
1584 | |
1585 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
1586 ++emsg_off; | |
1587 buf = get_buf_tv(&argvars[0], TRUE); | |
1588 #ifdef FEAT_WINDOWS | |
1589 for (wp = firstwin; wp; wp = wp->w_next) | |
1590 { | |
1591 ++winnr; | |
1592 if (wp->w_buffer == buf) | |
1593 break; | |
1594 } | |
1595 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); | |
1596 #else | |
1597 rettv->vval.v_number = (curwin->w_buffer == buf | |
1598 ? (get_nr ? 1 : curwin->w_id) : -1); | |
1599 #endif | |
1600 --emsg_off; | |
1601 } | |
1602 | |
1603 /* | |
1604 * "bufwinid(nr)" function | |
1605 */ | |
1606 static void | |
1607 f_bufwinid(typval_T *argvars, typval_T *rettv) | |
1608 { | |
1609 buf_win_common(argvars, rettv, FALSE); | |
1610 } | |
1611 | |
1612 /* | |
1613 * "bufwinnr(nr)" function | |
1614 */ | |
1615 static void | |
1616 f_bufwinnr(typval_T *argvars, typval_T *rettv) | |
1617 { | |
1618 buf_win_common(argvars, rettv, TRUE); | |
1619 } | |
1620 | |
1621 /* | |
1622 * "byte2line(byte)" function | |
1623 */ | |
1624 static void | |
1625 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv) | |
1626 { | |
1627 #ifndef FEAT_BYTEOFF | |
1628 rettv->vval.v_number = -1; | |
1629 #else | |
1630 long boff = 0; | |
1631 | |
1632 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */ | |
1633 if (boff < 0) | |
1634 rettv->vval.v_number = -1; | |
1635 else | |
1636 rettv->vval.v_number = ml_find_line_or_offset(curbuf, | |
1637 (linenr_T)0, &boff); | |
1638 #endif | |
1639 } | |
1640 | |
1641 static void | |
1642 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) | |
1643 { | |
1644 #ifdef FEAT_MBYTE | |
1645 char_u *t; | |
1646 #endif | |
1647 char_u *str; | |
1648 varnumber_T idx; | |
1649 | |
1650 str = get_tv_string_chk(&argvars[0]); | |
1651 idx = get_tv_number_chk(&argvars[1], NULL); | |
1652 rettv->vval.v_number = -1; | |
1653 if (str == NULL || idx < 0) | |
1654 return; | |
1655 | |
1656 #ifdef FEAT_MBYTE | |
1657 t = str; | |
1658 for ( ; idx > 0; idx--) | |
1659 { | |
1660 if (*t == NUL) /* EOL reached */ | |
1661 return; | |
1662 if (enc_utf8 && comp) | |
1663 t += utf_ptr2len(t); | |
1664 else | |
1665 t += (*mb_ptr2len)(t); | |
1666 } | |
1667 rettv->vval.v_number = (varnumber_T)(t - str); | |
1668 #else | |
1669 if ((size_t)idx <= STRLEN(str)) | |
1670 rettv->vval.v_number = idx; | |
1671 #endif | |
1672 } | |
1673 | |
1674 /* | |
1675 * "byteidx()" function | |
1676 */ | |
1677 static void | |
1678 f_byteidx(typval_T *argvars, typval_T *rettv) | |
1679 { | |
1680 byteidx(argvars, rettv, FALSE); | |
1681 } | |
1682 | |
1683 /* | |
1684 * "byteidxcomp()" function | |
1685 */ | |
1686 static void | |
1687 f_byteidxcomp(typval_T *argvars, typval_T *rettv) | |
1688 { | |
1689 byteidx(argvars, rettv, TRUE); | |
1690 } | |
1691 | |
1692 /* | |
1693 * "call(func, arglist [, dict])" function | |
1694 */ | |
1695 static void | |
1696 f_call(typval_T *argvars, typval_T *rettv) | |
1697 { | |
1698 char_u *func; | |
1699 partial_T *partial = NULL; | |
1700 dict_T *selfdict = NULL; | |
1701 | |
1702 if (argvars[1].v_type != VAR_LIST) | |
1703 { | |
1704 EMSG(_(e_listreq)); | |
1705 return; | |
1706 } | |
1707 if (argvars[1].vval.v_list == NULL) | |
1708 return; | |
1709 | |
1710 if (argvars[0].v_type == VAR_FUNC) | |
1711 func = argvars[0].vval.v_string; | |
1712 else if (argvars[0].v_type == VAR_PARTIAL) | |
1713 { | |
1714 partial = argvars[0].vval.v_partial; | |
1715 func = partial->pt_name; | |
1716 } | |
1717 else | |
1718 func = get_tv_string(&argvars[0]); | |
1719 if (*func == NUL) | |
1720 return; /* type error or empty name */ | |
1721 | |
1722 if (argvars[2].v_type != VAR_UNKNOWN) | |
1723 { | |
1724 if (argvars[2].v_type != VAR_DICT) | |
1725 { | |
1726 EMSG(_(e_dictreq)); | |
1727 return; | |
1728 } | |
1729 selfdict = argvars[2].vval.v_dict; | |
1730 } | |
1731 | |
1732 (void)func_call(func, &argvars[1], partial, selfdict, rettv); | |
1733 } | |
1734 | |
1735 #ifdef FEAT_FLOAT | |
1736 /* | |
1737 * "ceil({float})" function | |
1738 */ | |
1739 static void | |
1740 f_ceil(typval_T *argvars, typval_T *rettv) | |
1741 { | |
1742 float_T f = 0.0; | |
1743 | |
1744 rettv->v_type = VAR_FLOAT; | |
1745 if (get_float_arg(argvars, &f) == OK) | |
1746 rettv->vval.v_float = ceil(f); | |
1747 else | |
1748 rettv->vval.v_float = 0.0; | |
1749 } | |
1750 #endif | |
1751 | |
1752 #ifdef FEAT_JOB_CHANNEL | |
1753 /* | |
1754 * "ch_close()" function | |
1755 */ | |
1756 static void | |
1757 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) | |
1758 { | |
1759 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); | |
1760 | |
1761 if (channel != NULL) | |
1762 { | |
1763 channel_close(channel, FALSE); | |
1764 channel_clear(channel); | |
1765 } | |
1766 } | |
1767 | |
1768 /* | |
1769 * "ch_getbufnr()" function | |
1770 */ | |
1771 static void | |
1772 f_ch_getbufnr(typval_T *argvars, typval_T *rettv) | |
1773 { | |
1774 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
1775 | |
1776 rettv->vval.v_number = -1; | |
1777 if (channel != NULL) | |
1778 { | |
1779 char_u *what = get_tv_string(&argvars[1]); | |
1780 int part; | |
1781 | |
1782 if (STRCMP(what, "err") == 0) | |
1783 part = PART_ERR; | |
1784 else if (STRCMP(what, "out") == 0) | |
1785 part = PART_OUT; | |
1786 else if (STRCMP(what, "in") == 0) | |
1787 part = PART_IN; | |
1788 else | |
1789 part = PART_SOCK; | |
1790 if (channel->ch_part[part].ch_bufref.br_buf != NULL) | |
1791 rettv->vval.v_number = | |
1792 channel->ch_part[part].ch_bufref.br_buf->b_fnum; | |
1793 } | |
1794 } | |
1795 | |
1796 /* | |
1797 * "ch_getjob()" function | |
1798 */ | |
1799 static void | |
1800 f_ch_getjob(typval_T *argvars, typval_T *rettv) | |
1801 { | |
1802 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
1803 | |
1804 if (channel != NULL) | |
1805 { | |
1806 rettv->v_type = VAR_JOB; | |
1807 rettv->vval.v_job = channel->ch_job; | |
1808 if (channel->ch_job != NULL) | |
1809 ++channel->ch_job->jv_refcount; | |
1810 } | |
1811 } | |
1812 | |
1813 /* | |
1814 * "ch_info()" function | |
1815 */ | |
1816 static void | |
1817 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) | |
1818 { | |
1819 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
1820 | |
1821 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL) | |
1822 channel_info(channel, rettv->vval.v_dict); | |
1823 } | |
1824 | |
1825 /* | |
1826 * "ch_log()" function | |
1827 */ | |
1828 static void | |
1829 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) | |
1830 { | |
1831 char_u *msg = get_tv_string(&argvars[0]); | |
1832 channel_T *channel = NULL; | |
1833 | |
1834 if (argvars[1].v_type != VAR_UNKNOWN) | |
1835 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0); | |
1836 | |
1837 ch_log(channel, (char *)msg); | |
1838 } | |
1839 | |
1840 /* | |
1841 * "ch_logfile()" function | |
1842 */ | |
1843 static void | |
1844 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED) | |
1845 { | |
1846 char_u *fname; | |
1847 char_u *opt = (char_u *)""; | |
1848 char_u buf[NUMBUFLEN]; | |
1849 | |
1850 fname = get_tv_string(&argvars[0]); | |
1851 if (argvars[1].v_type == VAR_STRING) | |
1852 opt = get_tv_string_buf(&argvars[1], buf); | |
1853 ch_logfile(fname, opt); | |
1854 } | |
1855 | |
1856 /* | |
1857 * "ch_open()" function | |
1858 */ | |
1859 static void | |
1860 f_ch_open(typval_T *argvars, typval_T *rettv) | |
1861 { | |
1862 rettv->v_type = VAR_CHANNEL; | |
1863 if (check_restricted() || check_secure()) | |
1864 return; | |
1865 rettv->vval.v_channel = channel_open_func(argvars); | |
1866 } | |
1867 | |
1868 /* | |
1869 * "ch_read()" function | |
1870 */ | |
1871 static void | |
1872 f_ch_read(typval_T *argvars, typval_T *rettv) | |
1873 { | |
1874 common_channel_read(argvars, rettv, FALSE); | |
1875 } | |
1876 | |
1877 /* | |
1878 * "ch_readraw()" function | |
1879 */ | |
1880 static void | |
1881 f_ch_readraw(typval_T *argvars, typval_T *rettv) | |
1882 { | |
1883 common_channel_read(argvars, rettv, TRUE); | |
1884 } | |
1885 | |
1886 /* | |
1887 * "ch_evalexpr()" function | |
1888 */ | |
1889 static void | |
1890 f_ch_evalexpr(typval_T *argvars, typval_T *rettv) | |
1891 { | |
1892 ch_expr_common(argvars, rettv, TRUE); | |
1893 } | |
1894 | |
1895 /* | |
1896 * "ch_sendexpr()" function | |
1897 */ | |
1898 static void | |
1899 f_ch_sendexpr(typval_T *argvars, typval_T *rettv) | |
1900 { | |
1901 ch_expr_common(argvars, rettv, FALSE); | |
1902 } | |
1903 | |
1904 /* | |
1905 * "ch_evalraw()" function | |
1906 */ | |
1907 static void | |
1908 f_ch_evalraw(typval_T *argvars, typval_T *rettv) | |
1909 { | |
1910 ch_raw_common(argvars, rettv, TRUE); | |
1911 } | |
1912 | |
1913 /* | |
1914 * "ch_sendraw()" function | |
1915 */ | |
1916 static void | |
1917 f_ch_sendraw(typval_T *argvars, typval_T *rettv) | |
1918 { | |
1919 ch_raw_common(argvars, rettv, FALSE); | |
1920 } | |
1921 | |
1922 /* | |
1923 * "ch_setoptions()" function | |
1924 */ | |
1925 static void | |
1926 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) | |
1927 { | |
1928 channel_T *channel; | |
1929 jobopt_T opt; | |
1930 | |
1931 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
1932 if (channel == NULL) | |
1933 return; | |
1934 clear_job_options(&opt); | |
1935 if (get_job_options(&argvars[1], &opt, | |
1936 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK) | |
1937 channel_set_options(channel, &opt); | |
1938 free_job_options(&opt); | |
1939 } | |
1940 | |
1941 /* | |
1942 * "ch_status()" function | |
1943 */ | |
1944 static void | |
1945 f_ch_status(typval_T *argvars, typval_T *rettv) | |
1946 { | |
1947 channel_T *channel; | |
1948 | |
1949 /* return an empty string by default */ | |
1950 rettv->v_type = VAR_STRING; | |
1951 rettv->vval.v_string = NULL; | |
1952 | |
1953 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
1954 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel)); | |
1955 } | |
1956 #endif | |
1957 | |
1958 /* | |
1959 * "changenr()" function | |
1960 */ | |
1961 static void | |
1962 f_changenr(typval_T *argvars UNUSED, typval_T *rettv) | |
1963 { | |
1964 rettv->vval.v_number = curbuf->b_u_seq_cur; | |
1965 } | |
1966 | |
1967 /* | |
1968 * "char2nr(string)" function | |
1969 */ | |
1970 static void | |
1971 f_char2nr(typval_T *argvars, typval_T *rettv) | |
1972 { | |
1973 #ifdef FEAT_MBYTE | |
1974 if (has_mbyte) | |
1975 { | |
1976 int utf8 = 0; | |
1977 | |
1978 if (argvars[1].v_type != VAR_UNKNOWN) | |
1979 utf8 = (int)get_tv_number_chk(&argvars[1], NULL); | |
1980 | |
1981 if (utf8) | |
1982 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0])); | |
1983 else | |
1984 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0])); | |
1985 } | |
1986 else | |
1987 #endif | |
1988 rettv->vval.v_number = get_tv_string(&argvars[0])[0]; | |
1989 } | |
1990 | |
1991 /* | |
1992 * "cindent(lnum)" function | |
1993 */ | |
1994 static void | |
1995 f_cindent(typval_T *argvars UNUSED, typval_T *rettv) | |
1996 { | |
1997 #ifdef FEAT_CINDENT | |
1998 pos_T pos; | |
1999 linenr_T lnum; | |
2000 | |
2001 pos = curwin->w_cursor; | |
2002 lnum = get_tv_lnum(argvars); | |
2003 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
2004 { | |
2005 curwin->w_cursor.lnum = lnum; | |
2006 rettv->vval.v_number = get_c_indent(); | |
2007 curwin->w_cursor = pos; | |
2008 } | |
2009 else | |
2010 #endif | |
2011 rettv->vval.v_number = -1; | |
2012 } | |
2013 | |
2014 /* | |
2015 * "clearmatches()" function | |
2016 */ | |
2017 static void | |
2018 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
2019 { | |
2020 #ifdef FEAT_SEARCH_EXTRA | |
2021 clear_matches(curwin); | |
2022 #endif | |
2023 } | |
2024 | |
2025 /* | |
2026 * "col(string)" function | |
2027 */ | |
2028 static void | |
2029 f_col(typval_T *argvars, typval_T *rettv) | |
2030 { | |
2031 colnr_T col = 0; | |
2032 pos_T *fp; | |
2033 int fnum = curbuf->b_fnum; | |
2034 | |
2035 fp = var2fpos(&argvars[0], FALSE, &fnum); | |
2036 if (fp != NULL && fnum == curbuf->b_fnum) | |
2037 { | |
2038 if (fp->col == MAXCOL) | |
2039 { | |
2040 /* '> can be MAXCOL, get the length of the line then */ | |
2041 if (fp->lnum <= curbuf->b_ml.ml_line_count) | |
2042 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; | |
2043 else | |
2044 col = MAXCOL; | |
2045 } | |
2046 else | |
2047 { | |
2048 col = fp->col + 1; | |
2049 #ifdef FEAT_VIRTUALEDIT | |
2050 /* col(".") when the cursor is on the NUL at the end of the line | |
2051 * because of "coladd" can be seen as an extra column. */ | |
2052 if (virtual_active() && fp == &curwin->w_cursor) | |
2053 { | |
2054 char_u *p = ml_get_cursor(); | |
2055 | |
2056 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, | |
2057 curwin->w_virtcol - curwin->w_cursor.coladd)) | |
2058 { | |
2059 # ifdef FEAT_MBYTE | |
2060 int l; | |
2061 | |
2062 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) | |
2063 col += l; | |
2064 # else | |
2065 if (*p != NUL && p[1] == NUL) | |
2066 ++col; | |
2067 # endif | |
2068 } | |
2069 } | |
2070 #endif | |
2071 } | |
2072 } | |
2073 rettv->vval.v_number = col; | |
2074 } | |
2075 | |
2076 #if defined(FEAT_INS_EXPAND) | |
2077 /* | |
2078 * "complete()" function | |
2079 */ | |
2080 static void | |
2081 f_complete(typval_T *argvars, typval_T *rettv UNUSED) | |
2082 { | |
2083 int startcol; | |
2084 | |
2085 if ((State & INSERT) == 0) | |
2086 { | |
2087 EMSG(_("E785: complete() can only be used in Insert mode")); | |
2088 return; | |
2089 } | |
2090 | |
2091 /* Check for undo allowed here, because if something was already inserted | |
2092 * the line was already saved for undo and this check isn't done. */ | |
2093 if (!undo_allowed()) | |
2094 return; | |
2095 | |
2096 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) | |
2097 { | |
2098 EMSG(_(e_invarg)); | |
2099 return; | |
2100 } | |
2101 | |
2102 startcol = (int)get_tv_number_chk(&argvars[0], NULL); | |
2103 if (startcol <= 0) | |
2104 return; | |
2105 | |
2106 set_completion(startcol - 1, argvars[1].vval.v_list); | |
2107 } | |
2108 | |
2109 /* | |
2110 * "complete_add()" function | |
2111 */ | |
2112 static void | |
2113 f_complete_add(typval_T *argvars, typval_T *rettv) | |
2114 { | |
2115 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); | |
2116 } | |
2117 | |
2118 /* | |
2119 * "complete_check()" function | |
2120 */ | |
2121 static void | |
2122 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv) | |
2123 { | |
2124 int saved = RedrawingDisabled; | |
2125 | |
2126 RedrawingDisabled = 0; | |
2127 ins_compl_check_keys(0); | |
2128 rettv->vval.v_number = compl_interrupted; | |
2129 RedrawingDisabled = saved; | |
2130 } | |
2131 #endif | |
2132 | |
2133 /* | |
2134 * "confirm(message, buttons[, default [, type]])" function | |
2135 */ | |
2136 static void | |
2137 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
2138 { | |
2139 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) | |
2140 char_u *message; | |
2141 char_u *buttons = NULL; | |
2142 char_u buf[NUMBUFLEN]; | |
2143 char_u buf2[NUMBUFLEN]; | |
2144 int def = 1; | |
2145 int type = VIM_GENERIC; | |
2146 char_u *typestr; | |
2147 int error = FALSE; | |
2148 | |
2149 message = get_tv_string_chk(&argvars[0]); | |
2150 if (message == NULL) | |
2151 error = TRUE; | |
2152 if (argvars[1].v_type != VAR_UNKNOWN) | |
2153 { | |
2154 buttons = get_tv_string_buf_chk(&argvars[1], buf); | |
2155 if (buttons == NULL) | |
2156 error = TRUE; | |
2157 if (argvars[2].v_type != VAR_UNKNOWN) | |
2158 { | |
2159 def = (int)get_tv_number_chk(&argvars[2], &error); | |
2160 if (argvars[3].v_type != VAR_UNKNOWN) | |
2161 { | |
2162 typestr = get_tv_string_buf_chk(&argvars[3], buf2); | |
2163 if (typestr == NULL) | |
2164 error = TRUE; | |
2165 else | |
2166 { | |
2167 switch (TOUPPER_ASC(*typestr)) | |
2168 { | |
2169 case 'E': type = VIM_ERROR; break; | |
2170 case 'Q': type = VIM_QUESTION; break; | |
2171 case 'I': type = VIM_INFO; break; | |
2172 case 'W': type = VIM_WARNING; break; | |
2173 case 'G': type = VIM_GENERIC; break; | |
2174 } | |
2175 } | |
2176 } | |
2177 } | |
2178 } | |
2179 | |
2180 if (buttons == NULL || *buttons == NUL) | |
2181 buttons = (char_u *)_("&Ok"); | |
2182 | |
2183 if (!error) | |
2184 rettv->vval.v_number = do_dialog(type, NULL, message, buttons, | |
2185 def, NULL, FALSE); | |
2186 #endif | |
2187 } | |
2188 | |
2189 /* | |
2190 * "copy()" function | |
2191 */ | |
2192 static void | |
2193 f_copy(typval_T *argvars, typval_T *rettv) | |
2194 { | |
2195 item_copy(&argvars[0], rettv, FALSE, 0); | |
2196 } | |
2197 | |
2198 #ifdef FEAT_FLOAT | |
2199 /* | |
2200 * "cos()" function | |
2201 */ | |
2202 static void | |
2203 f_cos(typval_T *argvars, typval_T *rettv) | |
2204 { | |
2205 float_T f = 0.0; | |
2206 | |
2207 rettv->v_type = VAR_FLOAT; | |
2208 if (get_float_arg(argvars, &f) == OK) | |
2209 rettv->vval.v_float = cos(f); | |
2210 else | |
2211 rettv->vval.v_float = 0.0; | |
2212 } | |
2213 | |
2214 /* | |
2215 * "cosh()" function | |
2216 */ | |
2217 static void | |
2218 f_cosh(typval_T *argvars, typval_T *rettv) | |
2219 { | |
2220 float_T f = 0.0; | |
2221 | |
2222 rettv->v_type = VAR_FLOAT; | |
2223 if (get_float_arg(argvars, &f) == OK) | |
2224 rettv->vval.v_float = cosh(f); | |
2225 else | |
2226 rettv->vval.v_float = 0.0; | |
2227 } | |
2228 #endif | |
2229 | |
2230 /* | |
2231 * "count()" function | |
2232 */ | |
2233 static void | |
2234 f_count(typval_T *argvars, typval_T *rettv) | |
2235 { | |
2236 long n = 0; | |
2237 int ic = FALSE; | |
2238 | |
2239 if (argvars[0].v_type == VAR_LIST) | |
2240 { | |
2241 listitem_T *li; | |
2242 list_T *l; | |
2243 long idx; | |
2244 | |
2245 if ((l = argvars[0].vval.v_list) != NULL) | |
2246 { | |
2247 li = l->lv_first; | |
2248 if (argvars[2].v_type != VAR_UNKNOWN) | |
2249 { | |
2250 int error = FALSE; | |
2251 | |
2252 ic = (int)get_tv_number_chk(&argvars[2], &error); | |
2253 if (argvars[3].v_type != VAR_UNKNOWN) | |
2254 { | |
2255 idx = (long)get_tv_number_chk(&argvars[3], &error); | |
2256 if (!error) | |
2257 { | |
2258 li = list_find(l, idx); | |
2259 if (li == NULL) | |
2260 EMSGN(_(e_listidx), idx); | |
2261 } | |
2262 } | |
2263 if (error) | |
2264 li = NULL; | |
2265 } | |
2266 | |
2267 for ( ; li != NULL; li = li->li_next) | |
2268 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) | |
2269 ++n; | |
2270 } | |
2271 } | |
2272 else if (argvars[0].v_type == VAR_DICT) | |
2273 { | |
2274 int todo; | |
2275 dict_T *d; | |
2276 hashitem_T *hi; | |
2277 | |
2278 if ((d = argvars[0].vval.v_dict) != NULL) | |
2279 { | |
2280 int error = FALSE; | |
2281 | |
2282 if (argvars[2].v_type != VAR_UNKNOWN) | |
2283 { | |
2284 ic = (int)get_tv_number_chk(&argvars[2], &error); | |
2285 if (argvars[3].v_type != VAR_UNKNOWN) | |
2286 EMSG(_(e_invarg)); | |
2287 } | |
2288 | |
2289 todo = error ? 0 : (int)d->dv_hashtab.ht_used; | |
2290 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | |
2291 { | |
2292 if (!HASHITEM_EMPTY(hi)) | |
2293 { | |
2294 --todo; | |
2295 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) | |
2296 ++n; | |
2297 } | |
2298 } | |
2299 } | |
2300 } | |
2301 else | |
2302 EMSG2(_(e_listdictarg), "count()"); | |
2303 rettv->vval.v_number = n; | |
2304 } | |
2305 | |
2306 /* | |
2307 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function | |
2308 * | |
2309 * Checks the existence of a cscope connection. | |
2310 */ | |
2311 static void | |
2312 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
2313 { | |
2314 #ifdef FEAT_CSCOPE | |
2315 int num = 0; | |
2316 char_u *dbpath = NULL; | |
2317 char_u *prepend = NULL; | |
2318 char_u buf[NUMBUFLEN]; | |
2319 | |
2320 if (argvars[0].v_type != VAR_UNKNOWN | |
2321 && argvars[1].v_type != VAR_UNKNOWN) | |
2322 { | |
2323 num = (int)get_tv_number(&argvars[0]); | |
2324 dbpath = get_tv_string(&argvars[1]); | |
2325 if (argvars[2].v_type != VAR_UNKNOWN) | |
2326 prepend = get_tv_string_buf(&argvars[2], buf); | |
2327 } | |
2328 | |
2329 rettv->vval.v_number = cs_connection(num, dbpath, prepend); | |
2330 #endif | |
2331 } | |
2332 | |
2333 /* | |
2334 * "cursor(lnum, col)" function, or | |
2335 * "cursor(list)" | |
2336 * | |
2337 * Moves the cursor to the specified line and column. | |
2338 * Returns 0 when the position could be set, -1 otherwise. | |
2339 */ | |
2340 static void | |
2341 f_cursor(typval_T *argvars, typval_T *rettv) | |
2342 { | |
2343 long line, col; | |
2344 #ifdef FEAT_VIRTUALEDIT | |
2345 long coladd = 0; | |
2346 #endif | |
2347 int set_curswant = TRUE; | |
2348 | |
2349 rettv->vval.v_number = -1; | |
2350 if (argvars[1].v_type == VAR_UNKNOWN) | |
2351 { | |
2352 pos_T pos; | |
2353 colnr_T curswant = -1; | |
2354 | |
2355 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) | |
2356 { | |
2357 EMSG(_(e_invarg)); | |
2358 return; | |
2359 } | |
2360 line = pos.lnum; | |
2361 col = pos.col; | |
2362 #ifdef FEAT_VIRTUALEDIT | |
2363 coladd = pos.coladd; | |
2364 #endif | |
2365 if (curswant >= 0) | |
2366 { | |
2367 curwin->w_curswant = curswant - 1; | |
2368 set_curswant = FALSE; | |
2369 } | |
2370 } | |
2371 else | |
2372 { | |
2373 line = get_tv_lnum(argvars); | |
2374 col = (long)get_tv_number_chk(&argvars[1], NULL); | |
2375 #ifdef FEAT_VIRTUALEDIT | |
2376 if (argvars[2].v_type != VAR_UNKNOWN) | |
2377 coladd = (long)get_tv_number_chk(&argvars[2], NULL); | |
2378 #endif | |
2379 } | |
2380 if (line < 0 || col < 0 | |
2381 #ifdef FEAT_VIRTUALEDIT | |
2382 || coladd < 0 | |
2383 #endif | |
2384 ) | |
2385 return; /* type error; errmsg already given */ | |
2386 if (line > 0) | |
2387 curwin->w_cursor.lnum = line; | |
2388 if (col > 0) | |
2389 curwin->w_cursor.col = col - 1; | |
2390 #ifdef FEAT_VIRTUALEDIT | |
2391 curwin->w_cursor.coladd = coladd; | |
2392 #endif | |
2393 | |
2394 /* Make sure the cursor is in a valid position. */ | |
2395 check_cursor(); | |
2396 #ifdef FEAT_MBYTE | |
2397 /* Correct cursor for multi-byte character. */ | |
2398 if (has_mbyte) | |
2399 mb_adjust_cursor(); | |
2400 #endif | |
2401 | |
2402 curwin->w_set_curswant = set_curswant; | |
2403 rettv->vval.v_number = 0; | |
2404 } | |
2405 | |
2406 /* | |
2407 * "deepcopy()" function | |
2408 */ | |
2409 static void | |
2410 f_deepcopy(typval_T *argvars, typval_T *rettv) | |
2411 { | |
2412 int noref = 0; | |
2413 int copyID; | |
2414 | |
2415 if (argvars[1].v_type != VAR_UNKNOWN) | |
2416 noref = (int)get_tv_number_chk(&argvars[1], NULL); | |
2417 if (noref < 0 || noref > 1) | |
2418 EMSG(_(e_invarg)); | |
2419 else | |
2420 { | |
2421 copyID = get_copyID(); | |
2422 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0); | |
2423 } | |
2424 } | |
2425 | |
2426 /* | |
2427 * "delete()" function | |
2428 */ | |
2429 static void | |
2430 f_delete(typval_T *argvars, typval_T *rettv) | |
2431 { | |
2432 char_u nbuf[NUMBUFLEN]; | |
2433 char_u *name; | |
2434 char_u *flags; | |
2435 | |
2436 rettv->vval.v_number = -1; | |
2437 if (check_restricted() || check_secure()) | |
2438 return; | |
2439 | |
2440 name = get_tv_string(&argvars[0]); | |
2441 if (name == NULL || *name == NUL) | |
2442 { | |
2443 EMSG(_(e_invarg)); | |
2444 return; | |
2445 } | |
2446 | |
2447 if (argvars[1].v_type != VAR_UNKNOWN) | |
2448 flags = get_tv_string_buf(&argvars[1], nbuf); | |
2449 else | |
2450 flags = (char_u *)""; | |
2451 | |
2452 if (*flags == NUL) | |
2453 /* delete a file */ | |
2454 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1; | |
2455 else if (STRCMP(flags, "d") == 0) | |
2456 /* delete an empty directory */ | |
2457 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; | |
2458 else if (STRCMP(flags, "rf") == 0) | |
2459 /* delete a directory recursively */ | |
2460 rettv->vval.v_number = delete_recursive(name); | |
2461 else | |
2462 EMSG2(_(e_invexpr2), flags); | |
2463 } | |
2464 | |
2465 /* | |
2466 * "did_filetype()" function | |
2467 */ | |
2468 static void | |
2469 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
2470 { | |
2471 #ifdef FEAT_AUTOCMD | |
2472 rettv->vval.v_number = did_filetype; | |
2473 #endif | |
2474 } | |
2475 | |
2476 /* | |
2477 * "diff_filler()" function | |
2478 */ | |
2479 static void | |
2480 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
2481 { | |
2482 #ifdef FEAT_DIFF | |
2483 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars)); | |
2484 #endif | |
2485 } | |
2486 | |
2487 /* | |
2488 * "diff_hlID()" function | |
2489 */ | |
2490 static void | |
2491 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
2492 { | |
2493 #ifdef FEAT_DIFF | |
2494 linenr_T lnum = get_tv_lnum(argvars); | |
2495 static linenr_T prev_lnum = 0; | |
2496 static int changedtick = 0; | |
2497 static int fnum = 0; | |
2498 static int change_start = 0; | |
2499 static int change_end = 0; | |
2500 static hlf_T hlID = (hlf_T)0; | |
2501 int filler_lines; | |
2502 int col; | |
2503 | |
2504 if (lnum < 0) /* ignore type error in {lnum} arg */ | |
2505 lnum = 0; | |
2506 if (lnum != prev_lnum | |
2507 || changedtick != curbuf->b_changedtick | |
2508 || fnum != curbuf->b_fnum) | |
2509 { | |
2510 /* New line, buffer, change: need to get the values. */ | |
2511 filler_lines = diff_check(curwin, lnum); | |
2512 if (filler_lines < 0) | |
2513 { | |
2514 if (filler_lines == -1) | |
2515 { | |
2516 change_start = MAXCOL; | |
2517 change_end = -1; | |
2518 if (diff_find_change(curwin, lnum, &change_start, &change_end)) | |
2519 hlID = HLF_ADD; /* added line */ | |
2520 else | |
2521 hlID = HLF_CHD; /* changed line */ | |
2522 } | |
2523 else | |
2524 hlID = HLF_ADD; /* added line */ | |
2525 } | |
2526 else | |
2527 hlID = (hlf_T)0; | |
2528 prev_lnum = lnum; | |
2529 changedtick = curbuf->b_changedtick; | |
2530 fnum = curbuf->b_fnum; | |
2531 } | |
2532 | |
2533 if (hlID == HLF_CHD || hlID == HLF_TXD) | |
2534 { | |
2535 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */ | |
2536 if (col >= change_start && col <= change_end) | |
2537 hlID = HLF_TXD; /* changed text */ | |
2538 else | |
2539 hlID = HLF_CHD; /* changed line */ | |
2540 } | |
2541 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; | |
2542 #endif | |
2543 } | |
2544 | |
2545 /* | |
2546 * "empty({expr})" function | |
2547 */ | |
2548 static void | |
2549 f_empty(typval_T *argvars, typval_T *rettv) | |
2550 { | |
2551 int n = FALSE; | |
2552 | |
2553 switch (argvars[0].v_type) | |
2554 { | |
2555 case VAR_STRING: | |
2556 case VAR_FUNC: | |
2557 n = argvars[0].vval.v_string == NULL | |
2558 || *argvars[0].vval.v_string == NUL; | |
2559 break; | |
2560 case VAR_PARTIAL: | |
2561 n = FALSE; | |
2562 break; | |
2563 case VAR_NUMBER: | |
2564 n = argvars[0].vval.v_number == 0; | |
2565 break; | |
2566 case VAR_FLOAT: | |
2567 #ifdef FEAT_FLOAT | |
2568 n = argvars[0].vval.v_float == 0.0; | |
2569 break; | |
2570 #endif | |
2571 case VAR_LIST: | |
2572 n = argvars[0].vval.v_list == NULL | |
2573 || argvars[0].vval.v_list->lv_first == NULL; | |
2574 break; | |
2575 case VAR_DICT: | |
2576 n = argvars[0].vval.v_dict == NULL | |
2577 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0; | |
2578 break; | |
2579 case VAR_SPECIAL: | |
2580 n = argvars[0].vval.v_number != VVAL_TRUE; | |
2581 break; | |
2582 | |
2583 case VAR_JOB: | |
2584 #ifdef FEAT_JOB_CHANNEL | |
2585 n = argvars[0].vval.v_job == NULL | |
2586 || argvars[0].vval.v_job->jv_status != JOB_STARTED; | |
2587 break; | |
2588 #endif | |
2589 case VAR_CHANNEL: | |
2590 #ifdef FEAT_JOB_CHANNEL | |
2591 n = argvars[0].vval.v_channel == NULL | |
2592 || !channel_is_open(argvars[0].vval.v_channel); | |
2593 break; | |
2594 #endif | |
2595 case VAR_UNKNOWN: | |
2596 EMSG2(_(e_intern2), "f_empty(UNKNOWN)"); | |
2597 n = TRUE; | |
2598 break; | |
2599 } | |
2600 | |
2601 rettv->vval.v_number = n; | |
2602 } | |
2603 | |
2604 /* | |
2605 * "escape({string}, {chars})" function | |
2606 */ | |
2607 static void | |
2608 f_escape(typval_T *argvars, typval_T *rettv) | |
2609 { | |
2610 char_u buf[NUMBUFLEN]; | |
2611 | |
2612 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]), | |
2613 get_tv_string_buf(&argvars[1], buf)); | |
2614 rettv->v_type = VAR_STRING; | |
2615 } | |
2616 | |
2617 /* | |
2618 * "eval()" function | |
2619 */ | |
2620 static void | |
2621 f_eval(typval_T *argvars, typval_T *rettv) | |
2622 { | |
2623 char_u *s, *p; | |
2624 | |
2625 s = get_tv_string_chk(&argvars[0]); | |
2626 if (s != NULL) | |
2627 s = skipwhite(s); | |
2628 | |
2629 p = s; | |
2630 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) | |
2631 { | |
2632 if (p != NULL && !aborting()) | |
2633 EMSG2(_(e_invexpr2), p); | |
2634 need_clr_eos = FALSE; | |
2635 rettv->v_type = VAR_NUMBER; | |
2636 rettv->vval.v_number = 0; | |
2637 } | |
2638 else if (*s != NUL) | |
2639 EMSG(_(e_trailing)); | |
2640 } | |
2641 | |
2642 /* | |
2643 * "eventhandler()" function | |
2644 */ | |
2645 static void | |
2646 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) | |
2647 { | |
2648 rettv->vval.v_number = vgetc_busy; | |
2649 } | |
2650 | |
2651 /* | |
2652 * "executable()" function | |
2653 */ | |
2654 static void | |
2655 f_executable(typval_T *argvars, typval_T *rettv) | |
2656 { | |
2657 char_u *name = get_tv_string(&argvars[0]); | |
2658 | |
2659 /* Check in $PATH and also check directly if there is a directory name. */ | |
2660 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) | |
2661 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); | |
2662 } | |
2663 | |
2664 static garray_T redir_execute_ga; | |
2665 | |
2666 /* | |
2667 * Append "value[value_len]" to the execute() output. | |
2668 */ | |
2669 void | |
2670 execute_redir_str(char_u *value, int value_len) | |
2671 { | |
2672 int len; | |
2673 | |
2674 if (value_len == -1) | |
2675 len = (int)STRLEN(value); /* Append the entire string */ | |
2676 else | |
2677 len = value_len; /* Append only "value_len" characters */ | |
2678 if (ga_grow(&redir_execute_ga, len) == OK) | |
2679 { | |
2680 mch_memmove((char *)redir_execute_ga.ga_data | |
2681 + redir_execute_ga.ga_len, value, len); | |
2682 redir_execute_ga.ga_len += len; | |
2683 } | |
2684 } | |
2685 | |
2686 /* | |
2687 * Get next line from a list. | |
2688 * Called by do_cmdline() to get the next line. | |
2689 * Returns allocated string, or NULL for end of function. | |
2690 */ | |
2691 | |
2692 static char_u * | |
2693 get_list_line( | |
2694 int c UNUSED, | |
2695 void *cookie, | |
2696 int indent UNUSED) | |
2697 { | |
2698 listitem_T **p = (listitem_T **)cookie; | |
2699 listitem_T *item = *p; | |
2700 char_u buf[NUMBUFLEN]; | |
2701 char_u *s; | |
2702 | |
2703 if (item == NULL) | |
2704 return NULL; | |
2705 s = get_tv_string_buf_chk(&item->li_tv, buf); | |
2706 *p = item->li_next; | |
2707 return s == NULL ? NULL : vim_strsave(s); | |
2708 } | |
2709 | |
2710 /* | |
2711 * "execute()" function | |
2712 */ | |
2713 static void | |
2714 f_execute(typval_T *argvars, typval_T *rettv) | |
2715 { | |
2716 char_u *cmd = NULL; | |
2717 list_T *list = NULL; | |
2718 int save_msg_silent = msg_silent; | |
2719 int save_emsg_silent = emsg_silent; | |
2720 int save_emsg_noredir = emsg_noredir; | |
2721 int save_redir_execute = redir_execute; | |
2722 garray_T save_ga; | |
2723 | |
2724 rettv->vval.v_string = NULL; | |
2725 rettv->v_type = VAR_STRING; | |
2726 | |
2727 if (argvars[0].v_type == VAR_LIST) | |
2728 { | |
2729 list = argvars[0].vval.v_list; | |
2730 if (list == NULL || list->lv_first == NULL) | |
2731 /* empty list, no commands, empty output */ | |
2732 return; | |
2733 ++list->lv_refcount; | |
2734 } | |
2735 else | |
2736 { | |
2737 cmd = get_tv_string_chk(&argvars[0]); | |
2738 if (cmd == NULL) | |
2739 return; | |
2740 } | |
2741 | |
2742 if (argvars[1].v_type != VAR_UNKNOWN) | |
2743 { | |
2744 char_u buf[NUMBUFLEN]; | |
2745 char_u *s = get_tv_string_buf_chk(&argvars[1], buf); | |
2746 | |
2747 if (s == NULL) | |
2748 return; | |
2749 if (STRNCMP(s, "silent", 6) == 0) | |
2750 ++msg_silent; | |
2751 if (STRCMP(s, "silent!") == 0) | |
2752 { | |
2753 emsg_silent = TRUE; | |
2754 emsg_noredir = TRUE; | |
2755 } | |
2756 } | |
2757 else | |
2758 ++msg_silent; | |
2759 | |
2760 if (redir_execute) | |
2761 save_ga = redir_execute_ga; | |
2762 ga_init2(&redir_execute_ga, (int)sizeof(char), 500); | |
2763 redir_execute = TRUE; | |
2764 | |
2765 if (cmd != NULL) | |
2766 do_cmdline_cmd(cmd); | |
2767 else | |
2768 { | |
2769 listitem_T *item = list->lv_first; | |
2770 | |
2771 do_cmdline(NULL, get_list_line, (void *)&item, | |
2772 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); | |
2773 --list->lv_refcount; | |
2774 } | |
2775 | |
2776 rettv->vval.v_string = redir_execute_ga.ga_data; | |
2777 msg_silent = save_msg_silent; | |
2778 emsg_silent = save_emsg_silent; | |
2779 emsg_noredir = save_emsg_noredir; | |
2780 | |
2781 redir_execute = save_redir_execute; | |
2782 if (redir_execute) | |
2783 redir_execute_ga = save_ga; | |
2784 | |
2785 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the | |
2786 * line. Put it back in the first column. */ | |
2787 msg_col = 0; | |
2788 } | |
2789 | |
2790 /* | |
2791 * "exepath()" function | |
2792 */ | |
2793 static void | |
2794 f_exepath(typval_T *argvars, typval_T *rettv) | |
2795 { | |
2796 char_u *p = NULL; | |
2797 | |
2798 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE); | |
2799 rettv->v_type = VAR_STRING; | |
2800 rettv->vval.v_string = p; | |
2801 } | |
2802 | |
2803 /* | |
2804 * "exists()" function | |
2805 */ | |
2806 static void | |
2807 f_exists(typval_T *argvars, typval_T *rettv) | |
2808 { | |
2809 char_u *p; | |
2810 char_u *name; | |
2811 int n = FALSE; | |
2812 int len = 0; | |
2813 | |
2814 p = get_tv_string(&argvars[0]); | |
2815 if (*p == '$') /* environment variable */ | |
2816 { | |
2817 /* first try "normal" environment variables (fast) */ | |
2818 if (mch_getenv(p + 1) != NULL) | |
2819 n = TRUE; | |
2820 else | |
2821 { | |
2822 /* try expanding things like $VIM and ${HOME} */ | |
2823 p = expand_env_save(p); | |
2824 if (p != NULL && *p != '$') | |
2825 n = TRUE; | |
2826 vim_free(p); | |
2827 } | |
2828 } | |
2829 else if (*p == '&' || *p == '+') /* option */ | |
2830 { | |
2831 n = (get_option_tv(&p, NULL, TRUE) == OK); | |
2832 if (*skipwhite(p) != NUL) | |
2833 n = FALSE; /* trailing garbage */ | |
2834 } | |
2835 else if (*p == '*') /* internal or user defined function */ | |
2836 { | |
2837 n = function_exists(p + 1); | |
2838 } | |
2839 else if (*p == ':') | |
2840 { | |
2841 n = cmd_exists(p + 1); | |
2842 } | |
2843 else if (*p == '#') | |
2844 { | |
2845 #ifdef FEAT_AUTOCMD | |
2846 if (p[1] == '#') | |
2847 n = autocmd_supported(p + 2); | |
2848 else | |
2849 n = au_exists(p + 1); | |
2850 #endif | |
2851 } | |
2852 else /* internal variable */ | |
2853 { | |
2854 char_u *tofree; | |
2855 typval_T tv; | |
2856 | |
2857 /* get_name_len() takes care of expanding curly braces */ | |
2858 name = p; | |
2859 len = get_name_len(&p, &tofree, TRUE, FALSE); | |
2860 if (len > 0) | |
2861 { | |
2862 if (tofree != NULL) | |
2863 name = tofree; | |
2864 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK); | |
2865 if (n) | |
2866 { | |
2867 /* handle d.key, l[idx], f(expr) */ | |
2868 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK); | |
2869 if (n) | |
2870 clear_tv(&tv); | |
2871 } | |
2872 } | |
2873 if (*p != NUL) | |
2874 n = FALSE; | |
2875 | |
2876 vim_free(tofree); | |
2877 } | |
2878 | |
2879 rettv->vval.v_number = n; | |
2880 } | |
2881 | |
2882 #ifdef FEAT_FLOAT | |
2883 /* | |
2884 * "exp()" function | |
2885 */ | |
2886 static void | |
2887 f_exp(typval_T *argvars, typval_T *rettv) | |
2888 { | |
2889 float_T f = 0.0; | |
2890 | |
2891 rettv->v_type = VAR_FLOAT; | |
2892 if (get_float_arg(argvars, &f) == OK) | |
2893 rettv->vval.v_float = exp(f); | |
2894 else | |
2895 rettv->vval.v_float = 0.0; | |
2896 } | |
2897 #endif | |
2898 | |
2899 /* | |
2900 * "expand()" function | |
2901 */ | |
2902 static void | |
2903 f_expand(typval_T *argvars, typval_T *rettv) | |
2904 { | |
2905 char_u *s; | |
2906 int len; | |
2907 char_u *errormsg; | |
2908 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; | |
2909 expand_T xpc; | |
2910 int error = FALSE; | |
2911 char_u *result; | |
2912 | |
2913 rettv->v_type = VAR_STRING; | |
2914 if (argvars[1].v_type != VAR_UNKNOWN | |
2915 && argvars[2].v_type != VAR_UNKNOWN | |
2916 && get_tv_number_chk(&argvars[2], &error) | |
2917 && !error) | |
2918 { | |
2919 rettv->v_type = VAR_LIST; | |
2920 rettv->vval.v_list = NULL; | |
2921 } | |
2922 | |
2923 s = get_tv_string(&argvars[0]); | |
2924 if (*s == '%' || *s == '#' || *s == '<') | |
2925 { | |
2926 ++emsg_off; | |
2927 result = eval_vars(s, s, &len, NULL, &errormsg, NULL); | |
2928 --emsg_off; | |
2929 if (rettv->v_type == VAR_LIST) | |
2930 { | |
2931 if (rettv_list_alloc(rettv) != FAIL && result != NULL) | |
2932 list_append_string(rettv->vval.v_list, result, -1); | |
2933 else | |
2934 vim_free(result); | |
2935 } | |
2936 else | |
2937 rettv->vval.v_string = result; | |
2938 } | |
2939 else | |
2940 { | |
2941 /* When the optional second argument is non-zero, don't remove matches | |
2942 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ | |
2943 if (argvars[1].v_type != VAR_UNKNOWN | |
2944 && get_tv_number_chk(&argvars[1], &error)) | |
2945 options |= WILD_KEEP_ALL; | |
2946 if (!error) | |
2947 { | |
2948 ExpandInit(&xpc); | |
2949 xpc.xp_context = EXPAND_FILES; | |
2950 if (p_wic) | |
2951 options += WILD_ICASE; | |
2952 if (rettv->v_type == VAR_STRING) | |
2953 rettv->vval.v_string = ExpandOne(&xpc, s, NULL, | |
2954 options, WILD_ALL); | |
2955 else if (rettv_list_alloc(rettv) != FAIL) | |
2956 { | |
2957 int i; | |
2958 | |
2959 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP); | |
2960 for (i = 0; i < xpc.xp_numfiles; i++) | |
2961 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); | |
2962 ExpandCleanup(&xpc); | |
2963 } | |
2964 } | |
2965 else | |
2966 rettv->vval.v_string = NULL; | |
2967 } | |
2968 } | |
2969 | |
2970 /* | |
2971 * "extend(list, list [, idx])" function | |
2972 * "extend(dict, dict [, action])" function | |
2973 */ | |
2974 static void | |
2975 f_extend(typval_T *argvars, typval_T *rettv) | |
2976 { | |
2977 char_u *arg_errmsg = (char_u *)N_("extend() argument"); | |
2978 | |
2979 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) | |
2980 { | |
2981 list_T *l1, *l2; | |
2982 listitem_T *item; | |
2983 long before; | |
2984 int error = FALSE; | |
2985 | |
2986 l1 = argvars[0].vval.v_list; | |
2987 l2 = argvars[1].vval.v_list; | |
2988 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE) | |
2989 && l2 != NULL) | |
2990 { | |
2991 if (argvars[2].v_type != VAR_UNKNOWN) | |
2992 { | |
2993 before = (long)get_tv_number_chk(&argvars[2], &error); | |
2994 if (error) | |
2995 return; /* type error; errmsg already given */ | |
2996 | |
2997 if (before == l1->lv_len) | |
2998 item = NULL; | |
2999 else | |
3000 { | |
3001 item = list_find(l1, before); | |
3002 if (item == NULL) | |
3003 { | |
3004 EMSGN(_(e_listidx), before); | |
3005 return; | |
3006 } | |
3007 } | |
3008 } | |
3009 else | |
3010 item = NULL; | |
3011 list_extend(l1, l2, item); | |
3012 | |
3013 copy_tv(&argvars[0], rettv); | |
3014 } | |
3015 } | |
3016 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) | |
3017 { | |
3018 dict_T *d1, *d2; | |
3019 char_u *action; | |
3020 int i; | |
3021 | |
3022 d1 = argvars[0].vval.v_dict; | |
3023 d2 = argvars[1].vval.v_dict; | |
3024 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE) | |
3025 && d2 != NULL) | |
3026 { | |
3027 /* Check the third argument. */ | |
3028 if (argvars[2].v_type != VAR_UNKNOWN) | |
3029 { | |
3030 static char *(av[]) = {"keep", "force", "error"}; | |
3031 | |
3032 action = get_tv_string_chk(&argvars[2]); | |
3033 if (action == NULL) | |
3034 return; /* type error; errmsg already given */ | |
3035 for (i = 0; i < 3; ++i) | |
3036 if (STRCMP(action, av[i]) == 0) | |
3037 break; | |
3038 if (i == 3) | |
3039 { | |
3040 EMSG2(_(e_invarg2), action); | |
3041 return; | |
3042 } | |
3043 } | |
3044 else | |
3045 action = (char_u *)"force"; | |
3046 | |
3047 dict_extend(d1, d2, action); | |
3048 | |
3049 copy_tv(&argvars[0], rettv); | |
3050 } | |
3051 } | |
3052 else | |
3053 EMSG2(_(e_listdictarg), "extend()"); | |
3054 } | |
3055 | |
3056 /* | |
3057 * "feedkeys()" function | |
3058 */ | |
3059 static void | |
3060 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) | |
3061 { | |
3062 int remap = TRUE; | |
3063 int insert = FALSE; | |
3064 char_u *keys, *flags; | |
3065 char_u nbuf[NUMBUFLEN]; | |
3066 int typed = FALSE; | |
3067 int execute = FALSE; | |
3068 int dangerous = FALSE; | |
3069 char_u *keys_esc; | |
3070 | |
3071 /* This is not allowed in the sandbox. If the commands would still be | |
3072 * executed in the sandbox it would be OK, but it probably happens later, | |
3073 * when "sandbox" is no longer set. */ | |
3074 if (check_secure()) | |
3075 return; | |
3076 | |
3077 keys = get_tv_string(&argvars[0]); | |
3078 | |
3079 if (argvars[1].v_type != VAR_UNKNOWN) | |
3080 { | |
3081 flags = get_tv_string_buf(&argvars[1], nbuf); | |
3082 for ( ; *flags != NUL; ++flags) | |
3083 { | |
3084 switch (*flags) | |
3085 { | |
3086 case 'n': remap = FALSE; break; | |
3087 case 'm': remap = TRUE; break; | |
3088 case 't': typed = TRUE; break; | |
3089 case 'i': insert = TRUE; break; | |
3090 case 'x': execute = TRUE; break; | |
3091 case '!': dangerous = TRUE; break; | |
3092 } | |
3093 } | |
3094 } | |
3095 | |
3096 if (*keys != NUL || execute) | |
3097 { | |
3098 /* Need to escape K_SPECIAL and CSI before putting the string in the | |
3099 * typeahead buffer. */ | |
3100 keys_esc = vim_strsave_escape_csi(keys); | |
3101 if (keys_esc != NULL) | |
3102 { | |
3103 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), | |
3104 insert ? 0 : typebuf.tb_len, !typed, FALSE); | |
3105 vim_free(keys_esc); | |
3106 if (vgetc_busy) | |
3107 typebuf_was_filled = TRUE; | |
3108 if (execute) | |
3109 { | |
3110 int save_msg_scroll = msg_scroll; | |
3111 | |
3112 /* Avoid a 1 second delay when the keys start Insert mode. */ | |
3113 msg_scroll = FALSE; | |
3114 | |
3115 if (!dangerous) | |
3116 ++ex_normal_busy; | |
3117 exec_normal(TRUE); | |
3118 if (!dangerous) | |
3119 --ex_normal_busy; | |
3120 msg_scroll |= save_msg_scroll; | |
3121 } | |
3122 } | |
3123 } | |
3124 } | |
3125 | |
3126 /* | |
3127 * "filereadable()" function | |
3128 */ | |
3129 static void | |
3130 f_filereadable(typval_T *argvars, typval_T *rettv) | |
3131 { | |
3132 int fd; | |
3133 char_u *p; | |
3134 int n; | |
3135 | |
3136 #ifndef O_NONBLOCK | |
3137 # define O_NONBLOCK 0 | |
3138 #endif | |
3139 p = get_tv_string(&argvars[0]); | |
3140 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p, | |
3141 O_RDONLY | O_NONBLOCK, 0)) >= 0) | |
3142 { | |
3143 n = TRUE; | |
3144 close(fd); | |
3145 } | |
3146 else | |
3147 n = FALSE; | |
3148 | |
3149 rettv->vval.v_number = n; | |
3150 } | |
3151 | |
3152 /* | |
3153 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have | |
3154 * rights to write into. | |
3155 */ | |
3156 static void | |
3157 f_filewritable(typval_T *argvars, typval_T *rettv) | |
3158 { | |
3159 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0])); | |
3160 } | |
3161 | |
3162 static void | |
3163 findfilendir( | |
3164 typval_T *argvars UNUSED, | |
3165 typval_T *rettv, | |
3166 int find_what UNUSED) | |
3167 { | |
3168 #ifdef FEAT_SEARCHPATH | |
3169 char_u *fname; | |
3170 char_u *fresult = NULL; | |
3171 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; | |
3172 char_u *p; | |
3173 char_u pathbuf[NUMBUFLEN]; | |
3174 int count = 1; | |
3175 int first = TRUE; | |
3176 int error = FALSE; | |
3177 #endif | |
3178 | |
3179 rettv->vval.v_string = NULL; | |
3180 rettv->v_type = VAR_STRING; | |
3181 | |
3182 #ifdef FEAT_SEARCHPATH | |
3183 fname = get_tv_string(&argvars[0]); | |
3184 | |
3185 if (argvars[1].v_type != VAR_UNKNOWN) | |
3186 { | |
3187 p = get_tv_string_buf_chk(&argvars[1], pathbuf); | |
3188 if (p == NULL) | |
3189 error = TRUE; | |
3190 else | |
3191 { | |
3192 if (*p != NUL) | |
3193 path = p; | |
3194 | |
3195 if (argvars[2].v_type != VAR_UNKNOWN) | |
3196 count = (int)get_tv_number_chk(&argvars[2], &error); | |
3197 } | |
3198 } | |
3199 | |
3200 if (count < 0 && rettv_list_alloc(rettv) == FAIL) | |
3201 error = TRUE; | |
3202 | |
3203 if (*fname != NUL && !error) | |
3204 { | |
3205 do | |
3206 { | |
3207 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) | |
3208 vim_free(fresult); | |
3209 fresult = find_file_in_path_option(first ? fname : NULL, | |
3210 first ? (int)STRLEN(fname) : 0, | |
3211 0, first, path, | |
3212 find_what, | |
3213 curbuf->b_ffname, | |
3214 find_what == FINDFILE_DIR | |
3215 ? (char_u *)"" : curbuf->b_p_sua); | |
3216 first = FALSE; | |
3217 | |
3218 if (fresult != NULL && rettv->v_type == VAR_LIST) | |
3219 list_append_string(rettv->vval.v_list, fresult, -1); | |
3220 | |
3221 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); | |
3222 } | |
3223 | |
3224 if (rettv->v_type == VAR_STRING) | |
3225 rettv->vval.v_string = fresult; | |
3226 #endif | |
3227 } | |
3228 | |
3229 /* | |
3230 * "filter()" function | |
3231 */ | |
3232 static void | |
3233 f_filter(typval_T *argvars, typval_T *rettv) | |
3234 { | |
3235 filter_map(argvars, rettv, FALSE); | |
3236 } | |
3237 | |
3238 /* | |
3239 * "finddir({fname}[, {path}[, {count}]])" function | |
3240 */ | |
3241 static void | |
3242 f_finddir(typval_T *argvars, typval_T *rettv) | |
3243 { | |
3244 findfilendir(argvars, rettv, FINDFILE_DIR); | |
3245 } | |
3246 | |
3247 /* | |
3248 * "findfile({fname}[, {path}[, {count}]])" function | |
3249 */ | |
3250 static void | |
3251 f_findfile(typval_T *argvars, typval_T *rettv) | |
3252 { | |
3253 findfilendir(argvars, rettv, FINDFILE_FILE); | |
3254 } | |
3255 | |
3256 #ifdef FEAT_FLOAT | |
3257 /* | |
3258 * "float2nr({float})" function | |
3259 */ | |
3260 static void | |
3261 f_float2nr(typval_T *argvars, typval_T *rettv) | |
3262 { | |
3263 float_T f = 0.0; | |
3264 | |
3265 if (get_float_arg(argvars, &f) == OK) | |
3266 { | |
3267 # ifdef FEAT_NUM64 | |
3268 if (f < -0x7fffffffffffffff) | |
3269 rettv->vval.v_number = -0x7fffffffffffffff; | |
3270 else if (f > 0x7fffffffffffffff) | |
3271 rettv->vval.v_number = 0x7fffffffffffffff; | |
3272 else | |
3273 rettv->vval.v_number = (varnumber_T)f; | |
3274 # else | |
3275 if (f < -0x7fffffff) | |
3276 rettv->vval.v_number = -0x7fffffff; | |
3277 else if (f > 0x7fffffff) | |
3278 rettv->vval.v_number = 0x7fffffff; | |
3279 else | |
3280 rettv->vval.v_number = (varnumber_T)f; | |
3281 # endif | |
3282 } | |
3283 } | |
3284 | |
3285 /* | |
3286 * "floor({float})" function | |
3287 */ | |
3288 static void | |
3289 f_floor(typval_T *argvars, typval_T *rettv) | |
3290 { | |
3291 float_T f = 0.0; | |
3292 | |
3293 rettv->v_type = VAR_FLOAT; | |
3294 if (get_float_arg(argvars, &f) == OK) | |
3295 rettv->vval.v_float = floor(f); | |
3296 else | |
3297 rettv->vval.v_float = 0.0; | |
3298 } | |
3299 | |
3300 /* | |
3301 * "fmod()" function | |
3302 */ | |
3303 static void | |
3304 f_fmod(typval_T *argvars, typval_T *rettv) | |
3305 { | |
3306 float_T fx = 0.0, fy = 0.0; | |
3307 | |
3308 rettv->v_type = VAR_FLOAT; | |
3309 if (get_float_arg(argvars, &fx) == OK | |
3310 && get_float_arg(&argvars[1], &fy) == OK) | |
3311 rettv->vval.v_float = fmod(fx, fy); | |
3312 else | |
3313 rettv->vval.v_float = 0.0; | |
3314 } | |
3315 #endif | |
3316 | |
3317 /* | |
3318 * "fnameescape({string})" function | |
3319 */ | |
3320 static void | |
3321 f_fnameescape(typval_T *argvars, typval_T *rettv) | |
3322 { | |
3323 rettv->vval.v_string = vim_strsave_fnameescape( | |
3324 get_tv_string(&argvars[0]), FALSE); | |
3325 rettv->v_type = VAR_STRING; | |
3326 } | |
3327 | |
3328 /* | |
3329 * "fnamemodify({fname}, {mods})" function | |
3330 */ | |
3331 static void | |
3332 f_fnamemodify(typval_T *argvars, typval_T *rettv) | |
3333 { | |
3334 char_u *fname; | |
3335 char_u *mods; | |
3336 int usedlen = 0; | |
3337 int len; | |
3338 char_u *fbuf = NULL; | |
3339 char_u buf[NUMBUFLEN]; | |
3340 | |
3341 fname = get_tv_string_chk(&argvars[0]); | |
3342 mods = get_tv_string_buf_chk(&argvars[1], buf); | |
3343 if (fname == NULL || mods == NULL) | |
3344 fname = NULL; | |
3345 else | |
3346 { | |
3347 len = (int)STRLEN(fname); | |
3348 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len); | |
3349 } | |
3350 | |
3351 rettv->v_type = VAR_STRING; | |
3352 if (fname == NULL) | |
3353 rettv->vval.v_string = NULL; | |
3354 else | |
3355 rettv->vval.v_string = vim_strnsave(fname, len); | |
3356 vim_free(fbuf); | |
3357 } | |
3358 | |
3359 static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end); | |
3360 | |
3361 /* | |
3362 * "foldclosed()" function | |
3363 */ | |
3364 static void | |
3365 foldclosed_both( | |
3366 typval_T *argvars UNUSED, | |
3367 typval_T *rettv, | |
3368 int end UNUSED) | |
3369 { | |
3370 #ifdef FEAT_FOLDING | |
3371 linenr_T lnum; | |
3372 linenr_T first, last; | |
3373 | |
3374 lnum = get_tv_lnum(argvars); | |
3375 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
3376 { | |
3377 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL)) | |
3378 { | |
3379 if (end) | |
3380 rettv->vval.v_number = (varnumber_T)last; | |
3381 else | |
3382 rettv->vval.v_number = (varnumber_T)first; | |
3383 return; | |
3384 } | |
3385 } | |
3386 #endif | |
3387 rettv->vval.v_number = -1; | |
3388 } | |
3389 | |
3390 /* | |
3391 * "foldclosed()" function | |
3392 */ | |
3393 static void | |
3394 f_foldclosed(typval_T *argvars, typval_T *rettv) | |
3395 { | |
3396 foldclosed_both(argvars, rettv, FALSE); | |
3397 } | |
3398 | |
3399 /* | |
3400 * "foldclosedend()" function | |
3401 */ | |
3402 static void | |
3403 f_foldclosedend(typval_T *argvars, typval_T *rettv) | |
3404 { | |
3405 foldclosed_both(argvars, rettv, TRUE); | |
3406 } | |
3407 | |
3408 /* | |
3409 * "foldlevel()" function | |
3410 */ | |
3411 static void | |
3412 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
3413 { | |
3414 #ifdef FEAT_FOLDING | |
3415 linenr_T lnum; | |
3416 | |
3417 lnum = get_tv_lnum(argvars); | |
3418 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
3419 rettv->vval.v_number = foldLevel(lnum); | |
3420 #endif | |
3421 } | |
3422 | |
3423 /* | |
3424 * "foldtext()" function | |
3425 */ | |
3426 static void | |
3427 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv) | |
3428 { | |
3429 #ifdef FEAT_FOLDING | |
3430 linenr_T foldstart; | |
3431 linenr_T foldend; | |
3432 char_u *dashes; | |
3433 linenr_T lnum; | |
3434 char_u *s; | |
3435 char_u *r; | |
3436 int len; | |
3437 char *txt; | |
3438 #endif | |
3439 | |
3440 rettv->v_type = VAR_STRING; | |
3441 rettv->vval.v_string = NULL; | |
3442 #ifdef FEAT_FOLDING | |
3443 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART); | |
3444 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND); | |
3445 dashes = get_vim_var_str(VV_FOLDDASHES); | |
3446 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count | |
3447 && dashes != NULL) | |
3448 { | |
3449 /* Find first non-empty line in the fold. */ | |
3450 while (lnum < (linenr_T)get_vim_var_nr(VV_FOLDEND)) | |
3451 { | |
3452 if (!linewhite(lnum)) | |
3453 break; | |
3454 ++lnum; | |
3455 } | |
3456 | |
3457 /* Find interesting text in this line. */ | |
3458 s = skipwhite(ml_get(lnum)); | |
3459 /* skip C comment-start */ | |
3460 if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) | |
3461 { | |
3462 s = skipwhite(s + 2); | |
3463 if (*skipwhite(s) == NUL | |
3464 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND)) | |
3465 { | |
3466 s = skipwhite(ml_get(lnum + 1)); | |
3467 if (*s == '*') | |
3468 s = skipwhite(s + 1); | |
3469 } | |
3470 } | |
3471 txt = _("+-%s%3ld lines: "); | |
3472 r = alloc((unsigned)(STRLEN(txt) | |
3473 + STRLEN(dashes) /* for %s */ | |
3474 + 20 /* for %3ld */ | |
3475 + STRLEN(s))); /* concatenated */ | |
3476 if (r != NULL) | |
3477 { | |
3478 sprintf((char *)r, txt, dashes, (long)(foldend - foldstart + 1)); | |
3479 len = (int)STRLEN(r); | |
3480 STRCAT(r, s); | |
3481 /* remove 'foldmarker' and 'commentstring' */ | |
3482 foldtext_cleanup(r + len); | |
3483 rettv->vval.v_string = r; | |
3484 } | |
3485 } | |
3486 #endif | |
3487 } | |
3488 | |
3489 /* | |
3490 * "foldtextresult(lnum)" function | |
3491 */ | |
3492 static void | |
3493 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv) | |
3494 { | |
3495 #ifdef FEAT_FOLDING | |
3496 linenr_T lnum; | |
3497 char_u *text; | |
3498 char_u buf[51]; | |
3499 foldinfo_T foldinfo; | |
3500 int fold_count; | |
3501 #endif | |
3502 | |
3503 rettv->v_type = VAR_STRING; | |
3504 rettv->vval.v_string = NULL; | |
3505 #ifdef FEAT_FOLDING | |
3506 lnum = get_tv_lnum(argvars); | |
3507 /* treat illegal types and illegal string values for {lnum} the same */ | |
3508 if (lnum < 0) | |
3509 lnum = 0; | |
3510 fold_count = foldedCount(curwin, lnum, &foldinfo); | |
3511 if (fold_count > 0) | |
3512 { | |
3513 text = get_foldtext(curwin, lnum, lnum + fold_count - 1, | |
3514 &foldinfo, buf); | |
3515 if (text == buf) | |
3516 text = vim_strsave(text); | |
3517 rettv->vval.v_string = text; | |
3518 } | |
3519 #endif | |
3520 } | |
3521 | |
3522 /* | |
3523 * "foreground()" function | |
3524 */ | |
3525 static void | |
3526 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
3527 { | |
3528 #ifdef FEAT_GUI | |
3529 if (gui.in_use) | |
3530 gui_mch_set_foreground(); | |
3531 #else | |
3532 # ifdef WIN32 | |
3533 win32_set_foreground(); | |
3534 # endif | |
3535 #endif | |
3536 } | |
3537 | |
3538 /* | |
3539 * "function()" function | |
3540 */ | |
3541 static void | |
3542 f_function(typval_T *argvars, typval_T *rettv) | |
3543 { | |
3544 char_u *s; | |
3545 char_u *name; | |
3546 int use_string = FALSE; | |
3547 partial_T *arg_pt = NULL; | |
3548 | |
3549 if (argvars[0].v_type == VAR_FUNC) | |
3550 { | |
3551 /* function(MyFunc, [arg], dict) */ | |
3552 s = argvars[0].vval.v_string; | |
3553 } | |
3554 else if (argvars[0].v_type == VAR_PARTIAL | |
3555 && argvars[0].vval.v_partial != NULL) | |
3556 { | |
3557 /* function(dict.MyFunc, [arg]) */ | |
3558 arg_pt = argvars[0].vval.v_partial; | |
3559 s = arg_pt->pt_name; | |
3560 } | |
3561 else | |
3562 { | |
3563 /* function('MyFunc', [arg], dict) */ | |
3564 s = get_tv_string(&argvars[0]); | |
3565 use_string = TRUE; | |
3566 } | |
3567 | |
3568 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))) | |
3569 EMSG2(_(e_invarg2), s); | |
3570 /* Don't check an autoload name for existence here. */ | |
3571 else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL | |
3572 && !function_exists(s)) | |
3573 EMSG2(_("E700: Unknown function: %s"), s); | |
3574 else | |
3575 { | |
3576 int dict_idx = 0; | |
3577 int arg_idx = 0; | |
3578 list_T *list = NULL; | |
3579 | |
3580 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) | |
3581 { | |
3582 char sid_buf[25]; | |
3583 int off = *s == 's' ? 2 : 5; | |
3584 | |
3585 /* Expand s: and <SID> into <SNR>nr_, so that the function can | |
3586 * also be called from another script. Using trans_function_name() | |
3587 * would also work, but some plugins depend on the name being | |
3588 * printable text. */ | |
3589 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID); | |
3590 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); | |
3591 if (name != NULL) | |
3592 { | |
3593 STRCPY(name, sid_buf); | |
3594 STRCAT(name, s + off); | |
3595 } | |
3596 } | |
3597 else | |
3598 name = vim_strsave(s); | |
3599 | |
3600 if (argvars[1].v_type != VAR_UNKNOWN) | |
3601 { | |
3602 if (argvars[2].v_type != VAR_UNKNOWN) | |
3603 { | |
3604 /* function(name, [args], dict) */ | |
3605 arg_idx = 1; | |
3606 dict_idx = 2; | |
3607 } | |
3608 else if (argvars[1].v_type == VAR_DICT) | |
3609 /* function(name, dict) */ | |
3610 dict_idx = 1; | |
3611 else | |
3612 /* function(name, [args]) */ | |
3613 arg_idx = 1; | |
3614 if (dict_idx > 0) | |
3615 { | |
3616 if (argvars[dict_idx].v_type != VAR_DICT) | |
3617 { | |
3618 EMSG(_("E922: expected a dict")); | |
3619 vim_free(name); | |
3620 return; | |
3621 } | |
3622 if (argvars[dict_idx].vval.v_dict == NULL) | |
3623 dict_idx = 0; | |
3624 } | |
3625 if (arg_idx > 0) | |
3626 { | |
3627 if (argvars[arg_idx].v_type != VAR_LIST) | |
3628 { | |
3629 EMSG(_("E923: Second argument of function() must be a list or a dict")); | |
3630 vim_free(name); | |
3631 return; | |
3632 } | |
3633 list = argvars[arg_idx].vval.v_list; | |
3634 if (list == NULL || list->lv_len == 0) | |
3635 arg_idx = 0; | |
3636 } | |
3637 } | |
3638 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL) | |
3639 { | |
3640 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); | |
3641 | |
3642 /* result is a VAR_PARTIAL */ | |
3643 if (pt == NULL) | |
3644 vim_free(name); | |
3645 else | |
3646 { | |
3647 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) | |
3648 { | |
3649 listitem_T *li; | |
3650 int i = 0; | |
3651 int arg_len = 0; | |
3652 int lv_len = 0; | |
3653 | |
3654 if (arg_pt != NULL) | |
3655 arg_len = arg_pt->pt_argc; | |
3656 if (list != NULL) | |
3657 lv_len = list->lv_len; | |
3658 pt->pt_argc = arg_len + lv_len; | |
3659 pt->pt_argv = (typval_T *)alloc( | |
3660 sizeof(typval_T) * pt->pt_argc); | |
3661 if (pt->pt_argv == NULL) | |
3662 { | |
3663 vim_free(pt); | |
3664 vim_free(name); | |
3665 return; | |
3666 } | |
3667 else | |
3668 { | |
3669 for (i = 0; i < arg_len; i++) | |
3670 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); | |
3671 if (lv_len > 0) | |
3672 for (li = list->lv_first; li != NULL; | |
3673 li = li->li_next) | |
3674 copy_tv(&li->li_tv, &pt->pt_argv[i++]); | |
3675 } | |
3676 } | |
3677 | |
3678 /* For "function(dict.func, [], dict)" and "func" is a partial | |
3679 * use "dict". That is backwards compatible. */ | |
3680 if (dict_idx > 0) | |
3681 { | |
3682 /* The dict is bound explicitly, pt_auto is FALSE. */ | |
3683 pt->pt_dict = argvars[dict_idx].vval.v_dict; | |
3684 ++pt->pt_dict->dv_refcount; | |
3685 } | |
3686 else if (arg_pt != NULL) | |
3687 { | |
3688 /* If the dict was bound automatically the result is also | |
3689 * bound automatically. */ | |
3690 pt->pt_dict = arg_pt->pt_dict; | |
3691 pt->pt_auto = arg_pt->pt_auto; | |
3692 if (pt->pt_dict != NULL) | |
3693 ++pt->pt_dict->dv_refcount; | |
3694 } | |
3695 | |
3696 pt->pt_refcount = 1; | |
3697 pt->pt_name = name; | |
3698 func_ref(pt->pt_name); | |
3699 } | |
3700 rettv->v_type = VAR_PARTIAL; | |
3701 rettv->vval.v_partial = pt; | |
3702 } | |
3703 else | |
3704 { | |
3705 /* result is a VAR_FUNC */ | |
3706 rettv->v_type = VAR_FUNC; | |
3707 rettv->vval.v_string = name; | |
3708 func_ref(name); | |
3709 } | |
3710 } | |
3711 } | |
3712 | |
3713 /* | |
3714 * "garbagecollect()" function | |
3715 */ | |
3716 static void | |
3717 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) | |
3718 { | |
3719 /* This is postponed until we are back at the toplevel, because we may be | |
3720 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ | |
3721 want_garbage_collect = TRUE; | |
3722 | |
3723 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1) | |
3724 garbage_collect_at_exit = TRUE; | |
3725 } | |
3726 | |
3727 /* | |
3728 * "get()" function | |
3729 */ | |
3730 static void | |
3731 f_get(typval_T *argvars, typval_T *rettv) | |
3732 { | |
3733 listitem_T *li; | |
3734 list_T *l; | |
3735 dictitem_T *di; | |
3736 dict_T *d; | |
3737 typval_T *tv = NULL; | |
3738 | |
3739 if (argvars[0].v_type == VAR_LIST) | |
3740 { | |
3741 if ((l = argvars[0].vval.v_list) != NULL) | |
3742 { | |
3743 int error = FALSE; | |
3744 | |
3745 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error)); | |
3746 if (!error && li != NULL) | |
3747 tv = &li->li_tv; | |
3748 } | |
3749 } | |
3750 else if (argvars[0].v_type == VAR_DICT) | |
3751 { | |
3752 if ((d = argvars[0].vval.v_dict) != NULL) | |
3753 { | |
3754 di = dict_find(d, get_tv_string(&argvars[1]), -1); | |
3755 if (di != NULL) | |
3756 tv = &di->di_tv; | |
3757 } | |
3758 } | |
3759 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC) | |
3760 { | |
3761 partial_T *pt; | |
3762 partial_T fref_pt; | |
3763 | |
3764 if (argvars[0].v_type == VAR_PARTIAL) | |
3765 pt = argvars[0].vval.v_partial; | |
3766 else | |
3767 { | |
3768 vim_memset(&fref_pt, 0, sizeof(fref_pt)); | |
3769 fref_pt.pt_name = argvars[0].vval.v_string; | |
3770 pt = &fref_pt; | |
3771 } | |
3772 | |
3773 if (pt != NULL) | |
3774 { | |
3775 char_u *what = get_tv_string(&argvars[1]); | |
3776 | |
3777 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) | |
3778 { | |
3779 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); | |
3780 if (pt->pt_name == NULL) | |
3781 rettv->vval.v_string = NULL; | |
3782 else | |
3783 rettv->vval.v_string = vim_strsave(pt->pt_name); | |
3784 } | |
3785 else if (STRCMP(what, "dict") == 0) | |
3786 { | |
3787 rettv->v_type = VAR_DICT; | |
3788 rettv->vval.v_dict = pt->pt_dict; | |
3789 if (pt->pt_dict != NULL) | |
3790 ++pt->pt_dict->dv_refcount; | |
3791 } | |
3792 else if (STRCMP(what, "args") == 0) | |
3793 { | |
3794 rettv->v_type = VAR_LIST; | |
3795 if (rettv_list_alloc(rettv) == OK) | |
3796 { | |
3797 int i; | |
3798 | |
3799 for (i = 0; i < pt->pt_argc; ++i) | |
3800 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); | |
3801 } | |
3802 } | |
3803 else | |
3804 EMSG2(_(e_invarg2), what); | |
3805 return; | |
3806 } | |
3807 } | |
3808 else | |
3809 EMSG2(_(e_listdictarg), "get()"); | |
3810 | |
3811 if (tv == NULL) | |
3812 { | |
3813 if (argvars[2].v_type != VAR_UNKNOWN) | |
3814 copy_tv(&argvars[2], rettv); | |
3815 } | |
3816 else | |
3817 copy_tv(tv, rettv); | |
3818 } | |
3819 | |
3820 static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv); | |
3821 | |
3822 /* | |
3823 * Get line or list of lines from buffer "buf" into "rettv". | |
3824 * Return a range (from start to end) of lines in rettv from the specified | |
3825 * buffer. | |
3826 * If 'retlist' is TRUE, then the lines are returned as a Vim List. | |
3827 */ | |
3828 static void | |
3829 get_buffer_lines( | |
3830 buf_T *buf, | |
3831 linenr_T start, | |
3832 linenr_T end, | |
3833 int retlist, | |
3834 typval_T *rettv) | |
3835 { | |
3836 char_u *p; | |
3837 | |
3838 rettv->v_type = VAR_STRING; | |
3839 rettv->vval.v_string = NULL; | |
3840 if (retlist && rettv_list_alloc(rettv) == FAIL) | |
3841 return; | |
3842 | |
3843 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) | |
3844 return; | |
3845 | |
3846 if (!retlist) | |
3847 { | |
3848 if (start >= 1 && start <= buf->b_ml.ml_line_count) | |
3849 p = ml_get_buf(buf, start, FALSE); | |
3850 else | |
3851 p = (char_u *)""; | |
3852 rettv->vval.v_string = vim_strsave(p); | |
3853 } | |
3854 else | |
3855 { | |
3856 if (end < start) | |
3857 return; | |
3858 | |
3859 if (start < 1) | |
3860 start = 1; | |
3861 if (end > buf->b_ml.ml_line_count) | |
3862 end = buf->b_ml.ml_line_count; | |
3863 while (start <= end) | |
3864 if (list_append_string(rettv->vval.v_list, | |
3865 ml_get_buf(buf, start++, FALSE), -1) == FAIL) | |
3866 break; | |
3867 } | |
3868 } | |
3869 | |
3870 /* | |
3871 * Get the lnum from the first argument. | |
3872 * Also accepts "$", then "buf" is used. | |
3873 * Returns 0 on error. | |
3874 */ | |
3875 static linenr_T | |
3876 get_tv_lnum_buf(typval_T *argvars, buf_T *buf) | |
3877 { | |
3878 if (argvars[0].v_type == VAR_STRING | |
3879 && argvars[0].vval.v_string != NULL | |
3880 && argvars[0].vval.v_string[0] == '$' | |
3881 && buf != NULL) | |
3882 return buf->b_ml.ml_line_count; | |
3883 return (linenr_T)get_tv_number_chk(&argvars[0], NULL); | |
3884 } | |
3885 | |
3886 /* | |
3887 * "getbufline()" function | |
3888 */ | |
3889 static void | |
3890 f_getbufline(typval_T *argvars, typval_T *rettv) | |
3891 { | |
3892 linenr_T lnum; | |
3893 linenr_T end; | |
3894 buf_T *buf; | |
3895 | |
3896 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
3897 ++emsg_off; | |
3898 buf = get_buf_tv(&argvars[0], FALSE); | |
3899 --emsg_off; | |
3900 | |
3901 lnum = get_tv_lnum_buf(&argvars[1], buf); | |
3902 if (argvars[2].v_type == VAR_UNKNOWN) | |
3903 end = lnum; | |
3904 else | |
3905 end = get_tv_lnum_buf(&argvars[2], buf); | |
3906 | |
3907 get_buffer_lines(buf, lnum, end, TRUE, rettv); | |
3908 } | |
3909 | |
3910 /* | |
3911 * "getbufvar()" function | |
3912 */ | |
3913 static void | |
3914 f_getbufvar(typval_T *argvars, typval_T *rettv) | |
3915 { | |
3916 buf_T *buf; | |
3917 buf_T *save_curbuf; | |
3918 char_u *varname; | |
3919 dictitem_T *v; | |
3920 int done = FALSE; | |
3921 | |
3922 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
3923 varname = get_tv_string_chk(&argvars[1]); | |
3924 ++emsg_off; | |
3925 buf = get_buf_tv(&argvars[0], FALSE); | |
3926 | |
3927 rettv->v_type = VAR_STRING; | |
3928 rettv->vval.v_string = NULL; | |
3929 | |
3930 if (buf != NULL && varname != NULL) | |
3931 { | |
3932 /* set curbuf to be our buf, temporarily */ | |
3933 save_curbuf = curbuf; | |
3934 curbuf = buf; | |
3935 | |
3936 if (*varname == '&') /* buffer-local-option */ | |
3937 { | |
3938 if (get_option_tv(&varname, rettv, TRUE) == OK) | |
3939 done = TRUE; | |
3940 } | |
3941 else if (STRCMP(varname, "changedtick") == 0) | |
3942 { | |
3943 rettv->v_type = VAR_NUMBER; | |
3944 rettv->vval.v_number = curbuf->b_changedtick; | |
3945 done = TRUE; | |
3946 } | |
3947 else | |
3948 { | |
3949 /* Look up the variable. */ | |
3950 /* Let getbufvar({nr}, "") return the "b:" dictionary. */ | |
3951 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, | |
3952 'b', varname, FALSE); | |
3953 if (v != NULL) | |
3954 { | |
3955 copy_tv(&v->di_tv, rettv); | |
3956 done = TRUE; | |
3957 } | |
3958 } | |
3959 | |
3960 /* restore previous notion of curbuf */ | |
3961 curbuf = save_curbuf; | |
3962 } | |
3963 | |
3964 if (!done && argvars[2].v_type != VAR_UNKNOWN) | |
3965 /* use the default value */ | |
3966 copy_tv(&argvars[2], rettv); | |
3967 | |
3968 --emsg_off; | |
3969 } | |
3970 | |
3971 /* | |
3972 * "getchar()" function | |
3973 */ | |
3974 static void | |
3975 f_getchar(typval_T *argvars, typval_T *rettv) | |
3976 { | |
3977 varnumber_T n; | |
3978 int error = FALSE; | |
3979 | |
3980 /* Position the cursor. Needed after a message that ends in a space. */ | |
3981 windgoto(msg_row, msg_col); | |
3982 | |
3983 ++no_mapping; | |
3984 ++allow_keys; | |
3985 for (;;) | |
3986 { | |
3987 if (argvars[0].v_type == VAR_UNKNOWN) | |
3988 /* getchar(): blocking wait. */ | |
3989 n = safe_vgetc(); | |
3990 else if (get_tv_number_chk(&argvars[0], &error) == 1) | |
3991 /* getchar(1): only check if char avail */ | |
3992 n = vpeekc_any(); | |
3993 else if (error || vpeekc_any() == NUL) | |
3994 /* illegal argument or getchar(0) and no char avail: return zero */ | |
3995 n = 0; | |
3996 else | |
3997 /* getchar(0) and char avail: return char */ | |
3998 n = safe_vgetc(); | |
3999 | |
4000 if (n == K_IGNORE) | |
4001 continue; | |
4002 break; | |
4003 } | |
4004 --no_mapping; | |
4005 --allow_keys; | |
4006 | |
4007 set_vim_var_nr(VV_MOUSE_WIN, 0); | |
4008 set_vim_var_nr(VV_MOUSE_WINID, 0); | |
4009 set_vim_var_nr(VV_MOUSE_LNUM, 0); | |
4010 set_vim_var_nr(VV_MOUSE_COL, 0); | |
4011 | |
4012 rettv->vval.v_number = n; | |
4013 if (IS_SPECIAL(n) || mod_mask != 0) | |
4014 { | |
4015 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */ | |
4016 int i = 0; | |
4017 | |
4018 /* Turn a special key into three bytes, plus modifier. */ | |
4019 if (mod_mask != 0) | |
4020 { | |
4021 temp[i++] = K_SPECIAL; | |
4022 temp[i++] = KS_MODIFIER; | |
4023 temp[i++] = mod_mask; | |
4024 } | |
4025 if (IS_SPECIAL(n)) | |
4026 { | |
4027 temp[i++] = K_SPECIAL; | |
4028 temp[i++] = K_SECOND(n); | |
4029 temp[i++] = K_THIRD(n); | |
4030 } | |
4031 #ifdef FEAT_MBYTE | |
4032 else if (has_mbyte) | |
4033 i += (*mb_char2bytes)(n, temp + i); | |
4034 #endif | |
4035 else | |
4036 temp[i++] = n; | |
4037 temp[i++] = NUL; | |
4038 rettv->v_type = VAR_STRING; | |
4039 rettv->vval.v_string = vim_strsave(temp); | |
4040 | |
4041 #ifdef FEAT_MOUSE | |
4042 if (is_mouse_key(n)) | |
4043 { | |
4044 int row = mouse_row; | |
4045 int col = mouse_col; | |
4046 win_T *win; | |
4047 linenr_T lnum; | |
4048 # ifdef FEAT_WINDOWS | |
4049 win_T *wp; | |
4050 # endif | |
4051 int winnr = 1; | |
4052 | |
4053 if (row >= 0 && col >= 0) | |
4054 { | |
4055 /* Find the window at the mouse coordinates and compute the | |
4056 * text position. */ | |
4057 win = mouse_find_win(&row, &col); | |
4058 (void)mouse_comp_pos(win, &row, &col, &lnum); | |
4059 # ifdef FEAT_WINDOWS | |
4060 for (wp = firstwin; wp != win; wp = wp->w_next) | |
4061 ++winnr; | |
4062 # endif | |
4063 set_vim_var_nr(VV_MOUSE_WIN, winnr); | |
4064 set_vim_var_nr(VV_MOUSE_WINID, win->w_id); | |
4065 set_vim_var_nr(VV_MOUSE_LNUM, lnum); | |
4066 set_vim_var_nr(VV_MOUSE_COL, col + 1); | |
4067 } | |
4068 } | |
4069 #endif | |
4070 } | |
4071 } | |
4072 | |
4073 /* | |
4074 * "getcharmod()" function | |
4075 */ | |
4076 static void | |
4077 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv) | |
4078 { | |
4079 rettv->vval.v_number = mod_mask; | |
4080 } | |
4081 | |
4082 /* | |
4083 * "getcharsearch()" function | |
4084 */ | |
4085 static void | |
4086 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) | |
4087 { | |
4088 if (rettv_dict_alloc(rettv) != FAIL) | |
4089 { | |
4090 dict_T *dict = rettv->vval.v_dict; | |
4091 | |
4092 dict_add_nr_str(dict, "char", 0L, last_csearch()); | |
4093 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL); | |
4094 dict_add_nr_str(dict, "until", last_csearch_until(), NULL); | |
4095 } | |
4096 } | |
4097 | |
4098 /* | |
4099 * "getcmdline()" function | |
4100 */ | |
4101 static void | |
4102 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv) | |
4103 { | |
4104 rettv->v_type = VAR_STRING; | |
4105 rettv->vval.v_string = get_cmdline_str(); | |
4106 } | |
4107 | |
4108 /* | |
4109 * "getcmdpos()" function | |
4110 */ | |
4111 static void | |
4112 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv) | |
4113 { | |
4114 rettv->vval.v_number = get_cmdline_pos() + 1; | |
4115 } | |
4116 | |
4117 /* | |
4118 * "getcmdtype()" function | |
4119 */ | |
4120 static void | |
4121 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv) | |
4122 { | |
4123 rettv->v_type = VAR_STRING; | |
4124 rettv->vval.v_string = alloc(2); | |
4125 if (rettv->vval.v_string != NULL) | |
4126 { | |
4127 rettv->vval.v_string[0] = get_cmdline_type(); | |
4128 rettv->vval.v_string[1] = NUL; | |
4129 } | |
4130 } | |
4131 | |
4132 /* | |
4133 * "getcmdwintype()" function | |
4134 */ | |
4135 static void | |
4136 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) | |
4137 { | |
4138 rettv->v_type = VAR_STRING; | |
4139 rettv->vval.v_string = NULL; | |
4140 #ifdef FEAT_CMDWIN | |
4141 rettv->vval.v_string = alloc(2); | |
4142 if (rettv->vval.v_string != NULL) | |
4143 { | |
4144 rettv->vval.v_string[0] = cmdwin_type; | |
4145 rettv->vval.v_string[1] = NUL; | |
4146 } | |
4147 #endif | |
4148 } | |
4149 | |
4150 #if defined(FEAT_CMDL_COMPL) | |
4151 /* | |
4152 * "getcompletion()" function | |
4153 */ | |
4154 static void | |
4155 f_getcompletion(typval_T *argvars, typval_T *rettv) | |
4156 { | |
4157 char_u *pat; | |
4158 expand_T xpc; | |
4159 int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL | |
4160 | WILD_LIST_NOTFOUND | WILD_NO_BEEP; | |
4161 | |
4162 if (p_wic) | |
4163 options |= WILD_ICASE; | |
4164 | |
4165 ExpandInit(&xpc); | |
4166 xpc.xp_pattern = get_tv_string(&argvars[0]); | |
4167 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); | |
4168 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1])); | |
4169 if (xpc.xp_context == EXPAND_NOTHING) | |
4170 { | |
4171 if (argvars[1].v_type == VAR_STRING) | |
4172 EMSG2(_(e_invarg2), argvars[1].vval.v_string); | |
4173 else | |
4174 EMSG(_(e_invarg)); | |
4175 return; | |
4176 } | |
4177 | |
4178 # if defined(FEAT_MENU) | |
4179 if (xpc.xp_context == EXPAND_MENUS) | |
4180 { | |
4181 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); | |
4182 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); | |
4183 } | |
4184 # endif | |
4185 | |
4186 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); | |
4187 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) | |
4188 { | |
4189 int i; | |
4190 | |
4191 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); | |
4192 | |
4193 for (i = 0; i < xpc.xp_numfiles; i++) | |
4194 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); | |
4195 } | |
4196 vim_free(pat); | |
4197 ExpandCleanup(&xpc); | |
4198 } | |
4199 #endif | |
4200 | |
4201 /* | |
4202 * "getcwd()" function | |
4203 */ | |
4204 static void | |
4205 f_getcwd(typval_T *argvars, typval_T *rettv) | |
4206 { | |
4207 win_T *wp = NULL; | |
4208 char_u *cwd; | |
4209 | |
4210 rettv->v_type = VAR_STRING; | |
4211 rettv->vval.v_string = NULL; | |
4212 | |
4213 wp = find_tabwin(&argvars[0], &argvars[1]); | |
4214 if (wp != NULL) | |
4215 { | |
4216 if (wp->w_localdir != NULL) | |
4217 rettv->vval.v_string = vim_strsave(wp->w_localdir); | |
4218 else if (globaldir != NULL) | |
4219 rettv->vval.v_string = vim_strsave(globaldir); | |
4220 else | |
4221 { | |
4222 cwd = alloc(MAXPATHL); | |
4223 if (cwd != NULL) | |
4224 { | |
4225 if (mch_dirname(cwd, MAXPATHL) != FAIL) | |
4226 rettv->vval.v_string = vim_strsave(cwd); | |
4227 vim_free(cwd); | |
4228 } | |
4229 } | |
4230 #ifdef BACKSLASH_IN_FILENAME | |
4231 if (rettv->vval.v_string != NULL) | |
4232 slash_adjust(rettv->vval.v_string); | |
4233 #endif | |
4234 } | |
4235 } | |
4236 | |
4237 /* | |
4238 * "getfontname()" function | |
4239 */ | |
4240 static void | |
4241 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv) | |
4242 { | |
4243 rettv->v_type = VAR_STRING; | |
4244 rettv->vval.v_string = NULL; | |
4245 #ifdef FEAT_GUI | |
4246 if (gui.in_use) | |
4247 { | |
4248 GuiFont font; | |
4249 char_u *name = NULL; | |
4250 | |
4251 if (argvars[0].v_type == VAR_UNKNOWN) | |
4252 { | |
4253 /* Get the "Normal" font. Either the name saved by | |
4254 * hl_set_font_name() or from the font ID. */ | |
4255 font = gui.norm_font; | |
4256 name = hl_get_font_name(); | |
4257 } | |
4258 else | |
4259 { | |
4260 name = get_tv_string(&argvars[0]); | |
4261 if (STRCMP(name, "*") == 0) /* don't use font dialog */ | |
4262 return; | |
4263 font = gui_mch_get_font(name, FALSE); | |
4264 if (font == NOFONT) | |
4265 return; /* Invalid font name, return empty string. */ | |
4266 } | |
4267 rettv->vval.v_string = gui_mch_get_fontname(font, name); | |
4268 if (argvars[0].v_type != VAR_UNKNOWN) | |
4269 gui_mch_free_font(font); | |
4270 } | |
4271 #endif | |
4272 } | |
4273 | |
4274 /* | |
4275 * "getfperm({fname})" function | |
4276 */ | |
4277 static void | |
4278 f_getfperm(typval_T *argvars, typval_T *rettv) | |
4279 { | |
4280 char_u *fname; | |
4281 stat_T st; | |
4282 char_u *perm = NULL; | |
4283 char_u flags[] = "rwx"; | |
4284 int i; | |
4285 | |
4286 fname = get_tv_string(&argvars[0]); | |
4287 | |
4288 rettv->v_type = VAR_STRING; | |
4289 if (mch_stat((char *)fname, &st) >= 0) | |
4290 { | |
4291 perm = vim_strsave((char_u *)"---------"); | |
4292 if (perm != NULL) | |
4293 { | |
4294 for (i = 0; i < 9; i++) | |
4295 { | |
4296 if (st.st_mode & (1 << (8 - i))) | |
4297 perm[i] = flags[i % 3]; | |
4298 } | |
4299 } | |
4300 } | |
4301 rettv->vval.v_string = perm; | |
4302 } | |
4303 | |
4304 /* | |
4305 * "getfsize({fname})" function | |
4306 */ | |
4307 static void | |
4308 f_getfsize(typval_T *argvars, typval_T *rettv) | |
4309 { | |
4310 char_u *fname; | |
4311 stat_T st; | |
4312 | |
4313 fname = get_tv_string(&argvars[0]); | |
4314 | |
4315 rettv->v_type = VAR_NUMBER; | |
4316 | |
4317 if (mch_stat((char *)fname, &st) >= 0) | |
4318 { | |
4319 if (mch_isdir(fname)) | |
4320 rettv->vval.v_number = 0; | |
4321 else | |
4322 { | |
4323 rettv->vval.v_number = (varnumber_T)st.st_size; | |
4324 | |
4325 /* non-perfect check for overflow */ | |
4326 if ((off_T)rettv->vval.v_number != (off_T)st.st_size) | |
4327 rettv->vval.v_number = -2; | |
4328 } | |
4329 } | |
4330 else | |
4331 rettv->vval.v_number = -1; | |
4332 } | |
4333 | |
4334 /* | |
4335 * "getftime({fname})" function | |
4336 */ | |
4337 static void | |
4338 f_getftime(typval_T *argvars, typval_T *rettv) | |
4339 { | |
4340 char_u *fname; | |
4341 stat_T st; | |
4342 | |
4343 fname = get_tv_string(&argvars[0]); | |
4344 | |
4345 if (mch_stat((char *)fname, &st) >= 0) | |
4346 rettv->vval.v_number = (varnumber_T)st.st_mtime; | |
4347 else | |
4348 rettv->vval.v_number = -1; | |
4349 } | |
4350 | |
4351 /* | |
4352 * "getftype({fname})" function | |
4353 */ | |
4354 static void | |
4355 f_getftype(typval_T *argvars, typval_T *rettv) | |
4356 { | |
4357 char_u *fname; | |
4358 stat_T st; | |
4359 char_u *type = NULL; | |
4360 char *t; | |
4361 | |
4362 fname = get_tv_string(&argvars[0]); | |
4363 | |
4364 rettv->v_type = VAR_STRING; | |
4365 if (mch_lstat((char *)fname, &st) >= 0) | |
4366 { | |
4367 #ifdef S_ISREG | |
4368 if (S_ISREG(st.st_mode)) | |
4369 t = "file"; | |
4370 else if (S_ISDIR(st.st_mode)) | |
4371 t = "dir"; | |
4372 # ifdef S_ISLNK | |
4373 else if (S_ISLNK(st.st_mode)) | |
4374 t = "link"; | |
4375 # endif | |
4376 # ifdef S_ISBLK | |
4377 else if (S_ISBLK(st.st_mode)) | |
4378 t = "bdev"; | |
4379 # endif | |
4380 # ifdef S_ISCHR | |
4381 else if (S_ISCHR(st.st_mode)) | |
4382 t = "cdev"; | |
4383 # endif | |
4384 # ifdef S_ISFIFO | |
4385 else if (S_ISFIFO(st.st_mode)) | |
4386 t = "fifo"; | |
4387 # endif | |
4388 # ifdef S_ISSOCK | |
4389 else if (S_ISSOCK(st.st_mode)) | |
4390 t = "fifo"; | |
4391 # endif | |
4392 else | |
4393 t = "other"; | |
4394 #else | |
4395 # ifdef S_IFMT | |
4396 switch (st.st_mode & S_IFMT) | |
4397 { | |
4398 case S_IFREG: t = "file"; break; | |
4399 case S_IFDIR: t = "dir"; break; | |
4400 # ifdef S_IFLNK | |
4401 case S_IFLNK: t = "link"; break; | |
4402 # endif | |
4403 # ifdef S_IFBLK | |
4404 case S_IFBLK: t = "bdev"; break; | |
4405 # endif | |
4406 # ifdef S_IFCHR | |
4407 case S_IFCHR: t = "cdev"; break; | |
4408 # endif | |
4409 # ifdef S_IFIFO | |
4410 case S_IFIFO: t = "fifo"; break; | |
4411 # endif | |
4412 # ifdef S_IFSOCK | |
4413 case S_IFSOCK: t = "socket"; break; | |
4414 # endif | |
4415 default: t = "other"; | |
4416 } | |
4417 # else | |
4418 if (mch_isdir(fname)) | |
4419 t = "dir"; | |
4420 else | |
4421 t = "file"; | |
4422 # endif | |
4423 #endif | |
4424 type = vim_strsave((char_u *)t); | |
4425 } | |
4426 rettv->vval.v_string = type; | |
4427 } | |
4428 | |
4429 /* | |
4430 * "getline(lnum, [end])" function | |
4431 */ | |
4432 static void | |
4433 f_getline(typval_T *argvars, typval_T *rettv) | |
4434 { | |
4435 linenr_T lnum; | |
4436 linenr_T end; | |
4437 int retlist; | |
4438 | |
4439 lnum = get_tv_lnum(argvars); | |
4440 if (argvars[1].v_type == VAR_UNKNOWN) | |
4441 { | |
4442 end = 0; | |
4443 retlist = FALSE; | |
4444 } | |
4445 else | |
4446 { | |
4447 end = get_tv_lnum(&argvars[1]); | |
4448 retlist = TRUE; | |
4449 } | |
4450 | |
4451 get_buffer_lines(curbuf, lnum, end, retlist, rettv); | |
4452 } | |
4453 | |
4454 /* | |
4455 * "getmatches()" function | |
4456 */ | |
4457 static void | |
4458 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4459 { | |
4460 #ifdef FEAT_SEARCH_EXTRA | |
4461 dict_T *dict; | |
4462 matchitem_T *cur = curwin->w_match_head; | |
4463 int i; | |
4464 | |
4465 if (rettv_list_alloc(rettv) == OK) | |
4466 { | |
4467 while (cur != NULL) | |
4468 { | |
4469 dict = dict_alloc(); | |
4470 if (dict == NULL) | |
4471 return; | |
4472 if (cur->match.regprog == NULL) | |
4473 { | |
4474 /* match added with matchaddpos() */ | |
4475 for (i = 0; i < MAXPOSMATCH; ++i) | |
4476 { | |
4477 llpos_T *llpos; | |
4478 char buf[6]; | |
4479 list_T *l; | |
4480 | |
4481 llpos = &cur->pos.pos[i]; | |
4482 if (llpos->lnum == 0) | |
4483 break; | |
4484 l = list_alloc(); | |
4485 if (l == NULL) | |
4486 break; | |
4487 list_append_number(l, (varnumber_T)llpos->lnum); | |
4488 if (llpos->col > 0) | |
4489 { | |
4490 list_append_number(l, (varnumber_T)llpos->col); | |
4491 list_append_number(l, (varnumber_T)llpos->len); | |
4492 } | |
4493 sprintf(buf, "pos%d", i + 1); | |
4494 dict_add_list(dict, buf, l); | |
4495 } | |
4496 } | |
4497 else | |
4498 { | |
4499 dict_add_nr_str(dict, "pattern", 0L, cur->pattern); | |
4500 } | |
4501 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); | |
4502 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); | |
4503 dict_add_nr_str(dict, "id", (long)cur->id, NULL); | |
4504 # if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE) | |
4505 if (cur->conceal_char) | |
4506 { | |
4507 char_u buf[MB_MAXBYTES + 1]; | |
4508 | |
4509 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; | |
4510 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf); | |
4511 } | |
4512 # endif | |
4513 list_append_dict(rettv->vval.v_list, dict); | |
4514 cur = cur->next; | |
4515 } | |
4516 } | |
4517 #endif | |
4518 } | |
4519 | |
4520 /* | |
4521 * "getpid()" function | |
4522 */ | |
4523 static void | |
4524 f_getpid(typval_T *argvars UNUSED, typval_T *rettv) | |
4525 { | |
4526 rettv->vval.v_number = mch_get_pid(); | |
4527 } | |
4528 | |
4529 static void | |
4530 getpos_both( | |
4531 typval_T *argvars, | |
4532 typval_T *rettv, | |
4533 int getcurpos) | |
4534 { | |
4535 pos_T *fp; | |
4536 list_T *l; | |
4537 int fnum = -1; | |
4538 | |
4539 if (rettv_list_alloc(rettv) == OK) | |
4540 { | |
4541 l = rettv->vval.v_list; | |
4542 if (getcurpos) | |
4543 fp = &curwin->w_cursor; | |
4544 else | |
4545 fp = var2fpos(&argvars[0], TRUE, &fnum); | |
4546 if (fnum != -1) | |
4547 list_append_number(l, (varnumber_T)fnum); | |
4548 else | |
4549 list_append_number(l, (varnumber_T)0); | |
4550 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum | |
4551 : (varnumber_T)0); | |
4552 list_append_number(l, (fp != NULL) | |
4553 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) | |
4554 : (varnumber_T)0); | |
4555 list_append_number(l, | |
4556 #ifdef FEAT_VIRTUALEDIT | |
4557 (fp != NULL) ? (varnumber_T)fp->coladd : | |
4558 #endif | |
4559 (varnumber_T)0); | |
4560 if (getcurpos) | |
4561 { | |
4562 update_curswant(); | |
4563 list_append_number(l, curwin->w_curswant == MAXCOL ? | |
4564 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); | |
4565 } | |
4566 } | |
4567 else | |
4568 rettv->vval.v_number = FALSE; | |
4569 } | |
4570 | |
4571 | |
4572 /* | |
4573 * "getcurpos()" function | |
4574 */ | |
4575 static void | |
4576 f_getcurpos(typval_T *argvars, typval_T *rettv) | |
4577 { | |
4578 getpos_both(argvars, rettv, TRUE); | |
4579 } | |
4580 | |
4581 /* | |
4582 * "getpos(string)" function | |
4583 */ | |
4584 static void | |
4585 f_getpos(typval_T *argvars, typval_T *rettv) | |
4586 { | |
4587 getpos_both(argvars, rettv, FALSE); | |
4588 } | |
4589 | |
4590 /* | |
4591 * "getqflist()" and "getloclist()" functions | |
4592 */ | |
4593 static void | |
4594 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
4595 { | |
4596 #ifdef FEAT_QUICKFIX | |
4597 win_T *wp; | |
4598 #endif | |
4599 | |
4600 #ifdef FEAT_QUICKFIX | |
4601 if (rettv_list_alloc(rettv) == OK) | |
4602 { | |
4603 wp = NULL; | |
4604 if (argvars[0].v_type != VAR_UNKNOWN) /* getloclist() */ | |
4605 { | |
4606 wp = find_win_by_nr(&argvars[0], NULL); | |
4607 if (wp == NULL) | |
4608 return; | |
4609 } | |
4610 | |
4611 (void)get_errorlist(wp, rettv->vval.v_list); | |
4612 } | |
4613 #endif | |
4614 } | |
4615 | |
4616 /* | |
4617 * "getreg()" function | |
4618 */ | |
4619 static void | |
4620 f_getreg(typval_T *argvars, typval_T *rettv) | |
4621 { | |
4622 char_u *strregname; | |
4623 int regname; | |
4624 int arg2 = FALSE; | |
4625 int return_list = FALSE; | |
4626 int error = FALSE; | |
4627 | |
4628 if (argvars[0].v_type != VAR_UNKNOWN) | |
4629 { | |
4630 strregname = get_tv_string_chk(&argvars[0]); | |
4631 error = strregname == NULL; | |
4632 if (argvars[1].v_type != VAR_UNKNOWN) | |
4633 { | |
4634 arg2 = (int)get_tv_number_chk(&argvars[1], &error); | |
4635 if (!error && argvars[2].v_type != VAR_UNKNOWN) | |
4636 return_list = (int)get_tv_number_chk(&argvars[2], &error); | |
4637 } | |
4638 } | |
4639 else | |
4640 strregname = get_vim_var_str(VV_REG); | |
4641 | |
4642 if (error) | |
4643 return; | |
4644 | |
4645 regname = (strregname == NULL ? '"' : *strregname); | |
4646 if (regname == 0) | |
4647 regname = '"'; | |
4648 | |
4649 if (return_list) | |
4650 { | |
4651 rettv->v_type = VAR_LIST; | |
4652 rettv->vval.v_list = (list_T *)get_reg_contents(regname, | |
4653 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST); | |
4654 if (rettv->vval.v_list == NULL) | |
4655 (void)rettv_list_alloc(rettv); | |
4656 else | |
4657 ++rettv->vval.v_list->lv_refcount; | |
4658 } | |
4659 else | |
4660 { | |
4661 rettv->v_type = VAR_STRING; | |
4662 rettv->vval.v_string = get_reg_contents(regname, | |
4663 arg2 ? GREG_EXPR_SRC : 0); | |
4664 } | |
4665 } | |
4666 | |
4667 /* | |
4668 * "getregtype()" function | |
4669 */ | |
4670 static void | |
4671 f_getregtype(typval_T *argvars, typval_T *rettv) | |
4672 { | |
4673 char_u *strregname; | |
4674 int regname; | |
4675 char_u buf[NUMBUFLEN + 2]; | |
4676 long reglen = 0; | |
4677 | |
4678 if (argvars[0].v_type != VAR_UNKNOWN) | |
4679 { | |
4680 strregname = get_tv_string_chk(&argvars[0]); | |
4681 if (strregname == NULL) /* type error; errmsg already given */ | |
4682 { | |
4683 rettv->v_type = VAR_STRING; | |
4684 rettv->vval.v_string = NULL; | |
4685 return; | |
4686 } | |
4687 } | |
4688 else | |
4689 /* Default to v:register */ | |
4690 strregname = get_vim_var_str(VV_REG); | |
4691 | |
4692 regname = (strregname == NULL ? '"' : *strregname); | |
4693 if (regname == 0) | |
4694 regname = '"'; | |
4695 | |
4696 buf[0] = NUL; | |
4697 buf[1] = NUL; | |
4698 switch (get_reg_type(regname, ®len)) | |
4699 { | |
4700 case MLINE: buf[0] = 'V'; break; | |
4701 case MCHAR: buf[0] = 'v'; break; | |
4702 case MBLOCK: | |
4703 buf[0] = Ctrl_V; | |
4704 sprintf((char *)buf + 1, "%ld", reglen + 1); | |
4705 break; | |
4706 } | |
4707 rettv->v_type = VAR_STRING; | |
4708 rettv->vval.v_string = vim_strsave(buf); | |
4709 } | |
4710 | |
4711 /* | |
4712 * "gettabvar()" function | |
4713 */ | |
4714 static void | |
4715 f_gettabvar(typval_T *argvars, typval_T *rettv) | |
4716 { | |
4717 win_T *oldcurwin; | |
4718 tabpage_T *tp, *oldtabpage; | |
4719 dictitem_T *v; | |
4720 char_u *varname; | |
4721 int done = FALSE; | |
4722 | |
4723 rettv->v_type = VAR_STRING; | |
4724 rettv->vval.v_string = NULL; | |
4725 | |
4726 varname = get_tv_string_chk(&argvars[1]); | |
4727 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
4728 if (tp != NULL && varname != NULL) | |
4729 { | |
4730 /* Set tp to be our tabpage, temporarily. Also set the window to the | |
4731 * first window in the tabpage, otherwise the window is not valid. */ | |
4732 if (switch_win(&oldcurwin, &oldtabpage, | |
4733 tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE) | |
4734 == OK) | |
4735 { | |
4736 /* look up the variable */ | |
4737 /* Let gettabvar({nr}, "") return the "t:" dictionary. */ | |
4738 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); | |
4739 if (v != NULL) | |
4740 { | |
4741 copy_tv(&v->di_tv, rettv); | |
4742 done = TRUE; | |
4743 } | |
4744 } | |
4745 | |
4746 /* restore previous notion of curwin */ | |
4747 restore_win(oldcurwin, oldtabpage, TRUE); | |
4748 } | |
4749 | |
4750 if (!done && argvars[2].v_type != VAR_UNKNOWN) | |
4751 copy_tv(&argvars[2], rettv); | |
4752 } | |
4753 | |
4754 /* | |
4755 * "gettabwinvar()" function | |
4756 */ | |
4757 static void | |
4758 f_gettabwinvar(typval_T *argvars, typval_T *rettv) | |
4759 { | |
4760 getwinvar(argvars, rettv, 1); | |
4761 } | |
4762 | |
4763 /* | |
4764 * "getwinposx()" function | |
4765 */ | |
4766 static void | |
4767 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) | |
4768 { | |
4769 rettv->vval.v_number = -1; | |
4770 #ifdef FEAT_GUI | |
4771 if (gui.in_use) | |
4772 { | |
4773 int x, y; | |
4774 | |
4775 if (gui_mch_get_winpos(&x, &y) == OK) | |
4776 rettv->vval.v_number = x; | |
4777 } | |
4778 #endif | |
4779 } | |
4780 | |
4781 /* | |
4782 * "win_findbuf()" function | |
4783 */ | |
4784 static void | |
4785 f_win_findbuf(typval_T *argvars, typval_T *rettv) | |
4786 { | |
4787 if (rettv_list_alloc(rettv) != FAIL) | |
4788 win_findbuf(argvars, rettv->vval.v_list); | |
4789 } | |
4790 | |
4791 /* | |
4792 * "win_getid()" function | |
4793 */ | |
4794 static void | |
4795 f_win_getid(typval_T *argvars, typval_T *rettv) | |
4796 { | |
4797 rettv->vval.v_number = win_getid(argvars); | |
4798 } | |
4799 | |
4800 /* | |
4801 * "win_gotoid()" function | |
4802 */ | |
4803 static void | |
4804 f_win_gotoid(typval_T *argvars, typval_T *rettv) | |
4805 { | |
4806 rettv->vval.v_number = win_gotoid(argvars); | |
4807 } | |
4808 | |
4809 /* | |
4810 * "win_id2tabwin()" function | |
4811 */ | |
4812 static void | |
4813 f_win_id2tabwin(typval_T *argvars, typval_T *rettv) | |
4814 { | |
4815 if (rettv_list_alloc(rettv) != FAIL) | |
4816 win_id2tabwin(argvars, rettv->vval.v_list); | |
4817 } | |
4818 | |
4819 /* | |
4820 * "win_id2win()" function | |
4821 */ | |
4822 static void | |
4823 f_win_id2win(typval_T *argvars, typval_T *rettv) | |
4824 { | |
4825 rettv->vval.v_number = win_id2win(argvars); | |
4826 } | |
4827 | |
4828 /* | |
4829 * "getwinposy()" function | |
4830 */ | |
4831 static void | |
4832 f_getwinposy(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 = y; | |
4842 } | |
4843 #endif | |
4844 } | |
4845 | |
4846 /* | |
4847 * "getwinvar()" function | |
4848 */ | |
4849 static void | |
4850 f_getwinvar(typval_T *argvars, typval_T *rettv) | |
4851 { | |
4852 getwinvar(argvars, rettv, 0); | |
4853 } | |
4854 | |
4855 /* | |
4856 * "glob()" function | |
4857 */ | |
4858 static void | |
4859 f_glob(typval_T *argvars, typval_T *rettv) | |
4860 { | |
4861 int options = WILD_SILENT|WILD_USE_NL; | |
4862 expand_T xpc; | |
4863 int error = FALSE; | |
4864 | |
4865 /* When the optional second argument is non-zero, don't remove matches | |
4866 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ | |
4867 rettv->v_type = VAR_STRING; | |
4868 if (argvars[1].v_type != VAR_UNKNOWN) | |
4869 { | |
4870 if (get_tv_number_chk(&argvars[1], &error)) | |
4871 options |= WILD_KEEP_ALL; | |
4872 if (argvars[2].v_type != VAR_UNKNOWN) | |
4873 { | |
4874 if (get_tv_number_chk(&argvars[2], &error)) | |
4875 { | |
4876 rettv->v_type = VAR_LIST; | |
4877 rettv->vval.v_list = NULL; | |
4878 } | |
4879 if (argvars[3].v_type != VAR_UNKNOWN | |
4880 && get_tv_number_chk(&argvars[3], &error)) | |
4881 options |= WILD_ALLLINKS; | |
4882 } | |
4883 } | |
4884 if (!error) | |
4885 { | |
4886 ExpandInit(&xpc); | |
4887 xpc.xp_context = EXPAND_FILES; | |
4888 if (p_wic) | |
4889 options += WILD_ICASE; | |
4890 if (rettv->v_type == VAR_STRING) | |
4891 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]), | |
4892 NULL, options, WILD_ALL); | |
4893 else if (rettv_list_alloc(rettv) != FAIL) | |
4894 { | |
4895 int i; | |
4896 | |
4897 ExpandOne(&xpc, get_tv_string(&argvars[0]), | |
4898 NULL, options, WILD_ALL_KEEP); | |
4899 for (i = 0; i < xpc.xp_numfiles; i++) | |
4900 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); | |
4901 | |
4902 ExpandCleanup(&xpc); | |
4903 } | |
4904 } | |
4905 else | |
4906 rettv->vval.v_string = NULL; | |
4907 } | |
4908 | |
4909 /* | |
4910 * "globpath()" function | |
4911 */ | |
4912 static void | |
4913 f_globpath(typval_T *argvars, typval_T *rettv) | |
4914 { | |
4915 int flags = 0; | |
4916 char_u buf1[NUMBUFLEN]; | |
4917 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1); | |
4918 int error = FALSE; | |
4919 garray_T ga; | |
4920 int i; | |
4921 | |
4922 /* When the optional second argument is non-zero, don't remove matches | |
4923 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ | |
4924 rettv->v_type = VAR_STRING; | |
4925 if (argvars[2].v_type != VAR_UNKNOWN) | |
4926 { | |
4927 if (get_tv_number_chk(&argvars[2], &error)) | |
4928 flags |= WILD_KEEP_ALL; | |
4929 if (argvars[3].v_type != VAR_UNKNOWN) | |
4930 { | |
4931 if (get_tv_number_chk(&argvars[3], &error)) | |
4932 { | |
4933 rettv->v_type = VAR_LIST; | |
4934 rettv->vval.v_list = NULL; | |
4935 } | |
4936 if (argvars[4].v_type != VAR_UNKNOWN | |
4937 && get_tv_number_chk(&argvars[4], &error)) | |
4938 flags |= WILD_ALLLINKS; | |
4939 } | |
4940 } | |
4941 if (file != NULL && !error) | |
4942 { | |
4943 ga_init2(&ga, (int)sizeof(char_u *), 10); | |
4944 globpath(get_tv_string(&argvars[0]), file, &ga, flags); | |
4945 if (rettv->v_type == VAR_STRING) | |
4946 rettv->vval.v_string = ga_concat_strings(&ga, "\n"); | |
4947 else if (rettv_list_alloc(rettv) != FAIL) | |
4948 for (i = 0; i < ga.ga_len; ++i) | |
4949 list_append_string(rettv->vval.v_list, | |
4950 ((char_u **)(ga.ga_data))[i], -1); | |
4951 ga_clear_strings(&ga); | |
4952 } | |
4953 else | |
4954 rettv->vval.v_string = NULL; | |
4955 } | |
4956 | |
4957 /* | |
4958 * "glob2regpat()" function | |
4959 */ | |
4960 static void | |
4961 f_glob2regpat(typval_T *argvars, typval_T *rettv) | |
4962 { | |
4963 char_u *pat = get_tv_string_chk(&argvars[0]); | |
4964 | |
4965 rettv->v_type = VAR_STRING; | |
4966 rettv->vval.v_string = (pat == NULL) | |
4967 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE); | |
4968 } | |
4969 | |
4970 /* for VIM_VERSION_ defines */ | |
4971 #include "version.h" | |
4972 | |
4973 /* | |
4974 * "has()" function | |
4975 */ | |
4976 static void | |
4977 f_has(typval_T *argvars, typval_T *rettv) | |
4978 { | |
4979 int i; | |
4980 char_u *name; | |
4981 int n = FALSE; | |
4982 static char *(has_list[]) = | |
4983 { | |
4984 #ifdef AMIGA | |
4985 "amiga", | |
4986 # ifdef FEAT_ARP | |
4987 "arp", | |
4988 # endif | |
4989 #endif | |
4990 #ifdef __BEOS__ | |
4991 "beos", | |
4992 #endif | |
4993 #ifdef MACOS | |
4994 "mac", | |
4995 #endif | |
4996 #if defined(MACOS_X_UNIX) | |
4997 "macunix", /* built with 'darwin' enabled */ | |
4998 #endif | |
4999 #if defined(__APPLE__) && __APPLE__ == 1 | |
5000 "osx", /* built with or without 'darwin' enabled */ | |
5001 #endif | |
5002 #ifdef __QNX__ | |
5003 "qnx", | |
5004 #endif | |
5005 #ifdef UNIX | |
5006 "unix", | |
5007 #endif | |
5008 #ifdef VMS | |
5009 "vms", | |
5010 #endif | |
5011 #ifdef WIN32 | |
5012 "win32", | |
5013 #endif | |
5014 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__)) | |
5015 "win32unix", | |
5016 #endif | |
5017 #if defined(WIN64) || defined(_WIN64) | |
5018 "win64", | |
5019 #endif | |
5020 #ifdef EBCDIC | |
5021 "ebcdic", | |
5022 #endif | |
5023 #ifndef CASE_INSENSITIVE_FILENAME | |
5024 "fname_case", | |
5025 #endif | |
5026 #ifdef HAVE_ACL | |
5027 "acl", | |
5028 #endif | |
5029 #ifdef FEAT_ARABIC | |
5030 "arabic", | |
5031 #endif | |
5032 #ifdef FEAT_AUTOCMD | |
5033 "autocmd", | |
5034 #endif | |
5035 #ifdef FEAT_BEVAL | |
5036 "balloon_eval", | |
5037 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */ | |
5038 "balloon_multiline", | |
5039 # endif | |
5040 #endif | |
5041 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS) | |
5042 "builtin_terms", | |
5043 # ifdef ALL_BUILTIN_TCAPS | |
5044 "all_builtin_terms", | |
5045 # endif | |
5046 #endif | |
5047 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \ | |
5048 || defined(FEAT_GUI_W32) \ | |
5049 || defined(FEAT_GUI_MOTIF)) | |
5050 "browsefilter", | |
5051 #endif | |
5052 #ifdef FEAT_BYTEOFF | |
5053 "byte_offset", | |
5054 #endif | |
5055 #ifdef FEAT_JOB_CHANNEL | |
5056 "channel", | |
5057 #endif | |
5058 #ifdef FEAT_CINDENT | |
5059 "cindent", | |
5060 #endif | |
5061 #ifdef FEAT_CLIENTSERVER | |
5062 "clientserver", | |
5063 #endif | |
5064 #ifdef FEAT_CLIPBOARD | |
5065 "clipboard", | |
5066 #endif | |
5067 #ifdef FEAT_CMDL_COMPL | |
5068 "cmdline_compl", | |
5069 #endif | |
5070 #ifdef FEAT_CMDHIST | |
5071 "cmdline_hist", | |
5072 #endif | |
5073 #ifdef FEAT_COMMENTS | |
5074 "comments", | |
5075 #endif | |
5076 #ifdef FEAT_CONCEAL | |
5077 "conceal", | |
5078 #endif | |
5079 #ifdef FEAT_CRYPT | |
5080 "cryptv", | |
5081 "crypt-blowfish", | |
5082 "crypt-blowfish2", | |
5083 #endif | |
5084 #ifdef FEAT_CSCOPE | |
5085 "cscope", | |
5086 #endif | |
5087 #ifdef FEAT_CURSORBIND | |
5088 "cursorbind", | |
5089 #endif | |
5090 #ifdef CURSOR_SHAPE | |
5091 "cursorshape", | |
5092 #endif | |
5093 #ifdef DEBUG | |
5094 "debug", | |
5095 #endif | |
5096 #ifdef FEAT_CON_DIALOG | |
5097 "dialog_con", | |
5098 #endif | |
5099 #ifdef FEAT_GUI_DIALOG | |
5100 "dialog_gui", | |
5101 #endif | |
5102 #ifdef FEAT_DIFF | |
5103 "diff", | |
5104 #endif | |
5105 #ifdef FEAT_DIGRAPHS | |
5106 "digraphs", | |
5107 #endif | |
5108 #ifdef FEAT_DIRECTX | |
5109 "directx", | |
5110 #endif | |
5111 #ifdef FEAT_DND | |
5112 "dnd", | |
5113 #endif | |
5114 #ifdef FEAT_EMACS_TAGS | |
5115 "emacs_tags", | |
5116 #endif | |
5117 "eval", /* always present, of course! */ | |
5118 "ex_extra", /* graduated feature */ | |
5119 #ifdef FEAT_SEARCH_EXTRA | |
5120 "extra_search", | |
5121 #endif | |
5122 #ifdef FEAT_FKMAP | |
5123 "farsi", | |
5124 #endif | |
5125 #ifdef FEAT_SEARCHPATH | |
5126 "file_in_path", | |
5127 #endif | |
5128 #ifdef FEAT_FILTERPIPE | |
5129 "filterpipe", | |
5130 #endif | |
5131 #ifdef FEAT_FIND_ID | |
5132 "find_in_path", | |
5133 #endif | |
5134 #ifdef FEAT_FLOAT | |
5135 "float", | |
5136 #endif | |
5137 #ifdef FEAT_FOLDING | |
5138 "folding", | |
5139 #endif | |
5140 #ifdef FEAT_FOOTER | |
5141 "footer", | |
5142 #endif | |
5143 #if !defined(USE_SYSTEM) && defined(UNIX) | |
5144 "fork", | |
5145 #endif | |
5146 #ifdef FEAT_GETTEXT | |
5147 "gettext", | |
5148 #endif | |
5149 #ifdef FEAT_GUI | |
5150 "gui", | |
5151 #endif | |
5152 #ifdef FEAT_GUI_ATHENA | |
5153 # ifdef FEAT_GUI_NEXTAW | |
5154 "gui_neXtaw", | |
5155 # else | |
5156 "gui_athena", | |
5157 # endif | |
5158 #endif | |
5159 #ifdef FEAT_GUI_GTK | |
5160 "gui_gtk", | |
5161 # ifdef USE_GTK3 | |
5162 "gui_gtk3", | |
5163 # else | |
5164 "gui_gtk2", | |
5165 # endif | |
5166 #endif | |
5167 #ifdef FEAT_GUI_GNOME | |
5168 "gui_gnome", | |
5169 #endif | |
5170 #ifdef FEAT_GUI_MAC | |
5171 "gui_mac", | |
5172 #endif | |
5173 #ifdef FEAT_GUI_MOTIF | |
5174 "gui_motif", | |
5175 #endif | |
5176 #ifdef FEAT_GUI_PHOTON | |
5177 "gui_photon", | |
5178 #endif | |
5179 #ifdef FEAT_GUI_W32 | |
5180 "gui_win32", | |
5181 #endif | |
5182 #ifdef FEAT_HANGULIN | |
5183 "hangul_input", | |
5184 #endif | |
5185 #if defined(HAVE_ICONV_H) && defined(USE_ICONV) | |
5186 "iconv", | |
5187 #endif | |
5188 #ifdef FEAT_INS_EXPAND | |
5189 "insert_expand", | |
5190 #endif | |
5191 #ifdef FEAT_JOB_CHANNEL | |
5192 "job", | |
5193 #endif | |
5194 #ifdef FEAT_JUMPLIST | |
5195 "jumplist", | |
5196 #endif | |
5197 #ifdef FEAT_KEYMAP | |
5198 "keymap", | |
5199 #endif | |
5200 #ifdef FEAT_LANGMAP | |
5201 "langmap", | |
5202 #endif | |
5203 #ifdef FEAT_LIBCALL | |
5204 "libcall", | |
5205 #endif | |
5206 #ifdef FEAT_LINEBREAK | |
5207 "linebreak", | |
5208 #endif | |
5209 #ifdef FEAT_LISP | |
5210 "lispindent", | |
5211 #endif | |
5212 #ifdef FEAT_LISTCMDS | |
5213 "listcmds", | |
5214 #endif | |
5215 #ifdef FEAT_LOCALMAP | |
5216 "localmap", | |
5217 #endif | |
5218 #ifdef FEAT_LUA | |
5219 # ifndef DYNAMIC_LUA | |
5220 "lua", | |
5221 # endif | |
5222 #endif | |
5223 #ifdef FEAT_MENU | |
5224 "menu", | |
5225 #endif | |
5226 #ifdef FEAT_SESSION | |
5227 "mksession", | |
5228 #endif | |
5229 #ifdef FEAT_MODIFY_FNAME | |
5230 "modify_fname", | |
5231 #endif | |
5232 #ifdef FEAT_MOUSE | |
5233 "mouse", | |
5234 #endif | |
5235 #ifdef FEAT_MOUSESHAPE | |
5236 "mouseshape", | |
5237 #endif | |
5238 #if defined(UNIX) || defined(VMS) | |
5239 # ifdef FEAT_MOUSE_DEC | |
5240 "mouse_dec", | |
5241 # endif | |
5242 # ifdef FEAT_MOUSE_GPM | |
5243 "mouse_gpm", | |
5244 # endif | |
5245 # ifdef FEAT_MOUSE_JSB | |
5246 "mouse_jsbterm", | |
5247 # endif | |
5248 # ifdef FEAT_MOUSE_NET | |
5249 "mouse_netterm", | |
5250 # endif | |
5251 # ifdef FEAT_MOUSE_PTERM | |
5252 "mouse_pterm", | |
5253 # endif | |
5254 # ifdef FEAT_MOUSE_SGR | |
5255 "mouse_sgr", | |
5256 # endif | |
5257 # ifdef FEAT_SYSMOUSE | |
5258 "mouse_sysmouse", | |
5259 # endif | |
5260 # ifdef FEAT_MOUSE_URXVT | |
5261 "mouse_urxvt", | |
5262 # endif | |
5263 # ifdef FEAT_MOUSE_XTERM | |
5264 "mouse_xterm", | |
5265 # endif | |
5266 #endif | |
5267 #ifdef FEAT_MBYTE | |
5268 "multi_byte", | |
5269 #endif | |
5270 #ifdef FEAT_MBYTE_IME | |
5271 "multi_byte_ime", | |
5272 #endif | |
5273 #ifdef FEAT_MULTI_LANG | |
5274 "multi_lang", | |
5275 #endif | |
5276 #ifdef FEAT_MZSCHEME | |
5277 #ifndef DYNAMIC_MZSCHEME | |
5278 "mzscheme", | |
5279 #endif | |
5280 #endif | |
5281 #ifdef FEAT_NUM64 | |
5282 "num64", | |
5283 #endif | |
5284 #ifdef FEAT_OLE | |
5285 "ole", | |
5286 #endif | |
5287 "packages", | |
5288 #ifdef FEAT_PATH_EXTRA | |
5289 "path_extra", | |
5290 #endif | |
5291 #ifdef FEAT_PERL | |
5292 #ifndef DYNAMIC_PERL | |
5293 "perl", | |
5294 #endif | |
5295 #endif | |
5296 #ifdef FEAT_PERSISTENT_UNDO | |
5297 "persistent_undo", | |
5298 #endif | |
5299 #ifdef FEAT_PYTHON | |
5300 #ifndef DYNAMIC_PYTHON | |
5301 "python", | |
5302 #endif | |
5303 #endif | |
5304 #ifdef FEAT_PYTHON3 | |
5305 #ifndef DYNAMIC_PYTHON3 | |
5306 "python3", | |
5307 #endif | |
5308 #endif | |
5309 #ifdef FEAT_POSTSCRIPT | |
5310 "postscript", | |
5311 #endif | |
5312 #ifdef FEAT_PRINTER | |
5313 "printer", | |
5314 #endif | |
5315 #ifdef FEAT_PROFILE | |
5316 "profile", | |
5317 #endif | |
5318 #ifdef FEAT_RELTIME | |
5319 "reltime", | |
5320 #endif | |
5321 #ifdef FEAT_QUICKFIX | |
5322 "quickfix", | |
5323 #endif | |
5324 #ifdef FEAT_RIGHTLEFT | |
5325 "rightleft", | |
5326 #endif | |
5327 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY) | |
5328 "ruby", | |
5329 #endif | |
5330 #ifdef FEAT_SCROLLBIND | |
5331 "scrollbind", | |
5332 #endif | |
5333 #ifdef FEAT_CMDL_INFO | |
5334 "showcmd", | |
5335 "cmdline_info", | |
5336 #endif | |
5337 #ifdef FEAT_SIGNS | |
5338 "signs", | |
5339 #endif | |
5340 #ifdef FEAT_SMARTINDENT | |
5341 "smartindent", | |
5342 #endif | |
5343 #ifdef STARTUPTIME | |
5344 "startuptime", | |
5345 #endif | |
5346 #ifdef FEAT_STL_OPT | |
5347 "statusline", | |
5348 #endif | |
5349 #ifdef FEAT_SUN_WORKSHOP | |
5350 "sun_workshop", | |
5351 #endif | |
5352 #ifdef FEAT_NETBEANS_INTG | |
5353 "netbeans_intg", | |
5354 #endif | |
5355 #ifdef FEAT_SPELL | |
5356 "spell", | |
5357 #endif | |
5358 #ifdef FEAT_SYN_HL | |
5359 "syntax", | |
5360 #endif | |
5361 #if defined(USE_SYSTEM) || !defined(UNIX) | |
5362 "system", | |
5363 #endif | |
5364 #ifdef FEAT_TAG_BINS | |
5365 "tag_binary", | |
5366 #endif | |
5367 #ifdef FEAT_TAG_OLDSTATIC | |
5368 "tag_old_static", | |
5369 #endif | |
5370 #ifdef FEAT_TAG_ANYWHITE | |
5371 "tag_any_white", | |
5372 #endif | |
5373 #ifdef FEAT_TCL | |
5374 # ifndef DYNAMIC_TCL | |
5375 "tcl", | |
5376 # endif | |
5377 #endif | |
5378 #ifdef FEAT_TERMGUICOLORS | |
5379 "termguicolors", | |
5380 #endif | |
5381 #ifdef TERMINFO | |
5382 "terminfo", | |
5383 #endif | |
5384 #ifdef FEAT_TERMRESPONSE | |
5385 "termresponse", | |
5386 #endif | |
5387 #ifdef FEAT_TEXTOBJ | |
5388 "textobjects", | |
5389 #endif | |
5390 #ifdef HAVE_TGETENT | |
5391 "tgetent", | |
5392 #endif | |
5393 #ifdef FEAT_TIMERS | |
5394 "timers", | |
5395 #endif | |
5396 #ifdef FEAT_TITLE | |
5397 "title", | |
5398 #endif | |
5399 #ifdef FEAT_TOOLBAR | |
5400 "toolbar", | |
5401 #endif | |
5402 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) | |
5403 "unnamedplus", | |
5404 #endif | |
5405 #ifdef FEAT_USR_CMDS | |
5406 "user-commands", /* was accidentally included in 5.4 */ | |
5407 "user_commands", | |
5408 #endif | |
5409 #ifdef FEAT_VIMINFO | |
5410 "viminfo", | |
5411 #endif | |
5412 #ifdef FEAT_WINDOWS | |
5413 "vertsplit", | |
5414 #endif | |
5415 #ifdef FEAT_VIRTUALEDIT | |
5416 "virtualedit", | |
5417 #endif | |
5418 "visual", | |
5419 #ifdef FEAT_VISUALEXTRA | |
5420 "visualextra", | |
5421 #endif | |
5422 #ifdef FEAT_VREPLACE | |
5423 "vreplace", | |
5424 #endif | |
5425 #ifdef FEAT_WILDIGN | |
5426 "wildignore", | |
5427 #endif | |
5428 #ifdef FEAT_WILDMENU | |
5429 "wildmenu", | |
5430 #endif | |
5431 #ifdef FEAT_WINDOWS | |
5432 "windows", | |
5433 #endif | |
5434 #ifdef FEAT_WAK | |
5435 "winaltkeys", | |
5436 #endif | |
5437 #ifdef FEAT_WRITEBACKUP | |
5438 "writebackup", | |
5439 #endif | |
5440 #ifdef FEAT_XIM | |
5441 "xim", | |
5442 #endif | |
5443 #ifdef FEAT_XFONTSET | |
5444 "xfontset", | |
5445 #endif | |
5446 #ifdef FEAT_XPM_W32 | |
5447 "xpm", | |
5448 "xpm_w32", /* for backward compatibility */ | |
5449 #else | |
5450 # if defined(HAVE_XPM) | |
5451 "xpm", | |
5452 # endif | |
5453 #endif | |
5454 #ifdef USE_XSMP | |
5455 "xsmp", | |
5456 #endif | |
5457 #ifdef USE_XSMP_INTERACT | |
5458 "xsmp_interact", | |
5459 #endif | |
5460 #ifdef FEAT_XCLIPBOARD | |
5461 "xterm_clipboard", | |
5462 #endif | |
5463 #ifdef FEAT_XTERM_SAVE | |
5464 "xterm_save", | |
5465 #endif | |
5466 #if defined(UNIX) && defined(FEAT_X11) | |
5467 "X11", | |
5468 #endif | |
5469 NULL | |
5470 }; | |
5471 | |
5472 name = get_tv_string(&argvars[0]); | |
5473 for (i = 0; has_list[i] != NULL; ++i) | |
5474 if (STRICMP(name, has_list[i]) == 0) | |
5475 { | |
5476 n = TRUE; | |
5477 break; | |
5478 } | |
5479 | |
5480 if (n == FALSE) | |
5481 { | |
5482 if (STRNICMP(name, "patch", 5) == 0) | |
5483 { | |
5484 if (name[5] == '-' | |
5485 && STRLEN(name) >= 11 | |
5486 && vim_isdigit(name[6]) | |
5487 && vim_isdigit(name[8]) | |
5488 && vim_isdigit(name[10])) | |
5489 { | |
5490 int major = atoi((char *)name + 6); | |
5491 int minor = atoi((char *)name + 8); | |
5492 | |
5493 /* Expect "patch-9.9.01234". */ | |
5494 n = (major < VIM_VERSION_MAJOR | |
5495 || (major == VIM_VERSION_MAJOR | |
5496 && (minor < VIM_VERSION_MINOR | |
5497 || (minor == VIM_VERSION_MINOR | |
5498 && has_patch(atoi((char *)name + 10)))))); | |
5499 } | |
5500 else | |
5501 n = has_patch(atoi((char *)name + 5)); | |
5502 } | |
5503 else if (STRICMP(name, "vim_starting") == 0) | |
5504 n = (starting != 0); | |
5505 #ifdef FEAT_MBYTE | |
5506 else if (STRICMP(name, "multi_byte_encoding") == 0) | |
5507 n = has_mbyte; | |
5508 #endif | |
5509 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32) | |
5510 else if (STRICMP(name, "balloon_multiline") == 0) | |
5511 n = multiline_balloon_available(); | |
5512 #endif | |
5513 #ifdef DYNAMIC_TCL | |
5514 else if (STRICMP(name, "tcl") == 0) | |
5515 n = tcl_enabled(FALSE); | |
5516 #endif | |
5517 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV) | |
5518 else if (STRICMP(name, "iconv") == 0) | |
5519 n = iconv_enabled(FALSE); | |
5520 #endif | |
5521 #ifdef DYNAMIC_LUA | |
5522 else if (STRICMP(name, "lua") == 0) | |
5523 n = lua_enabled(FALSE); | |
5524 #endif | |
5525 #ifdef DYNAMIC_MZSCHEME | |
5526 else if (STRICMP(name, "mzscheme") == 0) | |
5527 n = mzscheme_enabled(FALSE); | |
5528 #endif | |
5529 #ifdef DYNAMIC_RUBY | |
5530 else if (STRICMP(name, "ruby") == 0) | |
5531 n = ruby_enabled(FALSE); | |
5532 #endif | |
5533 #ifdef FEAT_PYTHON | |
5534 #ifdef DYNAMIC_PYTHON | |
5535 else if (STRICMP(name, "python") == 0) | |
5536 n = python_enabled(FALSE); | |
5537 #endif | |
5538 #endif | |
5539 #ifdef FEAT_PYTHON3 | |
5540 #ifdef DYNAMIC_PYTHON3 | |
5541 else if (STRICMP(name, "python3") == 0) | |
5542 n = python3_enabled(FALSE); | |
5543 #endif | |
5544 #endif | |
5545 #ifdef DYNAMIC_PERL | |
5546 else if (STRICMP(name, "perl") == 0) | |
5547 n = perl_enabled(FALSE); | |
5548 #endif | |
5549 #ifdef FEAT_GUI | |
5550 else if (STRICMP(name, "gui_running") == 0) | |
5551 n = (gui.in_use || gui.starting); | |
5552 # ifdef FEAT_GUI_W32 | |
5553 else if (STRICMP(name, "gui_win32s") == 0) | |
5554 n = gui_is_win32s(); | |
5555 # endif | |
5556 # ifdef FEAT_BROWSE | |
5557 else if (STRICMP(name, "browse") == 0) | |
5558 n = gui.in_use; /* gui_mch_browse() works when GUI is running */ | |
5559 # endif | |
5560 #endif | |
5561 #ifdef FEAT_SYN_HL | |
5562 else if (STRICMP(name, "syntax_items") == 0) | |
5563 n = syntax_present(curwin); | |
5564 #endif | |
5565 #if defined(WIN3264) | |
5566 else if (STRICMP(name, "win95") == 0) | |
5567 n = mch_windows95(); | |
5568 #endif | |
5569 #ifdef FEAT_NETBEANS_INTG | |
5570 else if (STRICMP(name, "netbeans_enabled") == 0) | |
5571 n = netbeans_active(); | |
5572 #endif | |
5573 } | |
5574 | |
5575 rettv->vval.v_number = n; | |
5576 } | |
5577 | |
5578 /* | |
5579 * "has_key()" function | |
5580 */ | |
5581 static void | |
5582 f_has_key(typval_T *argvars, typval_T *rettv) | |
5583 { | |
5584 if (argvars[0].v_type != VAR_DICT) | |
5585 { | |
5586 EMSG(_(e_dictreq)); | |
5587 return; | |
5588 } | |
5589 if (argvars[0].vval.v_dict == NULL) | |
5590 return; | |
5591 | |
5592 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, | |
5593 get_tv_string(&argvars[1]), -1) != NULL; | |
5594 } | |
5595 | |
5596 /* | |
5597 * "haslocaldir()" function | |
5598 */ | |
5599 static void | |
5600 f_haslocaldir(typval_T *argvars, typval_T *rettv) | |
5601 { | |
5602 win_T *wp = NULL; | |
5603 | |
5604 wp = find_tabwin(&argvars[0], &argvars[1]); | |
5605 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL); | |
5606 } | |
5607 | |
5608 /* | |
5609 * "hasmapto()" function | |
5610 */ | |
5611 static void | |
5612 f_hasmapto(typval_T *argvars, typval_T *rettv) | |
5613 { | |
5614 char_u *name; | |
5615 char_u *mode; | |
5616 char_u buf[NUMBUFLEN]; | |
5617 int abbr = FALSE; | |
5618 | |
5619 name = get_tv_string(&argvars[0]); | |
5620 if (argvars[1].v_type == VAR_UNKNOWN) | |
5621 mode = (char_u *)"nvo"; | |
5622 else | |
5623 { | |
5624 mode = get_tv_string_buf(&argvars[1], buf); | |
5625 if (argvars[2].v_type != VAR_UNKNOWN) | |
5626 abbr = (int)get_tv_number(&argvars[2]); | |
5627 } | |
5628 | |
5629 if (map_to_exists(name, mode, abbr)) | |
5630 rettv->vval.v_number = TRUE; | |
5631 else | |
5632 rettv->vval.v_number = FALSE; | |
5633 } | |
5634 | |
5635 /* | |
5636 * "histadd()" function | |
5637 */ | |
5638 static void | |
5639 f_histadd(typval_T *argvars UNUSED, typval_T *rettv) | |
5640 { | |
5641 #ifdef FEAT_CMDHIST | |
5642 int histype; | |
5643 char_u *str; | |
5644 char_u buf[NUMBUFLEN]; | |
5645 #endif | |
5646 | |
5647 rettv->vval.v_number = FALSE; | |
5648 if (check_restricted() || check_secure()) | |
5649 return; | |
5650 #ifdef FEAT_CMDHIST | |
5651 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ | |
5652 histype = str != NULL ? get_histtype(str) : -1; | |
5653 if (histype >= 0) | |
5654 { | |
5655 str = get_tv_string_buf(&argvars[1], buf); | |
5656 if (*str != NUL) | |
5657 { | |
5658 init_history(); | |
5659 add_to_history(histype, str, FALSE, NUL); | |
5660 rettv->vval.v_number = TRUE; | |
5661 return; | |
5662 } | |
5663 } | |
5664 #endif | |
5665 } | |
5666 | |
5667 /* | |
5668 * "histdel()" function | |
5669 */ | |
5670 static void | |
5671 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
5672 { | |
5673 #ifdef FEAT_CMDHIST | |
5674 int n; | |
5675 char_u buf[NUMBUFLEN]; | |
5676 char_u *str; | |
5677 | |
5678 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ | |
5679 if (str == NULL) | |
5680 n = 0; | |
5681 else if (argvars[1].v_type == VAR_UNKNOWN) | |
5682 /* only one argument: clear entire history */ | |
5683 n = clr_history(get_histtype(str)); | |
5684 else if (argvars[1].v_type == VAR_NUMBER) | |
5685 /* index given: remove that entry */ | |
5686 n = del_history_idx(get_histtype(str), | |
5687 (int)get_tv_number(&argvars[1])); | |
5688 else | |
5689 /* string given: remove all matching entries */ | |
5690 n = del_history_entry(get_histtype(str), | |
5691 get_tv_string_buf(&argvars[1], buf)); | |
5692 rettv->vval.v_number = n; | |
5693 #endif | |
5694 } | |
5695 | |
5696 /* | |
5697 * "histget()" function | |
5698 */ | |
5699 static void | |
5700 f_histget(typval_T *argvars UNUSED, typval_T *rettv) | |
5701 { | |
5702 #ifdef FEAT_CMDHIST | |
5703 int type; | |
5704 int idx; | |
5705 char_u *str; | |
5706 | |
5707 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ | |
5708 if (str == NULL) | |
5709 rettv->vval.v_string = NULL; | |
5710 else | |
5711 { | |
5712 type = get_histtype(str); | |
5713 if (argvars[1].v_type == VAR_UNKNOWN) | |
5714 idx = get_history_idx(type); | |
5715 else | |
5716 idx = (int)get_tv_number_chk(&argvars[1], NULL); | |
5717 /* -1 on type error */ | |
5718 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); | |
5719 } | |
5720 #else | |
5721 rettv->vval.v_string = NULL; | |
5722 #endif | |
5723 rettv->v_type = VAR_STRING; | |
5724 } | |
5725 | |
5726 /* | |
5727 * "histnr()" function | |
5728 */ | |
5729 static void | |
5730 f_histnr(typval_T *argvars UNUSED, typval_T *rettv) | |
5731 { | |
5732 int i; | |
5733 | |
5734 #ifdef FEAT_CMDHIST | |
5735 char_u *history = get_tv_string_chk(&argvars[0]); | |
5736 | |
5737 i = history == NULL ? HIST_CMD - 1 : get_histtype(history); | |
5738 if (i >= HIST_CMD && i < HIST_COUNT) | |
5739 i = get_history_idx(i); | |
5740 else | |
5741 #endif | |
5742 i = -1; | |
5743 rettv->vval.v_number = i; | |
5744 } | |
5745 | |
5746 /* | |
5747 * "highlightID(name)" function | |
5748 */ | |
5749 static void | |
5750 f_hlID(typval_T *argvars, typval_T *rettv) | |
5751 { | |
5752 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0])); | |
5753 } | |
5754 | |
5755 /* | |
5756 * "highlight_exists()" function | |
5757 */ | |
5758 static void | |
5759 f_hlexists(typval_T *argvars, typval_T *rettv) | |
5760 { | |
5761 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0])); | |
5762 } | |
5763 | |
5764 /* | |
5765 * "hostname()" function | |
5766 */ | |
5767 static void | |
5768 f_hostname(typval_T *argvars UNUSED, typval_T *rettv) | |
5769 { | |
5770 char_u hostname[256]; | |
5771 | |
5772 mch_get_host_name(hostname, 256); | |
5773 rettv->v_type = VAR_STRING; | |
5774 rettv->vval.v_string = vim_strsave(hostname); | |
5775 } | |
5776 | |
5777 /* | |
5778 * iconv() function | |
5779 */ | |
5780 static void | |
5781 f_iconv(typval_T *argvars UNUSED, typval_T *rettv) | |
5782 { | |
5783 #ifdef FEAT_MBYTE | |
5784 char_u buf1[NUMBUFLEN]; | |
5785 char_u buf2[NUMBUFLEN]; | |
5786 char_u *from, *to, *str; | |
5787 vimconv_T vimconv; | |
5788 #endif | |
5789 | |
5790 rettv->v_type = VAR_STRING; | |
5791 rettv->vval.v_string = NULL; | |
5792 | |
5793 #ifdef FEAT_MBYTE | |
5794 str = get_tv_string(&argvars[0]); | |
5795 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1))); | |
5796 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2))); | |
5797 vimconv.vc_type = CONV_NONE; | |
5798 convert_setup(&vimconv, from, to); | |
5799 | |
5800 /* If the encodings are equal, no conversion needed. */ | |
5801 if (vimconv.vc_type == CONV_NONE) | |
5802 rettv->vval.v_string = vim_strsave(str); | |
5803 else | |
5804 rettv->vval.v_string = string_convert(&vimconv, str, NULL); | |
5805 | |
5806 convert_setup(&vimconv, NULL, NULL); | |
5807 vim_free(from); | |
5808 vim_free(to); | |
5809 #endif | |
5810 } | |
5811 | |
5812 /* | |
5813 * "indent()" function | |
5814 */ | |
5815 static void | |
5816 f_indent(typval_T *argvars, typval_T *rettv) | |
5817 { | |
5818 linenr_T lnum; | |
5819 | |
5820 lnum = get_tv_lnum(argvars); | |
5821 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
5822 rettv->vval.v_number = get_indent_lnum(lnum); | |
5823 else | |
5824 rettv->vval.v_number = -1; | |
5825 } | |
5826 | |
5827 /* | |
5828 * "index()" function | |
5829 */ | |
5830 static void | |
5831 f_index(typval_T *argvars, typval_T *rettv) | |
5832 { | |
5833 list_T *l; | |
5834 listitem_T *item; | |
5835 long idx = 0; | |
5836 int ic = FALSE; | |
5837 | |
5838 rettv->vval.v_number = -1; | |
5839 if (argvars[0].v_type != VAR_LIST) | |
5840 { | |
5841 EMSG(_(e_listreq)); | |
5842 return; | |
5843 } | |
5844 l = argvars[0].vval.v_list; | |
5845 if (l != NULL) | |
5846 { | |
5847 item = l->lv_first; | |
5848 if (argvars[2].v_type != VAR_UNKNOWN) | |
5849 { | |
5850 int error = FALSE; | |
5851 | |
5852 /* Start at specified item. Use the cached index that list_find() | |
5853 * sets, so that a negative number also works. */ | |
5854 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error)); | |
5855 idx = l->lv_idx; | |
5856 if (argvars[3].v_type != VAR_UNKNOWN) | |
5857 ic = (int)get_tv_number_chk(&argvars[3], &error); | |
5858 if (error) | |
5859 item = NULL; | |
5860 } | |
5861 | |
5862 for ( ; item != NULL; item = item->li_next, ++idx) | |
5863 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE)) | |
5864 { | |
5865 rettv->vval.v_number = idx; | |
5866 break; | |
5867 } | |
5868 } | |
5869 } | |
5870 | |
5871 static int inputsecret_flag = 0; | |
5872 | |
5873 /* | |
5874 * "input()" function | |
5875 * Also handles inputsecret() when inputsecret is set. | |
5876 */ | |
5877 static void | |
5878 f_input(typval_T *argvars, typval_T *rettv) | |
5879 { | |
5880 get_user_input(argvars, rettv, FALSE, inputsecret_flag); | |
5881 } | |
5882 | |
5883 /* | |
5884 * "inputdialog()" function | |
5885 */ | |
5886 static void | |
5887 f_inputdialog(typval_T *argvars, typval_T *rettv) | |
5888 { | |
5889 #if defined(FEAT_GUI_TEXTDIALOG) | |
5890 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */ | |
5891 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) | |
5892 { | |
5893 char_u *message; | |
5894 char_u buf[NUMBUFLEN]; | |
5895 char_u *defstr = (char_u *)""; | |
5896 | |
5897 message = get_tv_string_chk(&argvars[0]); | |
5898 if (argvars[1].v_type != VAR_UNKNOWN | |
5899 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL) | |
5900 vim_strncpy(IObuff, defstr, IOSIZE - 1); | |
5901 else | |
5902 IObuff[0] = NUL; | |
5903 if (message != NULL && defstr != NULL | |
5904 && do_dialog(VIM_QUESTION, NULL, message, | |
5905 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1) | |
5906 rettv->vval.v_string = vim_strsave(IObuff); | |
5907 else | |
5908 { | |
5909 if (message != NULL && defstr != NULL | |
5910 && argvars[1].v_type != VAR_UNKNOWN | |
5911 && argvars[2].v_type != VAR_UNKNOWN) | |
5912 rettv->vval.v_string = vim_strsave( | |
5913 get_tv_string_buf(&argvars[2], buf)); | |
5914 else | |
5915 rettv->vval.v_string = NULL; | |
5916 } | |
5917 rettv->v_type = VAR_STRING; | |
5918 } | |
5919 else | |
5920 #endif | |
5921 get_user_input(argvars, rettv, TRUE, inputsecret_flag); | |
5922 } | |
5923 | |
5924 /* | |
5925 * "inputlist()" function | |
5926 */ | |
5927 static void | |
5928 f_inputlist(typval_T *argvars, typval_T *rettv) | |
5929 { | |
5930 listitem_T *li; | |
5931 int selected; | |
5932 int mouse_used; | |
5933 | |
5934 #ifdef NO_CONSOLE_INPUT | |
5935 /* While starting up, there is no place to enter text. */ | |
5936 if (no_console_input()) | |
5937 return; | |
5938 #endif | |
5939 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) | |
5940 { | |
5941 EMSG2(_(e_listarg), "inputlist()"); | |
5942 return; | |
5943 } | |
5944 | |
5945 msg_start(); | |
5946 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */ | |
5947 lines_left = Rows; /* avoid more prompt */ | |
5948 msg_scroll = TRUE; | |
5949 msg_clr_eos(); | |
5950 | |
5951 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) | |
5952 { | |
5953 msg_puts(get_tv_string(&li->li_tv)); | |
5954 msg_putchar('\n'); | |
5955 } | |
5956 | |
5957 /* Ask for choice. */ | |
5958 selected = prompt_for_number(&mouse_used); | |
5959 if (mouse_used) | |
5960 selected -= lines_left; | |
5961 | |
5962 rettv->vval.v_number = selected; | |
5963 } | |
5964 | |
5965 | |
5966 static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; | |
5967 | |
5968 /* | |
5969 * "inputrestore()" function | |
5970 */ | |
5971 static void | |
5972 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) | |
5973 { | |
5974 if (ga_userinput.ga_len > 0) | |
5975 { | |
5976 --ga_userinput.ga_len; | |
5977 restore_typeahead((tasave_T *)(ga_userinput.ga_data) | |
5978 + ga_userinput.ga_len); | |
5979 /* default return is zero == OK */ | |
5980 } | |
5981 else if (p_verbose > 1) | |
5982 { | |
5983 verb_msg((char_u *)_("called inputrestore() more often than inputsave()")); | |
5984 rettv->vval.v_number = 1; /* Failed */ | |
5985 } | |
5986 } | |
5987 | |
5988 /* | |
5989 * "inputsave()" function | |
5990 */ | |
5991 static void | |
5992 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv) | |
5993 { | |
5994 /* Add an entry to the stack of typeahead storage. */ | |
5995 if (ga_grow(&ga_userinput, 1) == OK) | |
5996 { | |
5997 save_typeahead((tasave_T *)(ga_userinput.ga_data) | |
5998 + ga_userinput.ga_len); | |
5999 ++ga_userinput.ga_len; | |
6000 /* default return is zero == OK */ | |
6001 } | |
6002 else | |
6003 rettv->vval.v_number = 1; /* Failed */ | |
6004 } | |
6005 | |
6006 /* | |
6007 * "inputsecret()" function | |
6008 */ | |
6009 static void | |
6010 f_inputsecret(typval_T *argvars, typval_T *rettv) | |
6011 { | |
6012 ++cmdline_star; | |
6013 ++inputsecret_flag; | |
6014 f_input(argvars, rettv); | |
6015 --cmdline_star; | |
6016 --inputsecret_flag; | |
6017 } | |
6018 | |
6019 /* | |
6020 * "insert()" function | |
6021 */ | |
6022 static void | |
6023 f_insert(typval_T *argvars, typval_T *rettv) | |
6024 { | |
6025 long before = 0; | |
6026 listitem_T *item; | |
6027 list_T *l; | |
6028 int error = FALSE; | |
6029 | |
6030 if (argvars[0].v_type != VAR_LIST) | |
6031 EMSG2(_(e_listarg), "insert()"); | |
6032 else if ((l = argvars[0].vval.v_list) != NULL | |
6033 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE)) | |
6034 { | |
6035 if (argvars[2].v_type != VAR_UNKNOWN) | |
6036 before = (long)get_tv_number_chk(&argvars[2], &error); | |
6037 if (error) | |
6038 return; /* type error; errmsg already given */ | |
6039 | |
6040 if (before == l->lv_len) | |
6041 item = NULL; | |
6042 else | |
6043 { | |
6044 item = list_find(l, before); | |
6045 if (item == NULL) | |
6046 { | |
6047 EMSGN(_(e_listidx), before); | |
6048 l = NULL; | |
6049 } | |
6050 } | |
6051 if (l != NULL) | |
6052 { | |
6053 list_insert_tv(l, &argvars[1], item); | |
6054 copy_tv(&argvars[0], rettv); | |
6055 } | |
6056 } | |
6057 } | |
6058 | |
6059 /* | |
6060 * "invert(expr)" function | |
6061 */ | |
6062 static void | |
6063 f_invert(typval_T *argvars, typval_T *rettv) | |
6064 { | |
6065 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL); | |
6066 } | |
6067 | |
6068 /* | |
6069 * "isdirectory()" function | |
6070 */ | |
6071 static void | |
6072 f_isdirectory(typval_T *argvars, typval_T *rettv) | |
6073 { | |
6074 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); | |
6075 } | |
6076 | |
6077 /* | |
6078 * Return TRUE if typeval "tv" is locked: Either that value is locked itself | |
6079 * or it refers to a List or Dictionary that is locked. | |
6080 */ | |
6081 static int | |
6082 tv_islocked(typval_T *tv) | |
6083 { | |
6084 return (tv->v_lock & VAR_LOCKED) | |
6085 || (tv->v_type == VAR_LIST | |
6086 && tv->vval.v_list != NULL | |
6087 && (tv->vval.v_list->lv_lock & VAR_LOCKED)) | |
6088 || (tv->v_type == VAR_DICT | |
6089 && tv->vval.v_dict != NULL | |
6090 && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); | |
6091 } | |
6092 | |
6093 /* | |
6094 * "islocked()" function | |
6095 */ | |
6096 static void | |
6097 f_islocked(typval_T *argvars, typval_T *rettv) | |
6098 { | |
6099 lval_T lv; | |
6100 char_u *end; | |
6101 dictitem_T *di; | |
6102 | |
6103 rettv->vval.v_number = -1; | |
6104 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE, | |
6105 GLV_NO_AUTOLOAD, FNE_CHECK_START); | |
6106 if (end != NULL && lv.ll_name != NULL) | |
6107 { | |
6108 if (*end != NUL) | |
6109 EMSG(_(e_trailing)); | |
6110 else | |
6111 { | |
6112 if (lv.ll_tv == NULL) | |
6113 { | |
6114 if (check_changedtick(lv.ll_name)) | |
6115 rettv->vval.v_number = 1; /* always locked */ | |
6116 else | |
6117 { | |
6118 di = find_var(lv.ll_name, NULL, TRUE); | |
6119 if (di != NULL) | |
6120 { | |
6121 /* Consider a variable locked when: | |
6122 * 1. the variable itself is locked | |
6123 * 2. the value of the variable is locked. | |
6124 * 3. the List or Dict value is locked. | |
6125 */ | |
6126 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) | |
6127 || tv_islocked(&di->di_tv)); | |
6128 } | |
6129 } | |
6130 } | |
6131 else if (lv.ll_range) | |
6132 EMSG(_("E786: Range not allowed")); | |
6133 else if (lv.ll_newkey != NULL) | |
6134 EMSG2(_(e_dictkey), lv.ll_newkey); | |
6135 else if (lv.ll_list != NULL) | |
6136 /* List item. */ | |
6137 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); | |
6138 else | |
6139 /* Dictionary item. */ | |
6140 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); | |
6141 } | |
6142 } | |
6143 | |
6144 clear_lval(&lv); | |
6145 } | |
6146 | |
6147 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | |
6148 /* | |
6149 * "isnan()" function | |
6150 */ | |
6151 static void | |
6152 f_isnan(typval_T *argvars, typval_T *rettv) | |
6153 { | |
6154 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT | |
6155 && isnan(argvars[0].vval.v_float); | |
6156 } | |
6157 #endif | |
6158 | |
6159 /* | |
6160 * "items(dict)" function | |
6161 */ | |
6162 static void | |
6163 f_items(typval_T *argvars, typval_T *rettv) | |
6164 { | |
6165 dict_list(argvars, rettv, 2); | |
6166 } | |
6167 | |
6168 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) | |
6169 /* | |
6170 * Get the job from the argument. | |
6171 * Returns NULL if the job is invalid. | |
6172 */ | |
6173 static job_T * | |
6174 get_job_arg(typval_T *tv) | |
6175 { | |
6176 job_T *job; | |
6177 | |
6178 if (tv->v_type != VAR_JOB) | |
6179 { | |
6180 EMSG2(_(e_invarg2), get_tv_string(tv)); | |
6181 return NULL; | |
6182 } | |
6183 job = tv->vval.v_job; | |
6184 | |
6185 if (job == NULL) | |
6186 EMSG(_("E916: not a valid job")); | |
6187 return job; | |
6188 } | |
6189 | |
6190 /* | |
6191 * "job_getchannel()" function | |
6192 */ | |
6193 static void | |
6194 f_job_getchannel(typval_T *argvars, typval_T *rettv) | |
6195 { | |
6196 job_T *job = get_job_arg(&argvars[0]); | |
6197 | |
6198 if (job != NULL) | |
6199 { | |
6200 rettv->v_type = VAR_CHANNEL; | |
6201 rettv->vval.v_channel = job->jv_channel; | |
6202 if (job->jv_channel != NULL) | |
6203 ++job->jv_channel->ch_refcount; | |
6204 } | |
6205 } | |
6206 | |
6207 /* | |
6208 * "job_info()" function | |
6209 */ | |
6210 static void | |
6211 f_job_info(typval_T *argvars, typval_T *rettv) | |
6212 { | |
6213 job_T *job = get_job_arg(&argvars[0]); | |
6214 | |
6215 if (job != NULL && rettv_dict_alloc(rettv) != FAIL) | |
6216 job_info(job, rettv->vval.v_dict); | |
6217 } | |
6218 | |
6219 /* | |
6220 * "job_setoptions()" function | |
6221 */ | |
6222 static void | |
6223 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) | |
6224 { | |
6225 job_T *job = get_job_arg(&argvars[0]); | |
6226 jobopt_T opt; | |
6227 | |
6228 if (job == NULL) | |
6229 return; | |
6230 clear_job_options(&opt); | |
6231 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK) | |
6232 job_set_options(job, &opt); | |
6233 free_job_options(&opt); | |
6234 } | |
6235 | |
6236 /* | |
6237 * "job_start()" function | |
6238 */ | |
6239 static void | |
6240 f_job_start(typval_T *argvars, typval_T *rettv) | |
6241 { | |
6242 rettv->v_type = VAR_JOB; | |
6243 if (check_restricted() || check_secure()) | |
6244 return; | |
6245 rettv->vval.v_job = job_start(argvars); | |
6246 } | |
6247 | |
6248 /* | |
6249 * "job_status()" function | |
6250 */ | |
6251 static void | |
6252 f_job_status(typval_T *argvars, typval_T *rettv) | |
6253 { | |
6254 job_T *job = get_job_arg(&argvars[0]); | |
6255 | |
6256 if (job != NULL) | |
6257 { | |
6258 rettv->v_type = VAR_STRING; | |
6259 rettv->vval.v_string = vim_strsave((char_u *)job_status(job)); | |
6260 } | |
6261 } | |
6262 | |
6263 /* | |
6264 * "job_stop()" function | |
6265 */ | |
6266 static void | |
6267 f_job_stop(typval_T *argvars, typval_T *rettv) | |
6268 { | |
6269 job_T *job = get_job_arg(&argvars[0]); | |
6270 | |
6271 if (job != NULL) | |
6272 rettv->vval.v_number = job_stop(job, argvars); | |
6273 } | |
6274 #endif | |
6275 | |
6276 /* | |
6277 * "join()" function | |
6278 */ | |
6279 static void | |
6280 f_join(typval_T *argvars, typval_T *rettv) | |
6281 { | |
6282 garray_T ga; | |
6283 char_u *sep; | |
6284 | |
6285 if (argvars[0].v_type != VAR_LIST) | |
6286 { | |
6287 EMSG(_(e_listreq)); | |
6288 return; | |
6289 } | |
6290 if (argvars[0].vval.v_list == NULL) | |
6291 return; | |
6292 if (argvars[1].v_type == VAR_UNKNOWN) | |
6293 sep = (char_u *)" "; | |
6294 else | |
6295 sep = get_tv_string_chk(&argvars[1]); | |
6296 | |
6297 rettv->v_type = VAR_STRING; | |
6298 | |
6299 if (sep != NULL) | |
6300 { | |
6301 ga_init2(&ga, (int)sizeof(char), 80); | |
6302 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); | |
6303 ga_append(&ga, NUL); | |
6304 rettv->vval.v_string = (char_u *)ga.ga_data; | |
6305 } | |
6306 else | |
6307 rettv->vval.v_string = NULL; | |
6308 } | |
6309 | |
6310 /* | |
6311 * "js_decode()" function | |
6312 */ | |
6313 static void | |
6314 f_js_decode(typval_T *argvars, typval_T *rettv) | |
6315 { | |
6316 js_read_T reader; | |
6317 | |
6318 reader.js_buf = get_tv_string(&argvars[0]); | |
6319 reader.js_fill = NULL; | |
6320 reader.js_used = 0; | |
6321 if (json_decode_all(&reader, rettv, JSON_JS) != OK) | |
6322 EMSG(_(e_invarg)); | |
6323 } | |
6324 | |
6325 /* | |
6326 * "js_encode()" function | |
6327 */ | |
6328 static void | |
6329 f_js_encode(typval_T *argvars, typval_T *rettv) | |
6330 { | |
6331 rettv->v_type = VAR_STRING; | |
6332 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); | |
6333 } | |
6334 | |
6335 /* | |
6336 * "json_decode()" function | |
6337 */ | |
6338 static void | |
6339 f_json_decode(typval_T *argvars, typval_T *rettv) | |
6340 { | |
6341 js_read_T reader; | |
6342 | |
6343 reader.js_buf = get_tv_string(&argvars[0]); | |
6344 reader.js_fill = NULL; | |
6345 reader.js_used = 0; | |
6346 if (json_decode_all(&reader, rettv, 0) != OK) | |
6347 EMSG(_(e_invarg)); | |
6348 } | |
6349 | |
6350 /* | |
6351 * "json_encode()" function | |
6352 */ | |
6353 static void | |
6354 f_json_encode(typval_T *argvars, typval_T *rettv) | |
6355 { | |
6356 rettv->v_type = VAR_STRING; | |
6357 rettv->vval.v_string = json_encode(&argvars[0], 0); | |
6358 } | |
6359 | |
6360 /* | |
6361 * "keys()" function | |
6362 */ | |
6363 static void | |
6364 f_keys(typval_T *argvars, typval_T *rettv) | |
6365 { | |
6366 dict_list(argvars, rettv, 0); | |
6367 } | |
6368 | |
6369 /* | |
6370 * "last_buffer_nr()" function. | |
6371 */ | |
6372 static void | |
6373 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) | |
6374 { | |
6375 int n = 0; | |
6376 buf_T *buf; | |
6377 | |
6378 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
6379 if (n < buf->b_fnum) | |
6380 n = buf->b_fnum; | |
6381 | |
6382 rettv->vval.v_number = n; | |
6383 } | |
6384 | |
6385 /* | |
6386 * "len()" function | |
6387 */ | |
6388 static void | |
6389 f_len(typval_T *argvars, typval_T *rettv) | |
6390 { | |
6391 switch (argvars[0].v_type) | |
6392 { | |
6393 case VAR_STRING: | |
6394 case VAR_NUMBER: | |
6395 rettv->vval.v_number = (varnumber_T)STRLEN( | |
6396 get_tv_string(&argvars[0])); | |
6397 break; | |
6398 case VAR_LIST: | |
6399 rettv->vval.v_number = list_len(argvars[0].vval.v_list); | |
6400 break; | |
6401 case VAR_DICT: | |
6402 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); | |
6403 break; | |
6404 case VAR_UNKNOWN: | |
6405 case VAR_SPECIAL: | |
6406 case VAR_FLOAT: | |
6407 case VAR_FUNC: | |
6408 case VAR_PARTIAL: | |
6409 case VAR_JOB: | |
6410 case VAR_CHANNEL: | |
6411 EMSG(_("E701: Invalid type for len()")); | |
6412 break; | |
6413 } | |
6414 } | |
6415 | |
6416 static void libcall_common(typval_T *argvars, typval_T *rettv, int type); | |
6417 | |
6418 static void | |
6419 libcall_common(typval_T *argvars, typval_T *rettv, int type) | |
6420 { | |
6421 #ifdef FEAT_LIBCALL | |
6422 char_u *string_in; | |
6423 char_u **string_result; | |
6424 int nr_result; | |
6425 #endif | |
6426 | |
6427 rettv->v_type = type; | |
6428 if (type != VAR_NUMBER) | |
6429 rettv->vval.v_string = NULL; | |
6430 | |
6431 if (check_restricted() || check_secure()) | |
6432 return; | |
6433 | |
6434 #ifdef FEAT_LIBCALL | |
6435 /* The first two args must be strings, otherwise its meaningless */ | |
6436 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) | |
6437 { | |
6438 string_in = NULL; | |
6439 if (argvars[2].v_type == VAR_STRING) | |
6440 string_in = argvars[2].vval.v_string; | |
6441 if (type == VAR_NUMBER) | |
6442 string_result = NULL; | |
6443 else | |
6444 string_result = &rettv->vval.v_string; | |
6445 if (mch_libcall(argvars[0].vval.v_string, | |
6446 argvars[1].vval.v_string, | |
6447 string_in, | |
6448 argvars[2].vval.v_number, | |
6449 string_result, | |
6450 &nr_result) == OK | |
6451 && type == VAR_NUMBER) | |
6452 rettv->vval.v_number = nr_result; | |
6453 } | |
6454 #endif | |
6455 } | |
6456 | |
6457 /* | |
6458 * "libcall()" function | |
6459 */ | |
6460 static void | |
6461 f_libcall(typval_T *argvars, typval_T *rettv) | |
6462 { | |
6463 libcall_common(argvars, rettv, VAR_STRING); | |
6464 } | |
6465 | |
6466 /* | |
6467 * "libcallnr()" function | |
6468 */ | |
6469 static void | |
6470 f_libcallnr(typval_T *argvars, typval_T *rettv) | |
6471 { | |
6472 libcall_common(argvars, rettv, VAR_NUMBER); | |
6473 } | |
6474 | |
6475 /* | |
6476 * "line(string)" function | |
6477 */ | |
6478 static void | |
6479 f_line(typval_T *argvars, typval_T *rettv) | |
6480 { | |
6481 linenr_T lnum = 0; | |
6482 pos_T *fp; | |
6483 int fnum; | |
6484 | |
6485 fp = var2fpos(&argvars[0], TRUE, &fnum); | |
6486 if (fp != NULL) | |
6487 lnum = fp->lnum; | |
6488 rettv->vval.v_number = lnum; | |
6489 } | |
6490 | |
6491 /* | |
6492 * "line2byte(lnum)" function | |
6493 */ | |
6494 static void | |
6495 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) | |
6496 { | |
6497 #ifndef FEAT_BYTEOFF | |
6498 rettv->vval.v_number = -1; | |
6499 #else | |
6500 linenr_T lnum; | |
6501 | |
6502 lnum = get_tv_lnum(argvars); | |
6503 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) | |
6504 rettv->vval.v_number = -1; | |
6505 else | |
6506 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL); | |
6507 if (rettv->vval.v_number >= 0) | |
6508 ++rettv->vval.v_number; | |
6509 #endif | |
6510 } | |
6511 | |
6512 /* | |
6513 * "lispindent(lnum)" function | |
6514 */ | |
6515 static void | |
6516 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv) | |
6517 { | |
6518 #ifdef FEAT_LISP | |
6519 pos_T pos; | |
6520 linenr_T lnum; | |
6521 | |
6522 pos = curwin->w_cursor; | |
6523 lnum = get_tv_lnum(argvars); | |
6524 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
6525 { | |
6526 curwin->w_cursor.lnum = lnum; | |
6527 rettv->vval.v_number = get_lisp_indent(); | |
6528 curwin->w_cursor = pos; | |
6529 } | |
6530 else | |
6531 #endif | |
6532 rettv->vval.v_number = -1; | |
6533 } | |
6534 | |
6535 /* | |
6536 * "localtime()" function | |
6537 */ | |
6538 static void | |
6539 f_localtime(typval_T *argvars UNUSED, typval_T *rettv) | |
6540 { | |
6541 rettv->vval.v_number = (varnumber_T)time(NULL); | |
6542 } | |
6543 | |
6544 static void get_maparg(typval_T *argvars, typval_T *rettv, int exact); | |
6545 | |
6546 static void | |
6547 get_maparg(typval_T *argvars, typval_T *rettv, int exact) | |
6548 { | |
6549 char_u *keys; | |
6550 char_u *which; | |
6551 char_u buf[NUMBUFLEN]; | |
6552 char_u *keys_buf = NULL; | |
6553 char_u *rhs; | |
6554 int mode; | |
6555 int abbr = FALSE; | |
6556 int get_dict = FALSE; | |
6557 mapblock_T *mp; | |
6558 int buffer_local; | |
6559 | |
6560 /* return empty string for failure */ | |
6561 rettv->v_type = VAR_STRING; | |
6562 rettv->vval.v_string = NULL; | |
6563 | |
6564 keys = get_tv_string(&argvars[0]); | |
6565 if (*keys == NUL) | |
6566 return; | |
6567 | |
6568 if (argvars[1].v_type != VAR_UNKNOWN) | |
6569 { | |
6570 which = get_tv_string_buf_chk(&argvars[1], buf); | |
6571 if (argvars[2].v_type != VAR_UNKNOWN) | |
6572 { | |
6573 abbr = (int)get_tv_number(&argvars[2]); | |
6574 if (argvars[3].v_type != VAR_UNKNOWN) | |
6575 get_dict = (int)get_tv_number(&argvars[3]); | |
6576 } | |
6577 } | |
6578 else | |
6579 which = (char_u *)""; | |
6580 if (which == NULL) | |
6581 return; | |
6582 | |
6583 mode = get_map_mode(&which, 0); | |
6584 | |
6585 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); | |
6586 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); | |
6587 vim_free(keys_buf); | |
6588 | |
6589 if (!get_dict) | |
6590 { | |
6591 /* Return a string. */ | |
6592 if (rhs != NULL) | |
6593 rettv->vval.v_string = str2special_save(rhs, FALSE); | |
6594 | |
6595 } | |
6596 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL) | |
6597 { | |
6598 /* Return a dictionary. */ | |
6599 char_u *lhs = str2special_save(mp->m_keys, TRUE); | |
6600 char_u *mapmode = map_mode_to_chars(mp->m_mode); | |
6601 dict_T *dict = rettv->vval.v_dict; | |
6602 | |
6603 dict_add_nr_str(dict, "lhs", 0L, lhs); | |
6604 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); | |
6605 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL); | |
6606 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL); | |
6607 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL); | |
6608 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL); | |
6609 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL); | |
6610 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL); | |
6611 dict_add_nr_str(dict, "mode", 0L, mapmode); | |
6612 | |
6613 vim_free(lhs); | |
6614 vim_free(mapmode); | |
6615 } | |
6616 } | |
6617 | |
6618 #ifdef FEAT_FLOAT | |
6619 /* | |
6620 * "log()" function | |
6621 */ | |
6622 static void | |
6623 f_log(typval_T *argvars, typval_T *rettv) | |
6624 { | |
6625 float_T f = 0.0; | |
6626 | |
6627 rettv->v_type = VAR_FLOAT; | |
6628 if (get_float_arg(argvars, &f) == OK) | |
6629 rettv->vval.v_float = log(f); | |
6630 else | |
6631 rettv->vval.v_float = 0.0; | |
6632 } | |
6633 | |
6634 /* | |
6635 * "log10()" function | |
6636 */ | |
6637 static void | |
6638 f_log10(typval_T *argvars, typval_T *rettv) | |
6639 { | |
6640 float_T f = 0.0; | |
6641 | |
6642 rettv->v_type = VAR_FLOAT; | |
6643 if (get_float_arg(argvars, &f) == OK) | |
6644 rettv->vval.v_float = log10(f); | |
6645 else | |
6646 rettv->vval.v_float = 0.0; | |
6647 } | |
6648 #endif | |
6649 | |
6650 #ifdef FEAT_LUA | |
6651 /* | |
6652 * "luaeval()" function | |
6653 */ | |
6654 static void | |
6655 f_luaeval(typval_T *argvars, typval_T *rettv) | |
6656 { | |
6657 char_u *str; | |
6658 char_u buf[NUMBUFLEN]; | |
6659 | |
6660 str = get_tv_string_buf(&argvars[0], buf); | |
6661 do_luaeval(str, argvars + 1, rettv); | |
6662 } | |
6663 #endif | |
6664 | |
6665 /* | |
6666 * "map()" function | |
6667 */ | |
6668 static void | |
6669 f_map(typval_T *argvars, typval_T *rettv) | |
6670 { | |
6671 filter_map(argvars, rettv, TRUE); | |
6672 } | |
6673 | |
6674 /* | |
6675 * "maparg()" function | |
6676 */ | |
6677 static void | |
6678 f_maparg(typval_T *argvars, typval_T *rettv) | |
6679 { | |
6680 get_maparg(argvars, rettv, TRUE); | |
6681 } | |
6682 | |
6683 /* | |
6684 * "mapcheck()" function | |
6685 */ | |
6686 static void | |
6687 f_mapcheck(typval_T *argvars, typval_T *rettv) | |
6688 { | |
6689 get_maparg(argvars, rettv, FALSE); | |
6690 } | |
6691 | |
6692 static void find_some_match(typval_T *argvars, typval_T *rettv, int start); | |
6693 | |
6694 static void | |
6695 find_some_match(typval_T *argvars, typval_T *rettv, int type) | |
6696 { | |
6697 char_u *str = NULL; | |
6698 long len = 0; | |
6699 char_u *expr = NULL; | |
6700 char_u *pat; | |
6701 regmatch_T regmatch; | |
6702 char_u patbuf[NUMBUFLEN]; | |
6703 char_u strbuf[NUMBUFLEN]; | |
6704 char_u *save_cpo; | |
6705 long start = 0; | |
6706 long nth = 1; | |
6707 colnr_T startcol = 0; | |
6708 int match = 0; | |
6709 list_T *l = NULL; | |
6710 listitem_T *li = NULL; | |
6711 long idx = 0; | |
6712 char_u *tofree = NULL; | |
6713 | |
6714 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
6715 save_cpo = p_cpo; | |
6716 p_cpo = (char_u *)""; | |
6717 | |
6718 rettv->vval.v_number = -1; | |
6719 if (type == 3 || type == 4) | |
6720 { | |
6721 /* type 3: return empty list when there are no matches. | |
6722 * type 4: return ["", -1, -1, -1] */ | |
6723 if (rettv_list_alloc(rettv) == FAIL) | |
6724 goto theend; | |
6725 if (type == 4 | |
6726 && (list_append_string(rettv->vval.v_list, | |
6727 (char_u *)"", 0) == FAIL | |
6728 || list_append_number(rettv->vval.v_list, | |
6729 (varnumber_T)-1) == FAIL | |
6730 || list_append_number(rettv->vval.v_list, | |
6731 (varnumber_T)-1) == FAIL | |
6732 || list_append_number(rettv->vval.v_list, | |
6733 (varnumber_T)-1) == FAIL)) | |
6734 { | |
6735 list_free(rettv->vval.v_list); | |
6736 rettv->vval.v_list = NULL; | |
6737 goto theend; | |
6738 } | |
6739 } | |
6740 else if (type == 2) | |
6741 { | |
6742 rettv->v_type = VAR_STRING; | |
6743 rettv->vval.v_string = NULL; | |
6744 } | |
6745 | |
6746 if (argvars[0].v_type == VAR_LIST) | |
6747 { | |
6748 if ((l = argvars[0].vval.v_list) == NULL) | |
6749 goto theend; | |
6750 li = l->lv_first; | |
6751 } | |
6752 else | |
6753 { | |
6754 expr = str = get_tv_string(&argvars[0]); | |
6755 len = (long)STRLEN(str); | |
6756 } | |
6757 | |
6758 pat = get_tv_string_buf_chk(&argvars[1], patbuf); | |
6759 if (pat == NULL) | |
6760 goto theend; | |
6761 | |
6762 if (argvars[2].v_type != VAR_UNKNOWN) | |
6763 { | |
6764 int error = FALSE; | |
6765 | |
6766 start = (long)get_tv_number_chk(&argvars[2], &error); | |
6767 if (error) | |
6768 goto theend; | |
6769 if (l != NULL) | |
6770 { | |
6771 li = list_find(l, start); | |
6772 if (li == NULL) | |
6773 goto theend; | |
6774 idx = l->lv_idx; /* use the cached index */ | |
6775 } | |
6776 else | |
6777 { | |
6778 if (start < 0) | |
6779 start = 0; | |
6780 if (start > len) | |
6781 goto theend; | |
6782 /* When "count" argument is there ignore matches before "start", | |
6783 * otherwise skip part of the string. Differs when pattern is "^" | |
6784 * or "\<". */ | |
6785 if (argvars[3].v_type != VAR_UNKNOWN) | |
6786 startcol = start; | |
6787 else | |
6788 { | |
6789 str += start; | |
6790 len -= start; | |
6791 } | |
6792 } | |
6793 | |
6794 if (argvars[3].v_type != VAR_UNKNOWN) | |
6795 nth = (long)get_tv_number_chk(&argvars[3], &error); | |
6796 if (error) | |
6797 goto theend; | |
6798 } | |
6799 | |
6800 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); | |
6801 if (regmatch.regprog != NULL) | |
6802 { | |
6803 regmatch.rm_ic = p_ic; | |
6804 | |
6805 for (;;) | |
6806 { | |
6807 if (l != NULL) | |
6808 { | |
6809 if (li == NULL) | |
6810 { | |
6811 match = FALSE; | |
6812 break; | |
6813 } | |
6814 vim_free(tofree); | |
6815 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0); | |
6816 if (str == NULL) | |
6817 break; | |
6818 } | |
6819 | |
6820 match = vim_regexec_nl(®match, str, (colnr_T)startcol); | |
6821 | |
6822 if (match && --nth <= 0) | |
6823 break; | |
6824 if (l == NULL && !match) | |
6825 break; | |
6826 | |
6827 /* Advance to just after the match. */ | |
6828 if (l != NULL) | |
6829 { | |
6830 li = li->li_next; | |
6831 ++idx; | |
6832 } | |
6833 else | |
6834 { | |
6835 #ifdef FEAT_MBYTE | |
6836 startcol = (colnr_T)(regmatch.startp[0] | |
6837 + (*mb_ptr2len)(regmatch.startp[0]) - str); | |
6838 #else | |
6839 startcol = (colnr_T)(regmatch.startp[0] + 1 - str); | |
6840 #endif | |
6841 if (startcol > (colnr_T)len | |
6842 || str + startcol <= regmatch.startp[0]) | |
6843 { | |
6844 match = FALSE; | |
6845 break; | |
6846 } | |
6847 } | |
6848 } | |
6849 | |
6850 if (match) | |
6851 { | |
6852 if (type == 4) | |
6853 { | |
6854 listitem_T *li1 = rettv->vval.v_list->lv_first; | |
6855 listitem_T *li2 = li1->li_next; | |
6856 listitem_T *li3 = li2->li_next; | |
6857 listitem_T *li4 = li3->li_next; | |
6858 | |
6859 vim_free(li1->li_tv.vval.v_string); | |
6860 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0], | |
6861 (int)(regmatch.endp[0] - regmatch.startp[0])); | |
6862 li3->li_tv.vval.v_number = | |
6863 (varnumber_T)(regmatch.startp[0] - expr); | |
6864 li4->li_tv.vval.v_number = | |
6865 (varnumber_T)(regmatch.endp[0] - expr); | |
6866 if (l != NULL) | |
6867 li2->li_tv.vval.v_number = (varnumber_T)idx; | |
6868 } | |
6869 else if (type == 3) | |
6870 { | |
6871 int i; | |
6872 | |
6873 /* return list with matched string and submatches */ | |
6874 for (i = 0; i < NSUBEXP; ++i) | |
6875 { | |
6876 if (regmatch.endp[i] == NULL) | |
6877 { | |
6878 if (list_append_string(rettv->vval.v_list, | |
6879 (char_u *)"", 0) == FAIL) | |
6880 break; | |
6881 } | |
6882 else if (list_append_string(rettv->vval.v_list, | |
6883 regmatch.startp[i], | |
6884 (int)(regmatch.endp[i] - regmatch.startp[i])) | |
6885 == FAIL) | |
6886 break; | |
6887 } | |
6888 } | |
6889 else if (type == 2) | |
6890 { | |
6891 /* return matched string */ | |
6892 if (l != NULL) | |
6893 copy_tv(&li->li_tv, rettv); | |
6894 else | |
6895 rettv->vval.v_string = vim_strnsave(regmatch.startp[0], | |
6896 (int)(regmatch.endp[0] - regmatch.startp[0])); | |
6897 } | |
6898 else if (l != NULL) | |
6899 rettv->vval.v_number = idx; | |
6900 else | |
6901 { | |
6902 if (type != 0) | |
6903 rettv->vval.v_number = | |
6904 (varnumber_T)(regmatch.startp[0] - str); | |
6905 else | |
6906 rettv->vval.v_number = | |
6907 (varnumber_T)(regmatch.endp[0] - str); | |
6908 rettv->vval.v_number += (varnumber_T)(str - expr); | |
6909 } | |
6910 } | |
6911 vim_regfree(regmatch.regprog); | |
6912 } | |
6913 | |
6914 if (type == 4 && l == NULL) | |
6915 /* matchstrpos() without a list: drop the second item. */ | |
6916 listitem_remove(rettv->vval.v_list, | |
6917 rettv->vval.v_list->lv_first->li_next); | |
6918 | |
6919 theend: | |
6920 vim_free(tofree); | |
6921 p_cpo = save_cpo; | |
6922 } | |
6923 | |
6924 /* | |
6925 * "match()" function | |
6926 */ | |
6927 static void | |
6928 f_match(typval_T *argvars, typval_T *rettv) | |
6929 { | |
6930 find_some_match(argvars, rettv, 1); | |
6931 } | |
6932 | |
6933 /* | |
6934 * "matchadd()" function | |
6935 */ | |
6936 static void | |
6937 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
6938 { | |
6939 #ifdef FEAT_SEARCH_EXTRA | |
6940 char_u buf[NUMBUFLEN]; | |
6941 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */ | |
6942 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ | |
6943 int prio = 10; /* default priority */ | |
6944 int id = -1; | |
6945 int error = FALSE; | |
6946 char_u *conceal_char = NULL; | |
6947 | |
6948 rettv->vval.v_number = -1; | |
6949 | |
6950 if (grp == NULL || pat == NULL) | |
6951 return; | |
6952 if (argvars[2].v_type != VAR_UNKNOWN) | |
6953 { | |
6954 prio = (int)get_tv_number_chk(&argvars[2], &error); | |
6955 if (argvars[3].v_type != VAR_UNKNOWN) | |
6956 { | |
6957 id = (int)get_tv_number_chk(&argvars[3], &error); | |
6958 if (argvars[4].v_type != VAR_UNKNOWN) | |
6959 { | |
6960 if (argvars[4].v_type != VAR_DICT) | |
6961 { | |
6962 EMSG(_(e_dictreq)); | |
6963 return; | |
6964 } | |
6965 if (dict_find(argvars[4].vval.v_dict, | |
6966 (char_u *)"conceal", -1) != NULL) | |
6967 conceal_char = get_dict_string(argvars[4].vval.v_dict, | |
6968 (char_u *)"conceal", FALSE); | |
6969 } | |
6970 } | |
6971 } | |
6972 if (error == TRUE) | |
6973 return; | |
6974 if (id >= 1 && id <= 3) | |
6975 { | |
6976 EMSGN("E798: ID is reserved for \":match\": %ld", id); | |
6977 return; | |
6978 } | |
6979 | |
6980 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL, | |
6981 conceal_char); | |
6982 #endif | |
6983 } | |
6984 | |
6985 /* | |
6986 * "matchaddpos()" function | |
6987 */ | |
6988 static void | |
6989 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
6990 { | |
6991 #ifdef FEAT_SEARCH_EXTRA | |
6992 char_u buf[NUMBUFLEN]; | |
6993 char_u *group; | |
6994 int prio = 10; | |
6995 int id = -1; | |
6996 int error = FALSE; | |
6997 list_T *l; | |
6998 char_u *conceal_char = NULL; | |
6999 | |
7000 rettv->vval.v_number = -1; | |
7001 | |
7002 group = get_tv_string_buf_chk(&argvars[0], buf); | |
7003 if (group == NULL) | |
7004 return; | |
7005 | |
7006 if (argvars[1].v_type != VAR_LIST) | |
7007 { | |
7008 EMSG2(_(e_listarg), "matchaddpos()"); | |
7009 return; | |
7010 } | |
7011 l = argvars[1].vval.v_list; | |
7012 if (l == NULL) | |
7013 return; | |
7014 | |
7015 if (argvars[2].v_type != VAR_UNKNOWN) | |
7016 { | |
7017 prio = (int)get_tv_number_chk(&argvars[2], &error); | |
7018 if (argvars[3].v_type != VAR_UNKNOWN) | |
7019 { | |
7020 id = (int)get_tv_number_chk(&argvars[3], &error); | |
7021 if (argvars[4].v_type != VAR_UNKNOWN) | |
7022 { | |
7023 if (argvars[4].v_type != VAR_DICT) | |
7024 { | |
7025 EMSG(_(e_dictreq)); | |
7026 return; | |
7027 } | |
7028 if (dict_find(argvars[4].vval.v_dict, | |
7029 (char_u *)"conceal", -1) != NULL) | |
7030 conceal_char = get_dict_string(argvars[4].vval.v_dict, | |
7031 (char_u *)"conceal", FALSE); | |
7032 } | |
7033 } | |
7034 } | |
7035 if (error == TRUE) | |
7036 return; | |
7037 | |
7038 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */ | |
7039 if (id == 1 || id == 2) | |
7040 { | |
7041 EMSGN("E798: ID is reserved for \":match\": %ld", id); | |
7042 return; | |
7043 } | |
7044 | |
7045 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l, | |
7046 conceal_char); | |
7047 #endif | |
7048 } | |
7049 | |
7050 /* | |
7051 * "matcharg()" function | |
7052 */ | |
7053 static void | |
7054 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) | |
7055 { | |
7056 if (rettv_list_alloc(rettv) == OK) | |
7057 { | |
7058 #ifdef FEAT_SEARCH_EXTRA | |
7059 int id = (int)get_tv_number(&argvars[0]); | |
7060 matchitem_T *m; | |
7061 | |
7062 if (id >= 1 && id <= 3) | |
7063 { | |
7064 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) | |
7065 { | |
7066 list_append_string(rettv->vval.v_list, | |
7067 syn_id2name(m->hlg_id), -1); | |
7068 list_append_string(rettv->vval.v_list, m->pattern, -1); | |
7069 } | |
7070 else | |
7071 { | |
7072 list_append_string(rettv->vval.v_list, NULL, -1); | |
7073 list_append_string(rettv->vval.v_list, NULL, -1); | |
7074 } | |
7075 } | |
7076 #endif | |
7077 } | |
7078 } | |
7079 | |
7080 /* | |
7081 * "matchdelete()" function | |
7082 */ | |
7083 static void | |
7084 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
7085 { | |
7086 #ifdef FEAT_SEARCH_EXTRA | |
7087 rettv->vval.v_number = match_delete(curwin, | |
7088 (int)get_tv_number(&argvars[0]), TRUE); | |
7089 #endif | |
7090 } | |
7091 | |
7092 /* | |
7093 * "matchend()" function | |
7094 */ | |
7095 static void | |
7096 f_matchend(typval_T *argvars, typval_T *rettv) | |
7097 { | |
7098 find_some_match(argvars, rettv, 0); | |
7099 } | |
7100 | |
7101 /* | |
7102 * "matchlist()" function | |
7103 */ | |
7104 static void | |
7105 f_matchlist(typval_T *argvars, typval_T *rettv) | |
7106 { | |
7107 find_some_match(argvars, rettv, 3); | |
7108 } | |
7109 | |
7110 /* | |
7111 * "matchstr()" function | |
7112 */ | |
7113 static void | |
7114 f_matchstr(typval_T *argvars, typval_T *rettv) | |
7115 { | |
7116 find_some_match(argvars, rettv, 2); | |
7117 } | |
7118 | |
7119 /* | |
7120 * "matchstrpos()" function | |
7121 */ | |
7122 static void | |
7123 f_matchstrpos(typval_T *argvars, typval_T *rettv) | |
7124 { | |
7125 find_some_match(argvars, rettv, 4); | |
7126 } | |
7127 | |
7128 static void max_min(typval_T *argvars, typval_T *rettv, int domax); | |
7129 | |
7130 static void | |
7131 max_min(typval_T *argvars, typval_T *rettv, int domax) | |
7132 { | |
7133 varnumber_T n = 0; | |
7134 varnumber_T i; | |
7135 int error = FALSE; | |
7136 | |
7137 if (argvars[0].v_type == VAR_LIST) | |
7138 { | |
7139 list_T *l; | |
7140 listitem_T *li; | |
7141 | |
7142 l = argvars[0].vval.v_list; | |
7143 if (l != NULL) | |
7144 { | |
7145 li = l->lv_first; | |
7146 if (li != NULL) | |
7147 { | |
7148 n = get_tv_number_chk(&li->li_tv, &error); | |
7149 for (;;) | |
7150 { | |
7151 li = li->li_next; | |
7152 if (li == NULL) | |
7153 break; | |
7154 i = get_tv_number_chk(&li->li_tv, &error); | |
7155 if (domax ? i > n : i < n) | |
7156 n = i; | |
7157 } | |
7158 } | |
7159 } | |
7160 } | |
7161 else if (argvars[0].v_type == VAR_DICT) | |
7162 { | |
7163 dict_T *d; | |
7164 int first = TRUE; | |
7165 hashitem_T *hi; | |
7166 int todo; | |
7167 | |
7168 d = argvars[0].vval.v_dict; | |
7169 if (d != NULL) | |
7170 { | |
7171 todo = (int)d->dv_hashtab.ht_used; | |
7172 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | |
7173 { | |
7174 if (!HASHITEM_EMPTY(hi)) | |
7175 { | |
7176 --todo; | |
7177 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error); | |
7178 if (first) | |
7179 { | |
7180 n = i; | |
7181 first = FALSE; | |
7182 } | |
7183 else if (domax ? i > n : i < n) | |
7184 n = i; | |
7185 } | |
7186 } | |
7187 } | |
7188 } | |
7189 else | |
7190 EMSG(_(e_listdictarg)); | |
7191 rettv->vval.v_number = error ? 0 : n; | |
7192 } | |
7193 | |
7194 /* | |
7195 * "max()" function | |
7196 */ | |
7197 static void | |
7198 f_max(typval_T *argvars, typval_T *rettv) | |
7199 { | |
7200 max_min(argvars, rettv, TRUE); | |
7201 } | |
7202 | |
7203 /* | |
7204 * "min()" function | |
7205 */ | |
7206 static void | |
7207 f_min(typval_T *argvars, typval_T *rettv) | |
7208 { | |
7209 max_min(argvars, rettv, FALSE); | |
7210 } | |
7211 | |
7212 static int mkdir_recurse(char_u *dir, int prot); | |
7213 | |
7214 /* | |
7215 * Create the directory in which "dir" is located, and higher levels when | |
7216 * needed. | |
7217 */ | |
7218 static int | |
7219 mkdir_recurse(char_u *dir, int prot) | |
7220 { | |
7221 char_u *p; | |
7222 char_u *updir; | |
7223 int r = FAIL; | |
7224 | |
7225 /* Get end of directory name in "dir". | |
7226 * We're done when it's "/" or "c:/". */ | |
7227 p = gettail_sep(dir); | |
7228 if (p <= get_past_head(dir)) | |
7229 return OK; | |
7230 | |
7231 /* If the directory exists we're done. Otherwise: create it.*/ | |
7232 updir = vim_strnsave(dir, (int)(p - dir)); | |
7233 if (updir == NULL) | |
7234 return FAIL; | |
7235 if (mch_isdir(updir)) | |
7236 r = OK; | |
7237 else if (mkdir_recurse(updir, prot) == OK) | |
7238 r = vim_mkdir_emsg(updir, prot); | |
7239 vim_free(updir); | |
7240 return r; | |
7241 } | |
7242 | |
7243 #ifdef vim_mkdir | |
7244 /* | |
7245 * "mkdir()" function | |
7246 */ | |
7247 static void | |
7248 f_mkdir(typval_T *argvars, typval_T *rettv) | |
7249 { | |
7250 char_u *dir; | |
7251 char_u buf[NUMBUFLEN]; | |
7252 int prot = 0755; | |
7253 | |
7254 rettv->vval.v_number = FAIL; | |
7255 if (check_restricted() || check_secure()) | |
7256 return; | |
7257 | |
7258 dir = get_tv_string_buf(&argvars[0], buf); | |
7259 if (*dir == NUL) | |
7260 rettv->vval.v_number = FAIL; | |
7261 else | |
7262 { | |
7263 if (*gettail(dir) == NUL) | |
7264 /* remove trailing slashes */ | |
7265 *gettail_sep(dir) = NUL; | |
7266 | |
7267 if (argvars[1].v_type != VAR_UNKNOWN) | |
7268 { | |
7269 if (argvars[2].v_type != VAR_UNKNOWN) | |
7270 prot = (int)get_tv_number_chk(&argvars[2], NULL); | |
7271 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) | |
7272 mkdir_recurse(dir, prot); | |
7273 } | |
7274 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot); | |
7275 } | |
7276 } | |
7277 #endif | |
7278 | |
7279 /* | |
7280 * "mode()" function | |
7281 */ | |
7282 static void | |
7283 f_mode(typval_T *argvars, typval_T *rettv) | |
7284 { | |
7285 char_u buf[3]; | |
7286 | |
7287 buf[1] = NUL; | |
7288 buf[2] = NUL; | |
7289 | |
7290 if (time_for_testing == 93784) | |
7291 { | |
7292 /* Testing the two-character code. */ | |
7293 buf[0] = 'x'; | |
7294 buf[1] = '!'; | |
7295 } | |
7296 else if (VIsual_active) | |
7297 { | |
7298 if (VIsual_select) | |
7299 buf[0] = VIsual_mode + 's' - 'v'; | |
7300 else | |
7301 buf[0] = VIsual_mode; | |
7302 } | |
7303 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE | |
7304 || State == CONFIRM) | |
7305 { | |
7306 buf[0] = 'r'; | |
7307 if (State == ASKMORE) | |
7308 buf[1] = 'm'; | |
7309 else if (State == CONFIRM) | |
7310 buf[1] = '?'; | |
7311 } | |
7312 else if (State == EXTERNCMD) | |
7313 buf[0] = '!'; | |
7314 else if (State & INSERT) | |
7315 { | |
7316 #ifdef FEAT_VREPLACE | |
7317 if (State & VREPLACE_FLAG) | |
7318 { | |
7319 buf[0] = 'R'; | |
7320 buf[1] = 'v'; | |
7321 } | |
7322 else | |
7323 #endif | |
7324 if (State & REPLACE_FLAG) | |
7325 buf[0] = 'R'; | |
7326 else | |
7327 buf[0] = 'i'; | |
7328 } | |
7329 else if (State & CMDLINE) | |
7330 { | |
7331 buf[0] = 'c'; | |
7332 if (exmode_active) | |
7333 buf[1] = 'v'; | |
7334 } | |
7335 else if (exmode_active) | |
7336 { | |
7337 buf[0] = 'c'; | |
7338 buf[1] = 'e'; | |
7339 } | |
7340 else | |
7341 { | |
7342 buf[0] = 'n'; | |
7343 if (finish_op) | |
7344 buf[1] = 'o'; | |
7345 } | |
7346 | |
7347 /* Clear out the minor mode when the argument is not a non-zero number or | |
7348 * non-empty string. */ | |
7349 if (!non_zero_arg(&argvars[0])) | |
7350 buf[1] = NUL; | |
7351 | |
7352 rettv->vval.v_string = vim_strsave(buf); | |
7353 rettv->v_type = VAR_STRING; | |
7354 } | |
7355 | |
7356 #if defined(FEAT_MZSCHEME) || defined(PROTO) | |
7357 /* | |
7358 * "mzeval()" function | |
7359 */ | |
7360 static void | |
7361 f_mzeval(typval_T *argvars, typval_T *rettv) | |
7362 { | |
7363 char_u *str; | |
7364 char_u buf[NUMBUFLEN]; | |
7365 | |
7366 str = get_tv_string_buf(&argvars[0], buf); | |
7367 do_mzeval(str, rettv); | |
7368 } | |
7369 | |
7370 void | |
7371 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv) | |
7372 { | |
7373 typval_T argvars[3]; | |
7374 | |
7375 argvars[0].v_type = VAR_STRING; | |
7376 argvars[0].vval.v_string = name; | |
7377 copy_tv(args, &argvars[1]); | |
7378 argvars[2].v_type = VAR_UNKNOWN; | |
7379 f_call(argvars, rettv); | |
7380 clear_tv(&argvars[1]); | |
7381 } | |
7382 #endif | |
7383 | |
7384 /* | |
7385 * "nextnonblank()" function | |
7386 */ | |
7387 static void | |
7388 f_nextnonblank(typval_T *argvars, typval_T *rettv) | |
7389 { | |
7390 linenr_T lnum; | |
7391 | |
7392 for (lnum = get_tv_lnum(argvars); ; ++lnum) | |
7393 { | |
7394 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) | |
7395 { | |
7396 lnum = 0; | |
7397 break; | |
7398 } | |
7399 if (*skipwhite(ml_get(lnum)) != NUL) | |
7400 break; | |
7401 } | |
7402 rettv->vval.v_number = lnum; | |
7403 } | |
7404 | |
7405 /* | |
7406 * "nr2char()" function | |
7407 */ | |
7408 static void | |
7409 f_nr2char(typval_T *argvars, typval_T *rettv) | |
7410 { | |
7411 char_u buf[NUMBUFLEN]; | |
7412 | |
7413 #ifdef FEAT_MBYTE | |
7414 if (has_mbyte) | |
7415 { | |
7416 int utf8 = 0; | |
7417 | |
7418 if (argvars[1].v_type != VAR_UNKNOWN) | |
7419 utf8 = (int)get_tv_number_chk(&argvars[1], NULL); | |
7420 if (utf8) | |
7421 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; | |
7422 else | |
7423 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; | |
7424 } | |
7425 else | |
7426 #endif | |
7427 { | |
7428 buf[0] = (char_u)get_tv_number(&argvars[0]); | |
7429 buf[1] = NUL; | |
7430 } | |
7431 rettv->v_type = VAR_STRING; | |
7432 rettv->vval.v_string = vim_strsave(buf); | |
7433 } | |
7434 | |
7435 /* | |
7436 * "or(expr, expr)" function | |
7437 */ | |
7438 static void | |
7439 f_or(typval_T *argvars, typval_T *rettv) | |
7440 { | |
7441 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | |
7442 | get_tv_number_chk(&argvars[1], NULL); | |
7443 } | |
7444 | |
7445 /* | |
7446 * "pathshorten()" function | |
7447 */ | |
7448 static void | |
7449 f_pathshorten(typval_T *argvars, typval_T *rettv) | |
7450 { | |
7451 char_u *p; | |
7452 | |
7453 rettv->v_type = VAR_STRING; | |
7454 p = get_tv_string_chk(&argvars[0]); | |
7455 if (p == NULL) | |
7456 rettv->vval.v_string = NULL; | |
7457 else | |
7458 { | |
7459 p = vim_strsave(p); | |
7460 rettv->vval.v_string = p; | |
7461 if (p != NULL) | |
7462 shorten_dir(p); | |
7463 } | |
7464 } | |
7465 | |
7466 #ifdef FEAT_PERL | |
7467 /* | |
7468 * "perleval()" function | |
7469 */ | |
7470 static void | |
7471 f_perleval(typval_T *argvars, typval_T *rettv) | |
7472 { | |
7473 char_u *str; | |
7474 char_u buf[NUMBUFLEN]; | |
7475 | |
7476 str = get_tv_string_buf(&argvars[0], buf); | |
7477 do_perleval(str, rettv); | |
7478 } | |
7479 #endif | |
7480 | |
7481 #ifdef FEAT_FLOAT | |
7482 /* | |
7483 * "pow()" function | |
7484 */ | |
7485 static void | |
7486 f_pow(typval_T *argvars, typval_T *rettv) | |
7487 { | |
7488 float_T fx = 0.0, fy = 0.0; | |
7489 | |
7490 rettv->v_type = VAR_FLOAT; | |
7491 if (get_float_arg(argvars, &fx) == OK | |
7492 && get_float_arg(&argvars[1], &fy) == OK) | |
7493 rettv->vval.v_float = pow(fx, fy); | |
7494 else | |
7495 rettv->vval.v_float = 0.0; | |
7496 } | |
7497 #endif | |
7498 | |
7499 /* | |
7500 * "prevnonblank()" function | |
7501 */ | |
7502 static void | |
7503 f_prevnonblank(typval_T *argvars, typval_T *rettv) | |
7504 { | |
7505 linenr_T lnum; | |
7506 | |
7507 lnum = get_tv_lnum(argvars); | |
7508 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) | |
7509 lnum = 0; | |
7510 else | |
7511 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) | |
7512 --lnum; | |
7513 rettv->vval.v_number = lnum; | |
7514 } | |
7515 | |
7516 /* This dummy va_list is here because: | |
7517 * - passing a NULL pointer doesn't work when va_list isn't a pointer | |
7518 * - locally in the function results in a "used before set" warning | |
7519 * - using va_start() to initialize it gives "function with fixed args" error */ | |
7520 static va_list ap; | |
7521 | |
7522 /* | |
7523 * "printf()" function | |
7524 */ | |
7525 static void | |
7526 f_printf(typval_T *argvars, typval_T *rettv) | |
7527 { | |
7528 char_u buf[NUMBUFLEN]; | |
7529 int len; | |
7530 char_u *s; | |
7531 int saved_did_emsg = did_emsg; | |
7532 char *fmt; | |
7533 | |
7534 rettv->v_type = VAR_STRING; | |
7535 rettv->vval.v_string = NULL; | |
7536 | |
7537 /* Get the required length, allocate the buffer and do it for real. */ | |
7538 did_emsg = FALSE; | |
7539 fmt = (char *)get_tv_string_buf(&argvars[0], buf); | |
7540 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1); | |
7541 if (!did_emsg) | |
7542 { | |
7543 s = alloc(len + 1); | |
7544 if (s != NULL) | |
7545 { | |
7546 rettv->vval.v_string = s; | |
7547 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1); | |
7548 } | |
7549 } | |
7550 did_emsg |= saved_did_emsg; | |
7551 } | |
7552 | |
7553 /* | |
7554 * "pumvisible()" function | |
7555 */ | |
7556 static void | |
7557 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
7558 { | |
7559 #ifdef FEAT_INS_EXPAND | |
7560 if (pum_visible()) | |
7561 rettv->vval.v_number = 1; | |
7562 #endif | |
7563 } | |
7564 | |
7565 #ifdef FEAT_PYTHON3 | |
7566 /* | |
7567 * "py3eval()" function | |
7568 */ | |
7569 static void | |
7570 f_py3eval(typval_T *argvars, typval_T *rettv) | |
7571 { | |
7572 char_u *str; | |
7573 char_u buf[NUMBUFLEN]; | |
7574 | |
7575 str = get_tv_string_buf(&argvars[0], buf); | |
7576 do_py3eval(str, rettv); | |
7577 } | |
7578 #endif | |
7579 | |
7580 #ifdef FEAT_PYTHON | |
7581 /* | |
7582 * "pyeval()" function | |
7583 */ | |
7584 static void | |
7585 f_pyeval(typval_T *argvars, typval_T *rettv) | |
7586 { | |
7587 char_u *str; | |
7588 char_u buf[NUMBUFLEN]; | |
7589 | |
7590 str = get_tv_string_buf(&argvars[0], buf); | |
7591 do_pyeval(str, rettv); | |
7592 } | |
7593 #endif | |
7594 | |
7595 /* | |
7596 * "range()" function | |
7597 */ | |
7598 static void | |
7599 f_range(typval_T *argvars, typval_T *rettv) | |
7600 { | |
7601 varnumber_T start; | |
7602 varnumber_T end; | |
7603 varnumber_T stride = 1; | |
7604 varnumber_T i; | |
7605 int error = FALSE; | |
7606 | |
7607 start = get_tv_number_chk(&argvars[0], &error); | |
7608 if (argvars[1].v_type == VAR_UNKNOWN) | |
7609 { | |
7610 end = start - 1; | |
7611 start = 0; | |
7612 } | |
7613 else | |
7614 { | |
7615 end = get_tv_number_chk(&argvars[1], &error); | |
7616 if (argvars[2].v_type != VAR_UNKNOWN) | |
7617 stride = get_tv_number_chk(&argvars[2], &error); | |
7618 } | |
7619 | |
7620 if (error) | |
7621 return; /* type error; errmsg already given */ | |
7622 if (stride == 0) | |
7623 EMSG(_("E726: Stride is zero")); | |
7624 else if (stride > 0 ? end + 1 < start : end - 1 > start) | |
7625 EMSG(_("E727: Start past end")); | |
7626 else | |
7627 { | |
7628 if (rettv_list_alloc(rettv) == OK) | |
7629 for (i = start; stride > 0 ? i <= end : i >= end; i += stride) | |
7630 if (list_append_number(rettv->vval.v_list, | |
7631 (varnumber_T)i) == FAIL) | |
7632 break; | |
7633 } | |
7634 } | |
7635 | |
7636 /* | |
7637 * "readfile()" function | |
7638 */ | |
7639 static void | |
7640 f_readfile(typval_T *argvars, typval_T *rettv) | |
7641 { | |
7642 int binary = FALSE; | |
7643 int failed = FALSE; | |
7644 char_u *fname; | |
7645 FILE *fd; | |
7646 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */ | |
7647 int io_size = sizeof(buf); | |
7648 int readlen; /* size of last fread() */ | |
7649 char_u *prev = NULL; /* previously read bytes, if any */ | |
7650 long prevlen = 0; /* length of data in prev */ | |
7651 long prevsize = 0; /* size of prev buffer */ | |
7652 long maxline = MAXLNUM; | |
7653 long cnt = 0; | |
7654 char_u *p; /* position in buf */ | |
7655 char_u *start; /* start of current line */ | |
7656 | |
7657 if (argvars[1].v_type != VAR_UNKNOWN) | |
7658 { | |
7659 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0) | |
7660 binary = TRUE; | |
7661 if (argvars[2].v_type != VAR_UNKNOWN) | |
7662 maxline = (long)get_tv_number(&argvars[2]); | |
7663 } | |
7664 | |
7665 if (rettv_list_alloc(rettv) == FAIL) | |
7666 return; | |
7667 | |
7668 /* Always open the file in binary mode, library functions have a mind of | |
7669 * their own about CR-LF conversion. */ | |
7670 fname = get_tv_string(&argvars[0]); | |
7671 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) | |
7672 { | |
7673 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname); | |
7674 return; | |
7675 } | |
7676 | |
7677 while (cnt < maxline || maxline < 0) | |
7678 { | |
7679 readlen = (int)fread(buf, 1, io_size, fd); | |
7680 | |
7681 /* This for loop processes what was read, but is also entered at end | |
7682 * of file so that either: | |
7683 * - an incomplete line gets written | |
7684 * - a "binary" file gets an empty line at the end if it ends in a | |
7685 * newline. */ | |
7686 for (p = buf, start = buf; | |
7687 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); | |
7688 ++p) | |
7689 { | |
7690 if (*p == '\n' || readlen <= 0) | |
7691 { | |
7692 listitem_T *li; | |
7693 char_u *s = NULL; | |
7694 long_u len = p - start; | |
7695 | |
7696 /* Finished a line. Remove CRs before NL. */ | |
7697 if (readlen > 0 && !binary) | |
7698 { | |
7699 while (len > 0 && start[len - 1] == '\r') | |
7700 --len; | |
7701 /* removal may cross back to the "prev" string */ | |
7702 if (len == 0) | |
7703 while (prevlen > 0 && prev[prevlen - 1] == '\r') | |
7704 --prevlen; | |
7705 } | |
7706 if (prevlen == 0) | |
7707 s = vim_strnsave(start, (int)len); | |
7708 else | |
7709 { | |
7710 /* Change "prev" buffer to be the right size. This way | |
7711 * the bytes are only copied once, and very long lines are | |
7712 * allocated only once. */ | |
7713 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL) | |
7714 { | |
7715 mch_memmove(s + prevlen, start, len); | |
7716 s[prevlen + len] = NUL; | |
7717 prev = NULL; /* the list will own the string */ | |
7718 prevlen = prevsize = 0; | |
7719 } | |
7720 } | |
7721 if (s == NULL) | |
7722 { | |
7723 do_outofmem_msg((long_u) prevlen + len + 1); | |
7724 failed = TRUE; | |
7725 break; | |
7726 } | |
7727 | |
7728 if ((li = listitem_alloc()) == NULL) | |
7729 { | |
7730 vim_free(s); | |
7731 failed = TRUE; | |
7732 break; | |
7733 } | |
7734 li->li_tv.v_type = VAR_STRING; | |
7735 li->li_tv.v_lock = 0; | |
7736 li->li_tv.vval.v_string = s; | |
7737 list_append(rettv->vval.v_list, li); | |
7738 | |
7739 start = p + 1; /* step over newline */ | |
7740 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0) | |
7741 break; | |
7742 } | |
7743 else if (*p == NUL) | |
7744 *p = '\n'; | |
7745 #ifdef FEAT_MBYTE | |
7746 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this | |
7747 * when finding the BF and check the previous two bytes. */ | |
7748 else if (*p == 0xbf && enc_utf8 && !binary) | |
7749 { | |
7750 /* Find the two bytes before the 0xbf. If p is at buf, or buf | |
7751 * + 1, these may be in the "prev" string. */ | |
7752 char_u back1 = p >= buf + 1 ? p[-1] | |
7753 : prevlen >= 1 ? prev[prevlen - 1] : NUL; | |
7754 char_u back2 = p >= buf + 2 ? p[-2] | |
7755 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] | |
7756 : prevlen >= 2 ? prev[prevlen - 2] : NUL; | |
7757 | |
7758 if (back2 == 0xef && back1 == 0xbb) | |
7759 { | |
7760 char_u *dest = p - 2; | |
7761 | |
7762 /* Usually a BOM is at the beginning of a file, and so at | |
7763 * the beginning of a line; then we can just step over it. | |
7764 */ | |
7765 if (start == dest) | |
7766 start = p + 1; | |
7767 else | |
7768 { | |
7769 /* have to shuffle buf to close gap */ | |
7770 int adjust_prevlen = 0; | |
7771 | |
7772 if (dest < buf) | |
7773 { | |
7774 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */ | |
7775 dest = buf; | |
7776 } | |
7777 if (readlen > p - buf + 1) | |
7778 mch_memmove(dest, p + 1, readlen - (p - buf) - 1); | |
7779 readlen -= 3 - adjust_prevlen; | |
7780 prevlen -= adjust_prevlen; | |
7781 p = dest - 1; | |
7782 } | |
7783 } | |
7784 } | |
7785 #endif | |
7786 } /* for */ | |
7787 | |
7788 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0) | |
7789 break; | |
7790 if (start < p) | |
7791 { | |
7792 /* There's part of a line in buf, store it in "prev". */ | |
7793 if (p - start + prevlen >= prevsize) | |
7794 { | |
7795 /* need bigger "prev" buffer */ | |
7796 char_u *newprev; | |
7797 | |
7798 /* A common use case is ordinary text files and "prev" gets a | |
7799 * fragment of a line, so the first allocation is made | |
7800 * small, to avoid repeatedly 'allocing' large and | |
7801 * 'reallocing' small. */ | |
7802 if (prevsize == 0) | |
7803 prevsize = (long)(p - start); | |
7804 else | |
7805 { | |
7806 long grow50pc = (prevsize * 3) / 2; | |
7807 long growmin = (long)((p - start) * 2 + prevlen); | |
7808 prevsize = grow50pc > growmin ? grow50pc : growmin; | |
7809 } | |
7810 newprev = prev == NULL ? alloc(prevsize) | |
7811 : vim_realloc(prev, prevsize); | |
7812 if (newprev == NULL) | |
7813 { | |
7814 do_outofmem_msg((long_u)prevsize); | |
7815 failed = TRUE; | |
7816 break; | |
7817 } | |
7818 prev = newprev; | |
7819 } | |
7820 /* Add the line part to end of "prev". */ | |
7821 mch_memmove(prev + prevlen, start, p - start); | |
7822 prevlen += (long)(p - start); | |
7823 } | |
7824 } /* while */ | |
7825 | |
7826 /* | |
7827 * For a negative line count use only the lines at the end of the file, | |
7828 * free the rest. | |
7829 */ | |
7830 if (!failed && maxline < 0) | |
7831 while (cnt > -maxline) | |
7832 { | |
7833 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first); | |
7834 --cnt; | |
7835 } | |
7836 | |
7837 if (failed) | |
7838 { | |
7839 list_free(rettv->vval.v_list); | |
7840 /* readfile doc says an empty list is returned on error */ | |
7841 rettv->vval.v_list = list_alloc(); | |
7842 } | |
7843 | |
7844 vim_free(prev); | |
7845 fclose(fd); | |
7846 } | |
7847 | |
7848 #if defined(FEAT_RELTIME) | |
7849 static int list2proftime(typval_T *arg, proftime_T *tm); | |
7850 | |
7851 /* | |
7852 * Convert a List to proftime_T. | |
7853 * Return FAIL when there is something wrong. | |
7854 */ | |
7855 static int | |
7856 list2proftime(typval_T *arg, proftime_T *tm) | |
7857 { | |
7858 long n1, n2; | |
7859 int error = FALSE; | |
7860 | |
7861 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL | |
7862 || arg->vval.v_list->lv_len != 2) | |
7863 return FAIL; | |
7864 n1 = list_find_nr(arg->vval.v_list, 0L, &error); | |
7865 n2 = list_find_nr(arg->vval.v_list, 1L, &error); | |
7866 # ifdef WIN3264 | |
7867 tm->HighPart = n1; | |
7868 tm->LowPart = n2; | |
7869 # else | |
7870 tm->tv_sec = n1; | |
7871 tm->tv_usec = n2; | |
7872 # endif | |
7873 return error ? FAIL : OK; | |
7874 } | |
7875 #endif /* FEAT_RELTIME */ | |
7876 | |
7877 /* | |
7878 * "reltime()" function | |
7879 */ | |
7880 static void | |
7881 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
7882 { | |
7883 #ifdef FEAT_RELTIME | |
7884 proftime_T res; | |
7885 proftime_T start; | |
7886 | |
7887 if (argvars[0].v_type == VAR_UNKNOWN) | |
7888 { | |
7889 /* No arguments: get current time. */ | |
7890 profile_start(&res); | |
7891 } | |
7892 else if (argvars[1].v_type == VAR_UNKNOWN) | |
7893 { | |
7894 if (list2proftime(&argvars[0], &res) == FAIL) | |
7895 return; | |
7896 profile_end(&res); | |
7897 } | |
7898 else | |
7899 { | |
7900 /* Two arguments: compute the difference. */ | |
7901 if (list2proftime(&argvars[0], &start) == FAIL | |
7902 || list2proftime(&argvars[1], &res) == FAIL) | |
7903 return; | |
7904 profile_sub(&res, &start); | |
7905 } | |
7906 | |
7907 if (rettv_list_alloc(rettv) == OK) | |
7908 { | |
7909 long n1, n2; | |
7910 | |
7911 # ifdef WIN3264 | |
7912 n1 = res.HighPart; | |
7913 n2 = res.LowPart; | |
7914 # else | |
7915 n1 = res.tv_sec; | |
7916 n2 = res.tv_usec; | |
7917 # endif | |
7918 list_append_number(rettv->vval.v_list, (varnumber_T)n1); | |
7919 list_append_number(rettv->vval.v_list, (varnumber_T)n2); | |
7920 } | |
7921 #endif | |
7922 } | |
7923 | |
7924 #ifdef FEAT_FLOAT | |
7925 /* | |
7926 * "reltimefloat()" function | |
7927 */ | |
7928 static void | |
7929 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) | |
7930 { | |
7931 # ifdef FEAT_RELTIME | |
7932 proftime_T tm; | |
7933 # endif | |
7934 | |
7935 rettv->v_type = VAR_FLOAT; | |
7936 rettv->vval.v_float = 0; | |
7937 # ifdef FEAT_RELTIME | |
7938 if (list2proftime(&argvars[0], &tm) == OK) | |
7939 rettv->vval.v_float = profile_float(&tm); | |
7940 # endif | |
7941 } | |
7942 #endif | |
7943 | |
7944 /* | |
7945 * "reltimestr()" function | |
7946 */ | |
7947 static void | |
7948 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) | |
7949 { | |
7950 #ifdef FEAT_RELTIME | |
7951 proftime_T tm; | |
7952 #endif | |
7953 | |
7954 rettv->v_type = VAR_STRING; | |
7955 rettv->vval.v_string = NULL; | |
7956 #ifdef FEAT_RELTIME | |
7957 if (list2proftime(&argvars[0], &tm) == OK) | |
7958 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); | |
7959 #endif | |
7960 } | |
7961 | |
7962 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) | |
7963 static void make_connection(void); | |
7964 static int check_connection(void); | |
7965 | |
7966 static void | |
7967 make_connection(void) | |
7968 { | |
7969 if (X_DISPLAY == NULL | |
7970 # ifdef FEAT_GUI | |
7971 && !gui.in_use | |
7972 # endif | |
7973 ) | |
7974 { | |
7975 x_force_connect = TRUE; | |
7976 setup_term_clip(); | |
7977 x_force_connect = FALSE; | |
7978 } | |
7979 } | |
7980 | |
7981 static int | |
7982 check_connection(void) | |
7983 { | |
7984 make_connection(); | |
7985 if (X_DISPLAY == NULL) | |
7986 { | |
7987 EMSG(_("E240: No connection to Vim server")); | |
7988 return FAIL; | |
7989 } | |
7990 return OK; | |
7991 } | |
7992 #endif | |
7993 | |
7994 #ifdef FEAT_CLIENTSERVER | |
7995 static void | |
7996 remote_common(typval_T *argvars, typval_T *rettv, int expr) | |
7997 { | |
7998 char_u *server_name; | |
7999 char_u *keys; | |
8000 char_u *r = NULL; | |
8001 char_u buf[NUMBUFLEN]; | |
8002 # ifdef WIN32 | |
8003 HWND w; | |
8004 # else | |
8005 Window w; | |
8006 # endif | |
8007 | |
8008 if (check_restricted() || check_secure()) | |
8009 return; | |
8010 | |
8011 # ifdef FEAT_X11 | |
8012 if (check_connection() == FAIL) | |
8013 return; | |
8014 # endif | |
8015 | |
8016 server_name = get_tv_string_chk(&argvars[0]); | |
8017 if (server_name == NULL) | |
8018 return; /* type error; errmsg already given */ | |
8019 keys = get_tv_string_buf(&argvars[1], buf); | |
8020 # ifdef WIN32 | |
8021 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0) | |
8022 # else | |
8023 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE) | |
8024 < 0) | |
8025 # endif | |
8026 { | |
8027 if (r != NULL) | |
8028 EMSG(r); /* sending worked but evaluation failed */ | |
8029 else | |
8030 EMSG2(_("E241: Unable to send to %s"), server_name); | |
8031 return; | |
8032 } | |
8033 | |
8034 rettv->vval.v_string = r; | |
8035 | |
8036 if (argvars[2].v_type != VAR_UNKNOWN) | |
8037 { | |
8038 dictitem_T v; | |
8039 char_u str[30]; | |
8040 char_u *idvar; | |
8041 | |
8042 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); | |
8043 v.di_tv.v_type = VAR_STRING; | |
8044 v.di_tv.vval.v_string = vim_strsave(str); | |
8045 idvar = get_tv_string_chk(&argvars[2]); | |
8046 if (idvar != NULL) | |
8047 set_var(idvar, &v.di_tv, FALSE); | |
8048 vim_free(v.di_tv.vval.v_string); | |
8049 } | |
8050 } | |
8051 #endif | |
8052 | |
8053 /* | |
8054 * "remote_expr()" function | |
8055 */ | |
8056 static void | |
8057 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) | |
8058 { | |
8059 rettv->v_type = VAR_STRING; | |
8060 rettv->vval.v_string = NULL; | |
8061 #ifdef FEAT_CLIENTSERVER | |
8062 remote_common(argvars, rettv, TRUE); | |
8063 #endif | |
8064 } | |
8065 | |
8066 /* | |
8067 * "remote_foreground()" function | |
8068 */ | |
8069 static void | |
8070 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8071 { | |
8072 #ifdef FEAT_CLIENTSERVER | |
8073 # ifdef WIN32 | |
8074 /* On Win32 it's done in this application. */ | |
8075 { | |
8076 char_u *server_name = get_tv_string_chk(&argvars[0]); | |
8077 | |
8078 if (server_name != NULL) | |
8079 serverForeground(server_name); | |
8080 } | |
8081 # else | |
8082 /* Send a foreground() expression to the server. */ | |
8083 argvars[1].v_type = VAR_STRING; | |
8084 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); | |
8085 argvars[2].v_type = VAR_UNKNOWN; | |
8086 remote_common(argvars, rettv, TRUE); | |
8087 vim_free(argvars[1].vval.v_string); | |
8088 # endif | |
8089 #endif | |
8090 } | |
8091 | |
8092 static void | |
8093 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) | |
8094 { | |
8095 #ifdef FEAT_CLIENTSERVER | |
8096 dictitem_T v; | |
8097 char_u *s = NULL; | |
8098 # ifdef WIN32 | |
8099 long_u n = 0; | |
8100 # endif | |
8101 char_u *serverid; | |
8102 | |
8103 if (check_restricted() || check_secure()) | |
8104 { | |
8105 rettv->vval.v_number = -1; | |
8106 return; | |
8107 } | |
8108 serverid = get_tv_string_chk(&argvars[0]); | |
8109 if (serverid == NULL) | |
8110 { | |
8111 rettv->vval.v_number = -1; | |
8112 return; /* type error; errmsg already given */ | |
8113 } | |
8114 # ifdef WIN32 | |
8115 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); | |
8116 if (n == 0) | |
8117 rettv->vval.v_number = -1; | |
8118 else | |
8119 { | |
8120 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE); | |
8121 rettv->vval.v_number = (s != NULL); | |
8122 } | |
8123 # else | |
8124 if (check_connection() == FAIL) | |
8125 return; | |
8126 | |
8127 rettv->vval.v_number = serverPeekReply(X_DISPLAY, | |
8128 serverStrToWin(serverid), &s); | |
8129 # endif | |
8130 | |
8131 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) | |
8132 { | |
8133 char_u *retvar; | |
8134 | |
8135 v.di_tv.v_type = VAR_STRING; | |
8136 v.di_tv.vval.v_string = vim_strsave(s); | |
8137 retvar = get_tv_string_chk(&argvars[1]); | |
8138 if (retvar != NULL) | |
8139 set_var(retvar, &v.di_tv, FALSE); | |
8140 vim_free(v.di_tv.vval.v_string); | |
8141 } | |
8142 #else | |
8143 rettv->vval.v_number = -1; | |
8144 #endif | |
8145 } | |
8146 | |
8147 static void | |
8148 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) | |
8149 { | |
8150 char_u *r = NULL; | |
8151 | |
8152 #ifdef FEAT_CLIENTSERVER | |
8153 char_u *serverid = get_tv_string_chk(&argvars[0]); | |
8154 | |
8155 if (serverid != NULL && !check_restricted() && !check_secure()) | |
8156 { | |
8157 # ifdef WIN32 | |
8158 /* The server's HWND is encoded in the 'id' parameter */ | |
8159 long_u n = 0; | |
8160 | |
8161 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); | |
8162 if (n != 0) | |
8163 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE); | |
8164 if (r == NULL) | |
8165 # else | |
8166 if (check_connection() == FAIL || serverReadReply(X_DISPLAY, | |
8167 serverStrToWin(serverid), &r, FALSE) < 0) | |
8168 # endif | |
8169 EMSG(_("E277: Unable to read a server reply")); | |
8170 } | |
8171 #endif | |
8172 rettv->v_type = VAR_STRING; | |
8173 rettv->vval.v_string = r; | |
8174 } | |
8175 | |
8176 /* | |
8177 * "remote_send()" function | |
8178 */ | |
8179 static void | |
8180 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) | |
8181 { | |
8182 rettv->v_type = VAR_STRING; | |
8183 rettv->vval.v_string = NULL; | |
8184 #ifdef FEAT_CLIENTSERVER | |
8185 remote_common(argvars, rettv, FALSE); | |
8186 #endif | |
8187 } | |
8188 | |
8189 /* | |
8190 * "remove()" function | |
8191 */ | |
8192 static void | |
8193 f_remove(typval_T *argvars, typval_T *rettv) | |
8194 { | |
8195 list_T *l; | |
8196 listitem_T *item, *item2; | |
8197 listitem_T *li; | |
8198 long idx; | |
8199 long end; | |
8200 char_u *key; | |
8201 dict_T *d; | |
8202 dictitem_T *di; | |
8203 char_u *arg_errmsg = (char_u *)N_("remove() argument"); | |
8204 | |
8205 if (argvars[0].v_type == VAR_DICT) | |
8206 { | |
8207 if (argvars[2].v_type != VAR_UNKNOWN) | |
8208 EMSG2(_(e_toomanyarg), "remove()"); | |
8209 else if ((d = argvars[0].vval.v_dict) != NULL | |
8210 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE)) | |
8211 { | |
8212 key = get_tv_string_chk(&argvars[1]); | |
8213 if (key != NULL) | |
8214 { | |
8215 di = dict_find(d, key, -1); | |
8216 if (di == NULL) | |
8217 EMSG2(_(e_dictkey), key); | |
8218 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE) | |
8219 && !var_check_ro(di->di_flags, arg_errmsg, TRUE)) | |
8220 { | |
8221 *rettv = di->di_tv; | |
8222 init_tv(&di->di_tv); | |
8223 dictitem_remove(d, di); | |
8224 } | |
8225 } | |
8226 } | |
8227 } | |
8228 else if (argvars[0].v_type != VAR_LIST) | |
8229 EMSG2(_(e_listdictarg), "remove()"); | |
8230 else if ((l = argvars[0].vval.v_list) != NULL | |
8231 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE)) | |
8232 { | |
8233 int error = FALSE; | |
8234 | |
8235 idx = (long)get_tv_number_chk(&argvars[1], &error); | |
8236 if (error) | |
8237 ; /* type error: do nothing, errmsg already given */ | |
8238 else if ((item = list_find(l, idx)) == NULL) | |
8239 EMSGN(_(e_listidx), idx); | |
8240 else | |
8241 { | |
8242 if (argvars[2].v_type == VAR_UNKNOWN) | |
8243 { | |
8244 /* Remove one item, return its value. */ | |
8245 vimlist_remove(l, item, item); | |
8246 *rettv = item->li_tv; | |
8247 vim_free(item); | |
8248 } | |
8249 else | |
8250 { | |
8251 /* Remove range of items, return list with values. */ | |
8252 end = (long)get_tv_number_chk(&argvars[2], &error); | |
8253 if (error) | |
8254 ; /* type error: do nothing */ | |
8255 else if ((item2 = list_find(l, end)) == NULL) | |
8256 EMSGN(_(e_listidx), end); | |
8257 else | |
8258 { | |
8259 int cnt = 0; | |
8260 | |
8261 for (li = item; li != NULL; li = li->li_next) | |
8262 { | |
8263 ++cnt; | |
8264 if (li == item2) | |
8265 break; | |
8266 } | |
8267 if (li == NULL) /* didn't find "item2" after "item" */ | |
8268 EMSG(_(e_invrange)); | |
8269 else | |
8270 { | |
8271 vimlist_remove(l, item, item2); | |
8272 if (rettv_list_alloc(rettv) == OK) | |
8273 { | |
8274 l = rettv->vval.v_list; | |
8275 l->lv_first = item; | |
8276 l->lv_last = item2; | |
8277 item->li_prev = NULL; | |
8278 item2->li_next = NULL; | |
8279 l->lv_len = cnt; | |
8280 } | |
8281 } | |
8282 } | |
8283 } | |
8284 } | |
8285 } | |
8286 } | |
8287 | |
8288 /* | |
8289 * "rename({from}, {to})" function | |
8290 */ | |
8291 static void | |
8292 f_rename(typval_T *argvars, typval_T *rettv) | |
8293 { | |
8294 char_u buf[NUMBUFLEN]; | |
8295 | |
8296 if (check_restricted() || check_secure()) | |
8297 rettv->vval.v_number = -1; | |
8298 else | |
8299 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]), | |
8300 get_tv_string_buf(&argvars[1], buf)); | |
8301 } | |
8302 | |
8303 /* | |
8304 * "repeat()" function | |
8305 */ | |
8306 static void | |
8307 f_repeat(typval_T *argvars, typval_T *rettv) | |
8308 { | |
8309 char_u *p; | |
8310 int n; | |
8311 int slen; | |
8312 int len; | |
8313 char_u *r; | |
8314 int i; | |
8315 | |
8316 n = (int)get_tv_number(&argvars[1]); | |
8317 if (argvars[0].v_type == VAR_LIST) | |
8318 { | |
8319 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL) | |
8320 while (n-- > 0) | |
8321 if (list_extend(rettv->vval.v_list, | |
8322 argvars[0].vval.v_list, NULL) == FAIL) | |
8323 break; | |
8324 } | |
8325 else | |
8326 { | |
8327 p = get_tv_string(&argvars[0]); | |
8328 rettv->v_type = VAR_STRING; | |
8329 rettv->vval.v_string = NULL; | |
8330 | |
8331 slen = (int)STRLEN(p); | |
8332 len = slen * n; | |
8333 if (len <= 0) | |
8334 return; | |
8335 | |
8336 r = alloc(len + 1); | |
8337 if (r != NULL) | |
8338 { | |
8339 for (i = 0; i < n; i++) | |
8340 mch_memmove(r + i * slen, p, (size_t)slen); | |
8341 r[len] = NUL; | |
8342 } | |
8343 | |
8344 rettv->vval.v_string = r; | |
8345 } | |
8346 } | |
8347 | |
8348 /* | |
8349 * "resolve()" function | |
8350 */ | |
8351 static void | |
8352 f_resolve(typval_T *argvars, typval_T *rettv) | |
8353 { | |
8354 char_u *p; | |
8355 #ifdef HAVE_READLINK | |
8356 char_u *buf = NULL; | |
8357 #endif | |
8358 | |
8359 p = get_tv_string(&argvars[0]); | |
8360 #ifdef FEAT_SHORTCUT | |
8361 { | |
8362 char_u *v = NULL; | |
8363 | |
8364 v = mch_resolve_shortcut(p); | |
8365 if (v != NULL) | |
8366 rettv->vval.v_string = v; | |
8367 else | |
8368 rettv->vval.v_string = vim_strsave(p); | |
8369 } | |
8370 #else | |
8371 # ifdef HAVE_READLINK | |
8372 { | |
8373 char_u *cpy; | |
8374 int len; | |
8375 char_u *remain = NULL; | |
8376 char_u *q; | |
8377 int is_relative_to_current = FALSE; | |
8378 int has_trailing_pathsep = FALSE; | |
8379 int limit = 100; | |
8380 | |
8381 p = vim_strsave(p); | |
8382 | |
8383 if (p[0] == '.' && (vim_ispathsep(p[1]) | |
8384 || (p[1] == '.' && (vim_ispathsep(p[2]))))) | |
8385 is_relative_to_current = TRUE; | |
8386 | |
8387 len = STRLEN(p); | |
8388 if (len > 0 && after_pathsep(p, p + len)) | |
8389 { | |
8390 has_trailing_pathsep = TRUE; | |
8391 p[len - 1] = NUL; /* the trailing slash breaks readlink() */ | |
8392 } | |
8393 | |
8394 q = getnextcomp(p); | |
8395 if (*q != NUL) | |
8396 { | |
8397 /* Separate the first path component in "p", and keep the | |
8398 * remainder (beginning with the path separator). */ | |
8399 remain = vim_strsave(q - 1); | |
8400 q[-1] = NUL; | |
8401 } | |
8402 | |
8403 buf = alloc(MAXPATHL + 1); | |
8404 if (buf == NULL) | |
8405 goto fail; | |
8406 | |
8407 for (;;) | |
8408 { | |
8409 for (;;) | |
8410 { | |
8411 len = readlink((char *)p, (char *)buf, MAXPATHL); | |
8412 if (len <= 0) | |
8413 break; | |
8414 buf[len] = NUL; | |
8415 | |
8416 if (limit-- == 0) | |
8417 { | |
8418 vim_free(p); | |
8419 vim_free(remain); | |
8420 EMSG(_("E655: Too many symbolic links (cycle?)")); | |
8421 rettv->vval.v_string = NULL; | |
8422 goto fail; | |
8423 } | |
8424 | |
8425 /* Ensure that the result will have a trailing path separator | |
8426 * if the argument has one. */ | |
8427 if (remain == NULL && has_trailing_pathsep) | |
8428 add_pathsep(buf); | |
8429 | |
8430 /* Separate the first path component in the link value and | |
8431 * concatenate the remainders. */ | |
8432 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf); | |
8433 if (*q != NUL) | |
8434 { | |
8435 if (remain == NULL) | |
8436 remain = vim_strsave(q - 1); | |
8437 else | |
8438 { | |
8439 cpy = concat_str(q - 1, remain); | |
8440 if (cpy != NULL) | |
8441 { | |
8442 vim_free(remain); | |
8443 remain = cpy; | |
8444 } | |
8445 } | |
8446 q[-1] = NUL; | |
8447 } | |
8448 | |
8449 q = gettail(p); | |
8450 if (q > p && *q == NUL) | |
8451 { | |
8452 /* Ignore trailing path separator. */ | |
8453 q[-1] = NUL; | |
8454 q = gettail(p); | |
8455 } | |
8456 if (q > p && !mch_isFullName(buf)) | |
8457 { | |
8458 /* symlink is relative to directory of argument */ | |
8459 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1)); | |
8460 if (cpy != NULL) | |
8461 { | |
8462 STRCPY(cpy, p); | |
8463 STRCPY(gettail(cpy), buf); | |
8464 vim_free(p); | |
8465 p = cpy; | |
8466 } | |
8467 } | |
8468 else | |
8469 { | |
8470 vim_free(p); | |
8471 p = vim_strsave(buf); | |
8472 } | |
8473 } | |
8474 | |
8475 if (remain == NULL) | |
8476 break; | |
8477 | |
8478 /* Append the first path component of "remain" to "p". */ | |
8479 q = getnextcomp(remain + 1); | |
8480 len = q - remain - (*q != NUL); | |
8481 cpy = vim_strnsave(p, STRLEN(p) + len); | |
8482 if (cpy != NULL) | |
8483 { | |
8484 STRNCAT(cpy, remain, len); | |
8485 vim_free(p); | |
8486 p = cpy; | |
8487 } | |
8488 /* Shorten "remain". */ | |
8489 if (*q != NUL) | |
8490 STRMOVE(remain, q - 1); | |
8491 else | |
8492 { | |
8493 vim_free(remain); | |
8494 remain = NULL; | |
8495 } | |
8496 } | |
8497 | |
8498 /* If the result is a relative path name, make it explicitly relative to | |
8499 * the current directory if and only if the argument had this form. */ | |
8500 if (!vim_ispathsep(*p)) | |
8501 { | |
8502 if (is_relative_to_current | |
8503 && *p != NUL | |
8504 && !(p[0] == '.' | |
8505 && (p[1] == NUL | |
8506 || vim_ispathsep(p[1]) | |
8507 || (p[1] == '.' | |
8508 && (p[2] == NUL | |
8509 || vim_ispathsep(p[2])))))) | |
8510 { | |
8511 /* Prepend "./". */ | |
8512 cpy = concat_str((char_u *)"./", p); | |
8513 if (cpy != NULL) | |
8514 { | |
8515 vim_free(p); | |
8516 p = cpy; | |
8517 } | |
8518 } | |
8519 else if (!is_relative_to_current) | |
8520 { | |
8521 /* Strip leading "./". */ | |
8522 q = p; | |
8523 while (q[0] == '.' && vim_ispathsep(q[1])) | |
8524 q += 2; | |
8525 if (q > p) | |
8526 STRMOVE(p, p + 2); | |
8527 } | |
8528 } | |
8529 | |
8530 /* Ensure that the result will have no trailing path separator | |
8531 * if the argument had none. But keep "/" or "//". */ | |
8532 if (!has_trailing_pathsep) | |
8533 { | |
8534 q = p + STRLEN(p); | |
8535 if (after_pathsep(p, q)) | |
8536 *gettail_sep(p) = NUL; | |
8537 } | |
8538 | |
8539 rettv->vval.v_string = p; | |
8540 } | |
8541 # else | |
8542 rettv->vval.v_string = vim_strsave(p); | |
8543 # endif | |
8544 #endif | |
8545 | |
8546 simplify_filename(rettv->vval.v_string); | |
8547 | |
8548 #ifdef HAVE_READLINK | |
8549 fail: | |
8550 vim_free(buf); | |
8551 #endif | |
8552 rettv->v_type = VAR_STRING; | |
8553 } | |
8554 | |
8555 /* | |
8556 * "reverse({list})" function | |
8557 */ | |
8558 static void | |
8559 f_reverse(typval_T *argvars, typval_T *rettv) | |
8560 { | |
8561 list_T *l; | |
8562 listitem_T *li, *ni; | |
8563 | |
8564 if (argvars[0].v_type != VAR_LIST) | |
8565 EMSG2(_(e_listarg), "reverse()"); | |
8566 else if ((l = argvars[0].vval.v_list) != NULL | |
8567 && !tv_check_lock(l->lv_lock, | |
8568 (char_u *)N_("reverse() argument"), TRUE)) | |
8569 { | |
8570 li = l->lv_last; | |
8571 l->lv_first = l->lv_last = NULL; | |
8572 l->lv_len = 0; | |
8573 while (li != NULL) | |
8574 { | |
8575 ni = li->li_prev; | |
8576 list_append(l, li); | |
8577 li = ni; | |
8578 } | |
8579 rettv->vval.v_list = l; | |
8580 rettv->v_type = VAR_LIST; | |
8581 ++l->lv_refcount; | |
8582 l->lv_idx = l->lv_len - l->lv_idx - 1; | |
8583 } | |
8584 } | |
8585 | |
8586 #define SP_NOMOVE 0x01 /* don't move cursor */ | |
8587 #define SP_REPEAT 0x02 /* repeat to find outer pair */ | |
8588 #define SP_RETCOUNT 0x04 /* return matchcount */ | |
8589 #define SP_SETPCMARK 0x08 /* set previous context mark */ | |
8590 #define SP_START 0x10 /* accept match at start position */ | |
8591 #define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ | |
8592 #define SP_END 0x40 /* leave cursor at end of match */ | |
8593 #define SP_COLUMN 0x80 /* start at cursor column */ | |
8594 | |
8595 static int get_search_arg(typval_T *varp, int *flagsp); | |
8596 | |
8597 /* | |
8598 * Get flags for a search function. | |
8599 * Possibly sets "p_ws". | |
8600 * Returns BACKWARD, FORWARD or zero (for an error). | |
8601 */ | |
8602 static int | |
8603 get_search_arg(typval_T *varp, int *flagsp) | |
8604 { | |
8605 int dir = FORWARD; | |
8606 char_u *flags; | |
8607 char_u nbuf[NUMBUFLEN]; | |
8608 int mask; | |
8609 | |
8610 if (varp->v_type != VAR_UNKNOWN) | |
8611 { | |
8612 flags = get_tv_string_buf_chk(varp, nbuf); | |
8613 if (flags == NULL) | |
8614 return 0; /* type error; errmsg already given */ | |
8615 while (*flags != NUL) | |
8616 { | |
8617 switch (*flags) | |
8618 { | |
8619 case 'b': dir = BACKWARD; break; | |
8620 case 'w': p_ws = TRUE; break; | |
8621 case 'W': p_ws = FALSE; break; | |
8622 default: mask = 0; | |
8623 if (flagsp != NULL) | |
8624 switch (*flags) | |
8625 { | |
8626 case 'c': mask = SP_START; break; | |
8627 case 'e': mask = SP_END; break; | |
8628 case 'm': mask = SP_RETCOUNT; break; | |
8629 case 'n': mask = SP_NOMOVE; break; | |
8630 case 'p': mask = SP_SUBPAT; break; | |
8631 case 'r': mask = SP_REPEAT; break; | |
8632 case 's': mask = SP_SETPCMARK; break; | |
8633 case 'z': mask = SP_COLUMN; break; | |
8634 } | |
8635 if (mask == 0) | |
8636 { | |
8637 EMSG2(_(e_invarg2), flags); | |
8638 dir = 0; | |
8639 } | |
8640 else | |
8641 *flagsp |= mask; | |
8642 } | |
8643 if (dir == 0) | |
8644 break; | |
8645 ++flags; | |
8646 } | |
8647 } | |
8648 return dir; | |
8649 } | |
8650 | |
8651 /* | |
8652 * Shared by search() and searchpos() functions. | |
8653 */ | |
8654 static int | |
8655 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) | |
8656 { | |
8657 int flags; | |
8658 char_u *pat; | |
8659 pos_T pos; | |
8660 pos_T save_cursor; | |
8661 int save_p_ws = p_ws; | |
8662 int dir; | |
8663 int retval = 0; /* default: FAIL */ | |
8664 long lnum_stop = 0; | |
8665 proftime_T tm; | |
8666 #ifdef FEAT_RELTIME | |
8667 long time_limit = 0; | |
8668 #endif | |
8669 int options = SEARCH_KEEP; | |
8670 int subpatnum; | |
8671 | |
8672 pat = get_tv_string(&argvars[0]); | |
8673 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */ | |
8674 if (dir == 0) | |
8675 goto theend; | |
8676 flags = *flagsp; | |
8677 if (flags & SP_START) | |
8678 options |= SEARCH_START; | |
8679 if (flags & SP_END) | |
8680 options |= SEARCH_END; | |
8681 if (flags & SP_COLUMN) | |
8682 options |= SEARCH_COL; | |
8683 | |
8684 /* Optional arguments: line number to stop searching and timeout. */ | |
8685 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) | |
8686 { | |
8687 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL); | |
8688 if (lnum_stop < 0) | |
8689 goto theend; | |
8690 #ifdef FEAT_RELTIME | |
8691 if (argvars[3].v_type != VAR_UNKNOWN) | |
8692 { | |
8693 time_limit = (long)get_tv_number_chk(&argvars[3], NULL); | |
8694 if (time_limit < 0) | |
8695 goto theend; | |
8696 } | |
8697 #endif | |
8698 } | |
8699 | |
8700 #ifdef FEAT_RELTIME | |
8701 /* Set the time limit, if there is one. */ | |
8702 profile_setlimit(time_limit, &tm); | |
8703 #endif | |
8704 | |
8705 /* | |
8706 * This function does not accept SP_REPEAT and SP_RETCOUNT flags. | |
8707 * Check to make sure only those flags are set. | |
8708 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both | |
8709 * flags cannot be set. Check for that condition also. | |
8710 */ | |
8711 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0) | |
8712 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) | |
8713 { | |
8714 EMSG2(_(e_invarg2), get_tv_string(&argvars[1])); | |
8715 goto theend; | |
8716 } | |
8717 | |
8718 pos = save_cursor = curwin->w_cursor; | |
8719 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L, | |
8720 options, RE_SEARCH, (linenr_T)lnum_stop, &tm); | |
8721 if (subpatnum != FAIL) | |
8722 { | |
8723 if (flags & SP_SUBPAT) | |
8724 retval = subpatnum; | |
8725 else | |
8726 retval = pos.lnum; | |
8727 if (flags & SP_SETPCMARK) | |
8728 setpcmark(); | |
8729 curwin->w_cursor = pos; | |
8730 if (match_pos != NULL) | |
8731 { | |
8732 /* Store the match cursor position */ | |
8733 match_pos->lnum = pos.lnum; | |
8734 match_pos->col = pos.col + 1; | |
8735 } | |
8736 /* "/$" will put the cursor after the end of the line, may need to | |
8737 * correct that here */ | |
8738 check_cursor(); | |
8739 } | |
8740 | |
8741 /* If 'n' flag is used: restore cursor position. */ | |
8742 if (flags & SP_NOMOVE) | |
8743 curwin->w_cursor = save_cursor; | |
8744 else | |
8745 curwin->w_set_curswant = TRUE; | |
8746 theend: | |
8747 p_ws = save_p_ws; | |
8748 | |
8749 return retval; | |
8750 } | |
8751 | |
8752 #ifdef FEAT_FLOAT | |
8753 | |
8754 /* | |
8755 * round() is not in C90, use ceil() or floor() instead. | |
8756 */ | |
8757 float_T | |
8758 vim_round(float_T f) | |
8759 { | |
8760 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); | |
8761 } | |
8762 | |
8763 /* | |
8764 * "round({float})" function | |
8765 */ | |
8766 static void | |
8767 f_round(typval_T *argvars, typval_T *rettv) | |
8768 { | |
8769 float_T f = 0.0; | |
8770 | |
8771 rettv->v_type = VAR_FLOAT; | |
8772 if (get_float_arg(argvars, &f) == OK) | |
8773 rettv->vval.v_float = vim_round(f); | |
8774 else | |
8775 rettv->vval.v_float = 0.0; | |
8776 } | |
8777 #endif | |
8778 | |
8779 /* | |
8780 * "screenattr()" function | |
8781 */ | |
8782 static void | |
8783 f_screenattr(typval_T *argvars, typval_T *rettv) | |
8784 { | |
8785 int row; | |
8786 int col; | |
8787 int c; | |
8788 | |
8789 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; | |
8790 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; | |
8791 if (row < 0 || row >= screen_Rows | |
8792 || col < 0 || col >= screen_Columns) | |
8793 c = -1; | |
8794 else | |
8795 c = ScreenAttrs[LineOffset[row] + col]; | |
8796 rettv->vval.v_number = c; | |
8797 } | |
8798 | |
8799 /* | |
8800 * "screenchar()" function | |
8801 */ | |
8802 static void | |
8803 f_screenchar(typval_T *argvars, typval_T *rettv) | |
8804 { | |
8805 int row; | |
8806 int col; | |
8807 int off; | |
8808 int c; | |
8809 | |
8810 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; | |
8811 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; | |
8812 if (row < 0 || row >= screen_Rows | |
8813 || col < 0 || col >= screen_Columns) | |
8814 c = -1; | |
8815 else | |
8816 { | |
8817 off = LineOffset[row] + col; | |
8818 #ifdef FEAT_MBYTE | |
8819 if (enc_utf8 && ScreenLinesUC[off] != 0) | |
8820 c = ScreenLinesUC[off]; | |
8821 else | |
8822 #endif | |
8823 c = ScreenLines[off]; | |
8824 } | |
8825 rettv->vval.v_number = c; | |
8826 } | |
8827 | |
8828 /* | |
8829 * "screencol()" function | |
8830 * | |
8831 * First column is 1 to be consistent with virtcol(). | |
8832 */ | |
8833 static void | |
8834 f_screencol(typval_T *argvars UNUSED, typval_T *rettv) | |
8835 { | |
8836 rettv->vval.v_number = screen_screencol() + 1; | |
8837 } | |
8838 | |
8839 /* | |
8840 * "screenrow()" function | |
8841 */ | |
8842 static void | |
8843 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv) | |
8844 { | |
8845 rettv->vval.v_number = screen_screenrow() + 1; | |
8846 } | |
8847 | |
8848 /* | |
8849 * "search()" function | |
8850 */ | |
8851 static void | |
8852 f_search(typval_T *argvars, typval_T *rettv) | |
8853 { | |
8854 int flags = 0; | |
8855 | |
8856 rettv->vval.v_number = search_cmn(argvars, NULL, &flags); | |
8857 } | |
8858 | |
8859 /* | |
8860 * "searchdecl()" function | |
8861 */ | |
8862 static void | |
8863 f_searchdecl(typval_T *argvars, typval_T *rettv) | |
8864 { | |
8865 int locally = 1; | |
8866 int thisblock = 0; | |
8867 int error = FALSE; | |
8868 char_u *name; | |
8869 | |
8870 rettv->vval.v_number = 1; /* default: FAIL */ | |
8871 | |
8872 name = get_tv_string_chk(&argvars[0]); | |
8873 if (argvars[1].v_type != VAR_UNKNOWN) | |
8874 { | |
8875 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0; | |
8876 if (!error && argvars[2].v_type != VAR_UNKNOWN) | |
8877 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0; | |
8878 } | |
8879 if (!error && name != NULL) | |
8880 rettv->vval.v_number = find_decl(name, (int)STRLEN(name), | |
8881 locally, thisblock, SEARCH_KEEP) == FAIL; | |
8882 } | |
8883 | |
8884 /* | |
8885 * Used by searchpair() and searchpairpos() | |
8886 */ | |
8887 static int | |
8888 searchpair_cmn(typval_T *argvars, pos_T *match_pos) | |
8889 { | |
8890 char_u *spat, *mpat, *epat; | |
8891 char_u *skip; | |
8892 int save_p_ws = p_ws; | |
8893 int dir; | |
8894 int flags = 0; | |
8895 char_u nbuf1[NUMBUFLEN]; | |
8896 char_u nbuf2[NUMBUFLEN]; | |
8897 char_u nbuf3[NUMBUFLEN]; | |
8898 int retval = 0; /* default: FAIL */ | |
8899 long lnum_stop = 0; | |
8900 long time_limit = 0; | |
8901 | |
8902 /* Get the three pattern arguments: start, middle, end. */ | |
8903 spat = get_tv_string_chk(&argvars[0]); | |
8904 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1); | |
8905 epat = get_tv_string_buf_chk(&argvars[2], nbuf2); | |
8906 if (spat == NULL || mpat == NULL || epat == NULL) | |
8907 goto theend; /* type error */ | |
8908 | |
8909 /* Handle the optional fourth argument: flags */ | |
8910 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */ | |
8911 if (dir == 0) | |
8912 goto theend; | |
8913 | |
8914 /* Don't accept SP_END or SP_SUBPAT. | |
8915 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set. | |
8916 */ | |
8917 if ((flags & (SP_END | SP_SUBPAT)) != 0 | |
8918 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) | |
8919 { | |
8920 EMSG2(_(e_invarg2), get_tv_string(&argvars[3])); | |
8921 goto theend; | |
8922 } | |
8923 | |
8924 /* Using 'r' implies 'W', otherwise it doesn't work. */ | |
8925 if (flags & SP_REPEAT) | |
8926 p_ws = FALSE; | |
8927 | |
8928 /* Optional fifth argument: skip expression */ | |
8929 if (argvars[3].v_type == VAR_UNKNOWN | |
8930 || argvars[4].v_type == VAR_UNKNOWN) | |
8931 skip = (char_u *)""; | |
8932 else | |
8933 { | |
8934 skip = get_tv_string_buf_chk(&argvars[4], nbuf3); | |
8935 if (argvars[5].v_type != VAR_UNKNOWN) | |
8936 { | |
8937 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL); | |
8938 if (lnum_stop < 0) | |
8939 goto theend; | |
8940 #ifdef FEAT_RELTIME | |
8941 if (argvars[6].v_type != VAR_UNKNOWN) | |
8942 { | |
8943 time_limit = (long)get_tv_number_chk(&argvars[6], NULL); | |
8944 if (time_limit < 0) | |
8945 goto theend; | |
8946 } | |
8947 #endif | |
8948 } | |
8949 } | |
8950 if (skip == NULL) | |
8951 goto theend; /* type error */ | |
8952 | |
8953 retval = do_searchpair(spat, mpat, epat, dir, skip, flags, | |
8954 match_pos, lnum_stop, time_limit); | |
8955 | |
8956 theend: | |
8957 p_ws = save_p_ws; | |
8958 | |
8959 return retval; | |
8960 } | |
8961 | |
8962 /* | |
8963 * "searchpair()" function | |
8964 */ | |
8965 static void | |
8966 f_searchpair(typval_T *argvars, typval_T *rettv) | |
8967 { | |
8968 rettv->vval.v_number = searchpair_cmn(argvars, NULL); | |
8969 } | |
8970 | |
8971 /* | |
8972 * "searchpairpos()" function | |
8973 */ | |
8974 static void | |
8975 f_searchpairpos(typval_T *argvars, typval_T *rettv) | |
8976 { | |
8977 pos_T match_pos; | |
8978 int lnum = 0; | |
8979 int col = 0; | |
8980 | |
8981 if (rettv_list_alloc(rettv) == FAIL) | |
8982 return; | |
8983 | |
8984 if (searchpair_cmn(argvars, &match_pos) > 0) | |
8985 { | |
8986 lnum = match_pos.lnum; | |
8987 col = match_pos.col; | |
8988 } | |
8989 | |
8990 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); | |
8991 list_append_number(rettv->vval.v_list, (varnumber_T)col); | |
8992 } | |
8993 | |
8994 /* | |
8995 * Search for a start/middle/end thing. | |
8996 * Used by searchpair(), see its documentation for the details. | |
8997 * Returns 0 or -1 for no match, | |
8998 */ | |
8999 long | |
9000 do_searchpair( | |
9001 char_u *spat, /* start pattern */ | |
9002 char_u *mpat, /* middle pattern */ | |
9003 char_u *epat, /* end pattern */ | |
9004 int dir, /* BACKWARD or FORWARD */ | |
9005 char_u *skip, /* skip expression */ | |
9006 int flags, /* SP_SETPCMARK and other SP_ values */ | |
9007 pos_T *match_pos, | |
9008 linenr_T lnum_stop, /* stop at this line if not zero */ | |
9009 long time_limit UNUSED) /* stop after this many msec */ | |
9010 { | |
9011 char_u *save_cpo; | |
9012 char_u *pat, *pat2 = NULL, *pat3 = NULL; | |
9013 long retval = 0; | |
9014 pos_T pos; | |
9015 pos_T firstpos; | |
9016 pos_T foundpos; | |
9017 pos_T save_cursor; | |
9018 pos_T save_pos; | |
9019 int n; | |
9020 int r; | |
9021 int nest = 1; | |
9022 int err; | |
9023 int options = SEARCH_KEEP; | |
9024 proftime_T tm; | |
9025 | |
9026 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
9027 save_cpo = p_cpo; | |
9028 p_cpo = empty_option; | |
9029 | |
9030 #ifdef FEAT_RELTIME | |
9031 /* Set the time limit, if there is one. */ | |
9032 profile_setlimit(time_limit, &tm); | |
9033 #endif | |
9034 | |
9035 /* Make two search patterns: start/end (pat2, for in nested pairs) and | |
9036 * start/middle/end (pat3, for the top pair). */ | |
9037 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15)); | |
9038 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23)); | |
9039 if (pat2 == NULL || pat3 == NULL) | |
9040 goto theend; | |
9041 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); | |
9042 if (*mpat == NUL) | |
9043 STRCPY(pat3, pat2); | |
9044 else | |
9045 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", | |
9046 spat, epat, mpat); | |
9047 if (flags & SP_START) | |
9048 options |= SEARCH_START; | |
9049 | |
9050 save_cursor = curwin->w_cursor; | |
9051 pos = curwin->w_cursor; | |
9052 clearpos(&firstpos); | |
9053 clearpos(&foundpos); | |
9054 pat = pat3; | |
9055 for (;;) | |
9056 { | |
9057 n = searchit(curwin, curbuf, &pos, dir, pat, 1L, | |
9058 options, RE_SEARCH, lnum_stop, &tm); | |
9059 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) | |
9060 /* didn't find it or found the first match again: FAIL */ | |
9061 break; | |
9062 | |
9063 if (firstpos.lnum == 0) | |
9064 firstpos = pos; | |
9065 if (equalpos(pos, foundpos)) | |
9066 { | |
9067 /* Found the same position again. Can happen with a pattern that | |
9068 * has "\zs" at the end and searching backwards. Advance one | |
9069 * character and try again. */ | |
9070 if (dir == BACKWARD) | |
9071 decl(&pos); | |
9072 else | |
9073 incl(&pos); | |
9074 } | |
9075 foundpos = pos; | |
9076 | |
9077 /* clear the start flag to avoid getting stuck here */ | |
9078 options &= ~SEARCH_START; | |
9079 | |
9080 /* If the skip pattern matches, ignore this match. */ | |
9081 if (*skip != NUL) | |
9082 { | |
9083 save_pos = curwin->w_cursor; | |
9084 curwin->w_cursor = pos; | |
9085 r = eval_to_bool(skip, &err, NULL, FALSE); | |
9086 curwin->w_cursor = save_pos; | |
9087 if (err) | |
9088 { | |
9089 /* Evaluating {skip} caused an error, break here. */ | |
9090 curwin->w_cursor = save_cursor; | |
9091 retval = -1; | |
9092 break; | |
9093 } | |
9094 if (r) | |
9095 continue; | |
9096 } | |
9097 | |
9098 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) | |
9099 { | |
9100 /* Found end when searching backwards or start when searching | |
9101 * forward: nested pair. */ | |
9102 ++nest; | |
9103 pat = pat2; /* nested, don't search for middle */ | |
9104 } | |
9105 else | |
9106 { | |
9107 /* Found end when searching forward or start when searching | |
9108 * backward: end of (nested) pair; or found middle in outer pair. */ | |
9109 if (--nest == 1) | |
9110 pat = pat3; /* outer level, search for middle */ | |
9111 } | |
9112 | |
9113 if (nest == 0) | |
9114 { | |
9115 /* Found the match: return matchcount or line number. */ | |
9116 if (flags & SP_RETCOUNT) | |
9117 ++retval; | |
9118 else | |
9119 retval = pos.lnum; | |
9120 if (flags & SP_SETPCMARK) | |
9121 setpcmark(); | |
9122 curwin->w_cursor = pos; | |
9123 if (!(flags & SP_REPEAT)) | |
9124 break; | |
9125 nest = 1; /* search for next unmatched */ | |
9126 } | |
9127 } | |
9128 | |
9129 if (match_pos != NULL) | |
9130 { | |
9131 /* Store the match cursor position */ | |
9132 match_pos->lnum = curwin->w_cursor.lnum; | |
9133 match_pos->col = curwin->w_cursor.col + 1; | |
9134 } | |
9135 | |
9136 /* If 'n' flag is used or search failed: restore cursor position. */ | |
9137 if ((flags & SP_NOMOVE) || retval == 0) | |
9138 curwin->w_cursor = save_cursor; | |
9139 | |
9140 theend: | |
9141 vim_free(pat2); | |
9142 vim_free(pat3); | |
9143 if (p_cpo == empty_option) | |
9144 p_cpo = save_cpo; | |
9145 else | |
9146 /* Darn, evaluating the {skip} expression changed the value. */ | |
9147 free_string_option(save_cpo); | |
9148 | |
9149 return retval; | |
9150 } | |
9151 | |
9152 /* | |
9153 * "searchpos()" function | |
9154 */ | |
9155 static void | |
9156 f_searchpos(typval_T *argvars, typval_T *rettv) | |
9157 { | |
9158 pos_T match_pos; | |
9159 int lnum = 0; | |
9160 int col = 0; | |
9161 int n; | |
9162 int flags = 0; | |
9163 | |
9164 if (rettv_list_alloc(rettv) == FAIL) | |
9165 return; | |
9166 | |
9167 n = search_cmn(argvars, &match_pos, &flags); | |
9168 if (n > 0) | |
9169 { | |
9170 lnum = match_pos.lnum; | |
9171 col = match_pos.col; | |
9172 } | |
9173 | |
9174 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); | |
9175 list_append_number(rettv->vval.v_list, (varnumber_T)col); | |
9176 if (flags & SP_SUBPAT) | |
9177 list_append_number(rettv->vval.v_list, (varnumber_T)n); | |
9178 } | |
9179 | |
9180 static void | |
9181 f_server2client(typval_T *argvars UNUSED, typval_T *rettv) | |
9182 { | |
9183 #ifdef FEAT_CLIENTSERVER | |
9184 char_u buf[NUMBUFLEN]; | |
9185 char_u *server = get_tv_string_chk(&argvars[0]); | |
9186 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf); | |
9187 | |
9188 rettv->vval.v_number = -1; | |
9189 if (server == NULL || reply == NULL) | |
9190 return; | |
9191 if (check_restricted() || check_secure()) | |
9192 return; | |
9193 # ifdef FEAT_X11 | |
9194 if (check_connection() == FAIL) | |
9195 return; | |
9196 # endif | |
9197 | |
9198 if (serverSendReply(server, reply) < 0) | |
9199 { | |
9200 EMSG(_("E258: Unable to send to client")); | |
9201 return; | |
9202 } | |
9203 rettv->vval.v_number = 0; | |
9204 #else | |
9205 rettv->vval.v_number = -1; | |
9206 #endif | |
9207 } | |
9208 | |
9209 static void | |
9210 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) | |
9211 { | |
9212 char_u *r = NULL; | |
9213 | |
9214 #ifdef FEAT_CLIENTSERVER | |
9215 # ifdef WIN32 | |
9216 r = serverGetVimNames(); | |
9217 # else | |
9218 make_connection(); | |
9219 if (X_DISPLAY != NULL) | |
9220 r = serverGetVimNames(X_DISPLAY); | |
9221 # endif | |
9222 #endif | |
9223 rettv->v_type = VAR_STRING; | |
9224 rettv->vval.v_string = r; | |
9225 } | |
9226 | |
9227 /* | |
9228 * "setbufvar()" function | |
9229 */ | |
9230 static void | |
9231 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED) | |
9232 { | |
9233 buf_T *buf; | |
9234 char_u *varname, *bufvarname; | |
9235 typval_T *varp; | |
9236 char_u nbuf[NUMBUFLEN]; | |
9237 | |
9238 if (check_restricted() || check_secure()) | |
9239 return; | |
9240 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
9241 varname = get_tv_string_chk(&argvars[1]); | |
9242 buf = get_buf_tv(&argvars[0], FALSE); | |
9243 varp = &argvars[2]; | |
9244 | |
9245 if (buf != NULL && varname != NULL && varp != NULL) | |
9246 { | |
9247 if (*varname == '&') | |
9248 { | |
9249 long numval; | |
9250 char_u *strval; | |
9251 int error = FALSE; | |
9252 aco_save_T aco; | |
9253 | |
9254 /* set curbuf to be our buf, temporarily */ | |
9255 aucmd_prepbuf(&aco, buf); | |
9256 | |
9257 ++varname; | |
9258 numval = (long)get_tv_number_chk(varp, &error); | |
9259 strval = get_tv_string_buf_chk(varp, nbuf); | |
9260 if (!error && strval != NULL) | |
9261 set_option_value(varname, numval, strval, OPT_LOCAL); | |
9262 | |
9263 /* reset notion of buffer */ | |
9264 aucmd_restbuf(&aco); | |
9265 } | |
9266 else | |
9267 { | |
9268 buf_T *save_curbuf = curbuf; | |
9269 | |
9270 bufvarname = alloc((unsigned)STRLEN(varname) + 3); | |
9271 if (bufvarname != NULL) | |
9272 { | |
9273 curbuf = buf; | |
9274 STRCPY(bufvarname, "b:"); | |
9275 STRCPY(bufvarname + 2, varname); | |
9276 set_var(bufvarname, varp, TRUE); | |
9277 vim_free(bufvarname); | |
9278 curbuf = save_curbuf; | |
9279 } | |
9280 } | |
9281 } | |
9282 } | |
9283 | |
9284 static void | |
9285 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) | |
9286 { | |
9287 dict_T *d; | |
9288 dictitem_T *di; | |
9289 char_u *csearch; | |
9290 | |
9291 if (argvars[0].v_type != VAR_DICT) | |
9292 { | |
9293 EMSG(_(e_dictreq)); | |
9294 return; | |
9295 } | |
9296 | |
9297 if ((d = argvars[0].vval.v_dict) != NULL) | |
9298 { | |
9299 csearch = get_dict_string(d, (char_u *)"char", FALSE); | |
9300 if (csearch != NULL) | |
9301 { | |
9302 #ifdef FEAT_MBYTE | |
9303 if (enc_utf8) | |
9304 { | |
9305 int pcc[MAX_MCO]; | |
9306 int c = utfc_ptr2char(csearch, pcc); | |
9307 | |
9308 set_last_csearch(c, csearch, utfc_ptr2len(csearch)); | |
9309 } | |
9310 else | |
9311 #endif | |
9312 set_last_csearch(PTR2CHAR(csearch), | |
9313 csearch, MB_PTR2LEN(csearch)); | |
9314 } | |
9315 | |
9316 di = dict_find(d, (char_u *)"forward", -1); | |
9317 if (di != NULL) | |
9318 set_csearch_direction((int)get_tv_number(&di->di_tv) | |
9319 ? FORWARD : BACKWARD); | |
9320 | |
9321 di = dict_find(d, (char_u *)"until", -1); | |
9322 if (di != NULL) | |
9323 set_csearch_until(!!get_tv_number(&di->di_tv)); | |
9324 } | |
9325 } | |
9326 | |
9327 /* | |
9328 * "setcmdpos()" function | |
9329 */ | |
9330 static void | |
9331 f_setcmdpos(typval_T *argvars, typval_T *rettv) | |
9332 { | |
9333 int pos = (int)get_tv_number(&argvars[0]) - 1; | |
9334 | |
9335 if (pos >= 0) | |
9336 rettv->vval.v_number = set_cmdline_pos(pos); | |
9337 } | |
9338 | |
9339 /* | |
9340 * "setfperm({fname}, {mode})" function | |
9341 */ | |
9342 static void | |
9343 f_setfperm(typval_T *argvars, typval_T *rettv) | |
9344 { | |
9345 char_u *fname; | |
9346 char_u modebuf[NUMBUFLEN]; | |
9347 char_u *mode_str; | |
9348 int i; | |
9349 int mask; | |
9350 int mode = 0; | |
9351 | |
9352 rettv->vval.v_number = 0; | |
9353 fname = get_tv_string_chk(&argvars[0]); | |
9354 if (fname == NULL) | |
9355 return; | |
9356 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf); | |
9357 if (mode_str == NULL) | |
9358 return; | |
9359 if (STRLEN(mode_str) != 9) | |
9360 { | |
9361 EMSG2(_(e_invarg2), mode_str); | |
9362 return; | |
9363 } | |
9364 | |
9365 mask = 1; | |
9366 for (i = 8; i >= 0; --i) | |
9367 { | |
9368 if (mode_str[i] != '-') | |
9369 mode |= mask; | |
9370 mask = mask << 1; | |
9371 } | |
9372 rettv->vval.v_number = mch_setperm(fname, mode) == OK; | |
9373 } | |
9374 | |
9375 /* | |
9376 * "setline()" function | |
9377 */ | |
9378 static void | |
9379 f_setline(typval_T *argvars, typval_T *rettv) | |
9380 { | |
9381 linenr_T lnum; | |
9382 char_u *line = NULL; | |
9383 list_T *l = NULL; | |
9384 listitem_T *li = NULL; | |
9385 long added = 0; | |
9386 linenr_T lcount = curbuf->b_ml.ml_line_count; | |
9387 | |
9388 lnum = get_tv_lnum(&argvars[0]); | |
9389 if (argvars[1].v_type == VAR_LIST) | |
9390 { | |
9391 l = argvars[1].vval.v_list; | |
9392 li = l->lv_first; | |
9393 } | |
9394 else | |
9395 line = get_tv_string_chk(&argvars[1]); | |
9396 | |
9397 /* default result is zero == OK */ | |
9398 for (;;) | |
9399 { | |
9400 if (l != NULL) | |
9401 { | |
9402 /* list argument, get next string */ | |
9403 if (li == NULL) | |
9404 break; | |
9405 line = get_tv_string_chk(&li->li_tv); | |
9406 li = li->li_next; | |
9407 } | |
9408 | |
9409 rettv->vval.v_number = 1; /* FAIL */ | |
9410 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) | |
9411 break; | |
9412 | |
9413 /* When coming here from Insert mode, sync undo, so that this can be | |
9414 * undone separately from what was previously inserted. */ | |
9415 if (u_sync_once == 2) | |
9416 { | |
9417 u_sync_once = 1; /* notify that u_sync() was called */ | |
9418 u_sync(TRUE); | |
9419 } | |
9420 | |
9421 if (lnum <= curbuf->b_ml.ml_line_count) | |
9422 { | |
9423 /* existing line, replace it */ | |
9424 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) | |
9425 { | |
9426 changed_bytes(lnum, 0); | |
9427 if (lnum == curwin->w_cursor.lnum) | |
9428 check_cursor_col(); | |
9429 rettv->vval.v_number = 0; /* OK */ | |
9430 } | |
9431 } | |
9432 else if (added > 0 || u_save(lnum - 1, lnum) == OK) | |
9433 { | |
9434 /* lnum is one past the last line, append the line */ | |
9435 ++added; | |
9436 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) | |
9437 rettv->vval.v_number = 0; /* OK */ | |
9438 } | |
9439 | |
9440 if (l == NULL) /* only one string argument */ | |
9441 break; | |
9442 ++lnum; | |
9443 } | |
9444 | |
9445 if (added > 0) | |
9446 appended_lines_mark(lcount, added); | |
9447 } | |
9448 | |
9449 static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv); | |
9450 | |
9451 /* | |
9452 * Used by "setqflist()" and "setloclist()" functions | |
9453 */ | |
9454 static void | |
9455 set_qf_ll_list( | |
9456 win_T *wp UNUSED, | |
9457 typval_T *list_arg UNUSED, | |
9458 typval_T *action_arg UNUSED, | |
9459 typval_T *rettv) | |
9460 { | |
9461 #ifdef FEAT_QUICKFIX | |
9462 static char *e_invact = N_("E927: Invalid action: '%s'"); | |
9463 char_u *act; | |
9464 int action = 0; | |
9465 #endif | |
9466 | |
9467 rettv->vval.v_number = -1; | |
9468 | |
9469 #ifdef FEAT_QUICKFIX | |
9470 if (list_arg->v_type != VAR_LIST) | |
9471 EMSG(_(e_listreq)); | |
9472 else | |
9473 { | |
9474 list_T *l = list_arg->vval.v_list; | |
9475 | |
9476 if (action_arg->v_type == VAR_STRING) | |
9477 { | |
9478 act = get_tv_string_chk(action_arg); | |
9479 if (act == NULL) | |
9480 return; /* type error; errmsg already given */ | |
9481 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) | |
9482 action = *act; | |
9483 else | |
9484 EMSG2(_(e_invact), act); | |
9485 } | |
9486 else if (action_arg->v_type == VAR_UNKNOWN) | |
9487 action = ' '; | |
9488 else | |
9489 EMSG(_(e_stringreq)); | |
9490 | |
9491 if (l != NULL && action && set_errorlist(wp, l, action, | |
9492 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK) | |
9493 rettv->vval.v_number = 0; | |
9494 } | |
9495 #endif | |
9496 } | |
9497 | |
9498 /* | |
9499 * "setloclist()" function | |
9500 */ | |
9501 static void | |
9502 f_setloclist(typval_T *argvars, typval_T *rettv) | |
9503 { | |
9504 win_T *win; | |
9505 | |
9506 rettv->vval.v_number = -1; | |
9507 | |
9508 win = find_win_by_nr(&argvars[0], NULL); | |
9509 if (win != NULL) | |
9510 set_qf_ll_list(win, &argvars[1], &argvars[2], rettv); | |
9511 } | |
9512 | |
9513 /* | |
9514 * "setmatches()" function | |
9515 */ | |
9516 static void | |
9517 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
9518 { | |
9519 #ifdef FEAT_SEARCH_EXTRA | |
9520 list_T *l; | |
9521 listitem_T *li; | |
9522 dict_T *d; | |
9523 list_T *s = NULL; | |
9524 | |
9525 rettv->vval.v_number = -1; | |
9526 if (argvars[0].v_type != VAR_LIST) | |
9527 { | |
9528 EMSG(_(e_listreq)); | |
9529 return; | |
9530 } | |
9531 if ((l = argvars[0].vval.v_list) != NULL) | |
9532 { | |
9533 | |
9534 /* To some extent make sure that we are dealing with a list from | |
9535 * "getmatches()". */ | |
9536 li = l->lv_first; | |
9537 while (li != NULL) | |
9538 { | |
9539 if (li->li_tv.v_type != VAR_DICT | |
9540 || (d = li->li_tv.vval.v_dict) == NULL) | |
9541 { | |
9542 EMSG(_(e_invarg)); | |
9543 return; | |
9544 } | |
9545 if (!(dict_find(d, (char_u *)"group", -1) != NULL | |
9546 && (dict_find(d, (char_u *)"pattern", -1) != NULL | |
9547 || dict_find(d, (char_u *)"pos1", -1) != NULL) | |
9548 && dict_find(d, (char_u *)"priority", -1) != NULL | |
9549 && dict_find(d, (char_u *)"id", -1) != NULL)) | |
9550 { | |
9551 EMSG(_(e_invarg)); | |
9552 return; | |
9553 } | |
9554 li = li->li_next; | |
9555 } | |
9556 | |
9557 clear_matches(curwin); | |
9558 li = l->lv_first; | |
9559 while (li != NULL) | |
9560 { | |
9561 int i = 0; | |
9562 char_u buf[5]; | |
9563 dictitem_T *di; | |
9564 char_u *group; | |
9565 int priority; | |
9566 int id; | |
9567 char_u *conceal; | |
9568 | |
9569 d = li->li_tv.vval.v_dict; | |
9570 if (dict_find(d, (char_u *)"pattern", -1) == NULL) | |
9571 { | |
9572 if (s == NULL) | |
9573 { | |
9574 s = list_alloc(); | |
9575 if (s == NULL) | |
9576 return; | |
9577 } | |
9578 | |
9579 /* match from matchaddpos() */ | |
9580 for (i = 1; i < 9; i++) | |
9581 { | |
9582 sprintf((char *)buf, (char *)"pos%d", i); | |
9583 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) | |
9584 { | |
9585 if (di->di_tv.v_type != VAR_LIST) | |
9586 return; | |
9587 | |
9588 list_append_tv(s, &di->di_tv); | |
9589 s->lv_refcount++; | |
9590 } | |
9591 else | |
9592 break; | |
9593 } | |
9594 } | |
9595 | |
9596 group = get_dict_string(d, (char_u *)"group", FALSE); | |
9597 priority = (int)get_dict_number(d, (char_u *)"priority"); | |
9598 id = (int)get_dict_number(d, (char_u *)"id"); | |
9599 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL | |
9600 ? get_dict_string(d, (char_u *)"conceal", FALSE) | |
9601 : NULL; | |
9602 if (i == 0) | |
9603 { | |
9604 match_add(curwin, group, | |
9605 get_dict_string(d, (char_u *)"pattern", FALSE), | |
9606 priority, id, NULL, conceal); | |
9607 } | |
9608 else | |
9609 { | |
9610 match_add(curwin, group, NULL, priority, id, s, conceal); | |
9611 list_unref(s); | |
9612 s = NULL; | |
9613 } | |
9614 | |
9615 li = li->li_next; | |
9616 } | |
9617 rettv->vval.v_number = 0; | |
9618 } | |
9619 #endif | |
9620 } | |
9621 | |
9622 /* | |
9623 * "setpos()" function | |
9624 */ | |
9625 static void | |
9626 f_setpos(typval_T *argvars, typval_T *rettv) | |
9627 { | |
9628 pos_T pos; | |
9629 int fnum; | |
9630 char_u *name; | |
9631 colnr_T curswant = -1; | |
9632 | |
9633 rettv->vval.v_number = -1; | |
9634 name = get_tv_string_chk(argvars); | |
9635 if (name != NULL) | |
9636 { | |
9637 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) | |
9638 { | |
9639 if (--pos.col < 0) | |
9640 pos.col = 0; | |
9641 if (name[0] == '.' && name[1] == NUL) | |
9642 { | |
9643 /* set cursor */ | |
9644 if (fnum == curbuf->b_fnum) | |
9645 { | |
9646 curwin->w_cursor = pos; | |
9647 if (curswant >= 0) | |
9648 { | |
9649 curwin->w_curswant = curswant - 1; | |
9650 curwin->w_set_curswant = FALSE; | |
9651 } | |
9652 check_cursor(); | |
9653 rettv->vval.v_number = 0; | |
9654 } | |
9655 else | |
9656 EMSG(_(e_invarg)); | |
9657 } | |
9658 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) | |
9659 { | |
9660 /* set mark */ | |
9661 if (setmark_pos(name[1], &pos, fnum) == OK) | |
9662 rettv->vval.v_number = 0; | |
9663 } | |
9664 else | |
9665 EMSG(_(e_invarg)); | |
9666 } | |
9667 } | |
9668 } | |
9669 | |
9670 /* | |
9671 * "setqflist()" function | |
9672 */ | |
9673 static void | |
9674 f_setqflist(typval_T *argvars, typval_T *rettv) | |
9675 { | |
9676 set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv); | |
9677 } | |
9678 | |
9679 /* | |
9680 * "setreg()" function | |
9681 */ | |
9682 static void | |
9683 f_setreg(typval_T *argvars, typval_T *rettv) | |
9684 { | |
9685 int regname; | |
9686 char_u *strregname; | |
9687 char_u *stropt; | |
9688 char_u *strval; | |
9689 int append; | |
9690 char_u yank_type; | |
9691 long block_len; | |
9692 | |
9693 block_len = -1; | |
9694 yank_type = MAUTO; | |
9695 append = FALSE; | |
9696 | |
9697 strregname = get_tv_string_chk(argvars); | |
9698 rettv->vval.v_number = 1; /* FAIL is default */ | |
9699 | |
9700 if (strregname == NULL) | |
9701 return; /* type error; errmsg already given */ | |
9702 regname = *strregname; | |
9703 if (regname == 0 || regname == '@') | |
9704 regname = '"'; | |
9705 | |
9706 if (argvars[2].v_type != VAR_UNKNOWN) | |
9707 { | |
9708 stropt = get_tv_string_chk(&argvars[2]); | |
9709 if (stropt == NULL) | |
9710 return; /* type error */ | |
9711 for (; *stropt != NUL; ++stropt) | |
9712 switch (*stropt) | |
9713 { | |
9714 case 'a': case 'A': /* append */ | |
9715 append = TRUE; | |
9716 break; | |
9717 case 'v': case 'c': /* character-wise selection */ | |
9718 yank_type = MCHAR; | |
9719 break; | |
9720 case 'V': case 'l': /* line-wise selection */ | |
9721 yank_type = MLINE; | |
9722 break; | |
9723 case 'b': case Ctrl_V: /* block-wise selection */ | |
9724 yank_type = MBLOCK; | |
9725 if (VIM_ISDIGIT(stropt[1])) | |
9726 { | |
9727 ++stropt; | |
9728 block_len = getdigits(&stropt) - 1; | |
9729 --stropt; | |
9730 } | |
9731 break; | |
9732 } | |
9733 } | |
9734 | |
9735 if (argvars[1].v_type == VAR_LIST) | |
9736 { | |
9737 char_u **lstval; | |
9738 char_u **allocval; | |
9739 char_u buf[NUMBUFLEN]; | |
9740 char_u **curval; | |
9741 char_u **curallocval; | |
9742 list_T *ll = argvars[1].vval.v_list; | |
9743 listitem_T *li; | |
9744 int len; | |
9745 | |
9746 /* If the list is NULL handle like an empty list. */ | |
9747 len = ll == NULL ? 0 : ll->lv_len; | |
9748 | |
9749 /* First half: use for pointers to result lines; second half: use for | |
9750 * pointers to allocated copies. */ | |
9751 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2)); | |
9752 if (lstval == NULL) | |
9753 return; | |
9754 curval = lstval; | |
9755 allocval = lstval + len + 2; | |
9756 curallocval = allocval; | |
9757 | |
9758 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL; | |
9759 li = li->li_next) | |
9760 { | |
9761 strval = get_tv_string_buf_chk(&li->li_tv, buf); | |
9762 if (strval == NULL) | |
9763 goto free_lstval; | |
9764 if (strval == buf) | |
9765 { | |
9766 /* Need to make a copy, next get_tv_string_buf_chk() will | |
9767 * overwrite the string. */ | |
9768 strval = vim_strsave(buf); | |
9769 if (strval == NULL) | |
9770 goto free_lstval; | |
9771 *curallocval++ = strval; | |
9772 } | |
9773 *curval++ = strval; | |
9774 } | |
9775 *curval++ = NULL; | |
9776 | |
9777 write_reg_contents_lst(regname, lstval, -1, | |
9778 append, yank_type, block_len); | |
9779 free_lstval: | |
9780 while (curallocval > allocval) | |
9781 vim_free(*--curallocval); | |
9782 vim_free(lstval); | |
9783 } | |
9784 else | |
9785 { | |
9786 strval = get_tv_string_chk(&argvars[1]); | |
9787 if (strval == NULL) | |
9788 return; | |
9789 write_reg_contents_ex(regname, strval, -1, | |
9790 append, yank_type, block_len); | |
9791 } | |
9792 rettv->vval.v_number = 0; | |
9793 } | |
9794 | |
9795 /* | |
9796 * "settabvar()" function | |
9797 */ | |
9798 static void | |
9799 f_settabvar(typval_T *argvars, typval_T *rettv) | |
9800 { | |
9801 #ifdef FEAT_WINDOWS | |
9802 tabpage_T *save_curtab; | |
9803 tabpage_T *tp; | |
9804 #endif | |
9805 char_u *varname, *tabvarname; | |
9806 typval_T *varp; | |
9807 | |
9808 rettv->vval.v_number = 0; | |
9809 | |
9810 if (check_restricted() || check_secure()) | |
9811 return; | |
9812 | |
9813 #ifdef FEAT_WINDOWS | |
9814 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
9815 #endif | |
9816 varname = get_tv_string_chk(&argvars[1]); | |
9817 varp = &argvars[2]; | |
9818 | |
9819 if (varname != NULL && varp != NULL | |
9820 #ifdef FEAT_WINDOWS | |
9821 && tp != NULL | |
9822 #endif | |
9823 ) | |
9824 { | |
9825 #ifdef FEAT_WINDOWS | |
9826 save_curtab = curtab; | |
9827 goto_tabpage_tp(tp, FALSE, FALSE); | |
9828 #endif | |
9829 | |
9830 tabvarname = alloc((unsigned)STRLEN(varname) + 3); | |
9831 if (tabvarname != NULL) | |
9832 { | |
9833 STRCPY(tabvarname, "t:"); | |
9834 STRCPY(tabvarname + 2, varname); | |
9835 set_var(tabvarname, varp, TRUE); | |
9836 vim_free(tabvarname); | |
9837 } | |
9838 | |
9839 #ifdef FEAT_WINDOWS | |
9840 /* Restore current tabpage */ | |
9841 if (valid_tabpage(save_curtab)) | |
9842 goto_tabpage_tp(save_curtab, FALSE, FALSE); | |
9843 #endif | |
9844 } | |
9845 } | |
9846 | |
9847 /* | |
9848 * "settabwinvar()" function | |
9849 */ | |
9850 static void | |
9851 f_settabwinvar(typval_T *argvars, typval_T *rettv) | |
9852 { | |
9853 setwinvar(argvars, rettv, 1); | |
9854 } | |
9855 | |
9856 /* | |
9857 * "setwinvar()" function | |
9858 */ | |
9859 static void | |
9860 f_setwinvar(typval_T *argvars, typval_T *rettv) | |
9861 { | |
9862 setwinvar(argvars, rettv, 0); | |
9863 } | |
9864 | |
9865 #ifdef FEAT_CRYPT | |
9866 /* | |
9867 * "sha256({string})" function | |
9868 */ | |
9869 static void | |
9870 f_sha256(typval_T *argvars, typval_T *rettv) | |
9871 { | |
9872 char_u *p; | |
9873 | |
9874 p = get_tv_string(&argvars[0]); | |
9875 rettv->vval.v_string = vim_strsave( | |
9876 sha256_bytes(p, (int)STRLEN(p), NULL, 0)); | |
9877 rettv->v_type = VAR_STRING; | |
9878 } | |
9879 #endif /* FEAT_CRYPT */ | |
9880 | |
9881 /* | |
9882 * "shellescape({string})" function | |
9883 */ | |
9884 static void | |
9885 f_shellescape(typval_T *argvars, typval_T *rettv) | |
9886 { | |
9887 rettv->vval.v_string = vim_strsave_shellescape( | |
9888 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE); | |
9889 rettv->v_type = VAR_STRING; | |
9890 } | |
9891 | |
9892 /* | |
9893 * shiftwidth() function | |
9894 */ | |
9895 static void | |
9896 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) | |
9897 { | |
9898 rettv->vval.v_number = get_sw_value(curbuf); | |
9899 } | |
9900 | |
9901 /* | |
9902 * "simplify()" function | |
9903 */ | |
9904 static void | |
9905 f_simplify(typval_T *argvars, typval_T *rettv) | |
9906 { | |
9907 char_u *p; | |
9908 | |
9909 p = get_tv_string(&argvars[0]); | |
9910 rettv->vval.v_string = vim_strsave(p); | |
9911 simplify_filename(rettv->vval.v_string); /* simplify in place */ | |
9912 rettv->v_type = VAR_STRING; | |
9913 } | |
9914 | |
9915 #ifdef FEAT_FLOAT | |
9916 /* | |
9917 * "sin()" function | |
9918 */ | |
9919 static void | |
9920 f_sin(typval_T *argvars, typval_T *rettv) | |
9921 { | |
9922 float_T f = 0.0; | |
9923 | |
9924 rettv->v_type = VAR_FLOAT; | |
9925 if (get_float_arg(argvars, &f) == OK) | |
9926 rettv->vval.v_float = sin(f); | |
9927 else | |
9928 rettv->vval.v_float = 0.0; | |
9929 } | |
9930 | |
9931 /* | |
9932 * "sinh()" function | |
9933 */ | |
9934 static void | |
9935 f_sinh(typval_T *argvars, typval_T *rettv) | |
9936 { | |
9937 float_T f = 0.0; | |
9938 | |
9939 rettv->v_type = VAR_FLOAT; | |
9940 if (get_float_arg(argvars, &f) == OK) | |
9941 rettv->vval.v_float = sinh(f); | |
9942 else | |
9943 rettv->vval.v_float = 0.0; | |
9944 } | |
9945 #endif | |
9946 | |
9947 static int | |
9948 #ifdef __BORLANDC__ | |
9949 _RTLENTRYF | |
9950 #endif | |
9951 item_compare(const void *s1, const void *s2); | |
9952 static int | |
9953 #ifdef __BORLANDC__ | |
9954 _RTLENTRYF | |
9955 #endif | |
9956 item_compare2(const void *s1, const void *s2); | |
9957 | |
9958 /* struct used in the array that's given to qsort() */ | |
9959 typedef struct | |
9960 { | |
9961 listitem_T *item; | |
9962 int idx; | |
9963 } sortItem_T; | |
9964 | |
9965 /* struct storing information about current sort */ | |
9966 typedef struct | |
9967 { | |
9968 int item_compare_ic; | |
9969 int item_compare_numeric; | |
9970 int item_compare_numbers; | |
9971 #ifdef FEAT_FLOAT | |
9972 int item_compare_float; | |
9973 #endif | |
9974 char_u *item_compare_func; | |
9975 partial_T *item_compare_partial; | |
9976 dict_T *item_compare_selfdict; | |
9977 int item_compare_func_err; | |
9978 int item_compare_keep_zero; | |
9979 } sortinfo_T; | |
9980 static sortinfo_T *sortinfo = NULL; | |
9981 static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort); | |
9982 #define ITEM_COMPARE_FAIL 999 | |
9983 | |
9984 /* | |
9985 * Compare functions for f_sort() and f_uniq() below. | |
9986 */ | |
9987 static int | |
9988 #ifdef __BORLANDC__ | |
9989 _RTLENTRYF | |
9990 #endif | |
9991 item_compare(const void *s1, const void *s2) | |
9992 { | |
9993 sortItem_T *si1, *si2; | |
9994 typval_T *tv1, *tv2; | |
9995 char_u *p1, *p2; | |
9996 char_u *tofree1 = NULL, *tofree2 = NULL; | |
9997 int res; | |
9998 char_u numbuf1[NUMBUFLEN]; | |
9999 char_u numbuf2[NUMBUFLEN]; | |
10000 | |
10001 si1 = (sortItem_T *)s1; | |
10002 si2 = (sortItem_T *)s2; | |
10003 tv1 = &si1->item->li_tv; | |
10004 tv2 = &si2->item->li_tv; | |
10005 | |
10006 if (sortinfo->item_compare_numbers) | |
10007 { | |
10008 varnumber_T v1 = get_tv_number(tv1); | |
10009 varnumber_T v2 = get_tv_number(tv2); | |
10010 | |
10011 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | |
10012 } | |
10013 | |
10014 #ifdef FEAT_FLOAT | |
10015 if (sortinfo->item_compare_float) | |
10016 { | |
10017 float_T v1 = get_tv_float(tv1); | |
10018 float_T v2 = get_tv_float(tv2); | |
10019 | |
10020 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | |
10021 } | |
10022 #endif | |
10023 | |
10024 /* tv2string() puts quotes around a string and allocates memory. Don't do | |
10025 * that for string variables. Use a single quote when comparing with a | |
10026 * non-string to do what the docs promise. */ | |
10027 if (tv1->v_type == VAR_STRING) | |
10028 { | |
10029 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) | |
10030 p1 = (char_u *)"'"; | |
10031 else | |
10032 p1 = tv1->vval.v_string; | |
10033 } | |
10034 else | |
10035 p1 = tv2string(tv1, &tofree1, numbuf1, 0); | |
10036 if (tv2->v_type == VAR_STRING) | |
10037 { | |
10038 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) | |
10039 p2 = (char_u *)"'"; | |
10040 else | |
10041 p2 = tv2->vval.v_string; | |
10042 } | |
10043 else | |
10044 p2 = tv2string(tv2, &tofree2, numbuf2, 0); | |
10045 if (p1 == NULL) | |
10046 p1 = (char_u *)""; | |
10047 if (p2 == NULL) | |
10048 p2 = (char_u *)""; | |
10049 if (!sortinfo->item_compare_numeric) | |
10050 { | |
10051 if (sortinfo->item_compare_ic) | |
10052 res = STRICMP(p1, p2); | |
10053 else | |
10054 res = STRCMP(p1, p2); | |
10055 } | |
10056 else | |
10057 { | |
10058 double n1, n2; | |
10059 n1 = strtod((char *)p1, (char **)&p1); | |
10060 n2 = strtod((char *)p2, (char **)&p2); | |
10061 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; | |
10062 } | |
10063 | |
10064 /* When the result would be zero, compare the item indexes. Makes the | |
10065 * sort stable. */ | |
10066 if (res == 0 && !sortinfo->item_compare_keep_zero) | |
10067 res = si1->idx > si2->idx ? 1 : -1; | |
10068 | |
10069 vim_free(tofree1); | |
10070 vim_free(tofree2); | |
10071 return res; | |
10072 } | |
10073 | |
10074 static int | |
10075 #ifdef __BORLANDC__ | |
10076 _RTLENTRYF | |
10077 #endif | |
10078 item_compare2(const void *s1, const void *s2) | |
10079 { | |
10080 sortItem_T *si1, *si2; | |
10081 int res; | |
10082 typval_T rettv; | |
10083 typval_T argv[3]; | |
10084 int dummy; | |
10085 char_u *func_name; | |
10086 partial_T *partial = sortinfo->item_compare_partial; | |
10087 | |
10088 /* shortcut after failure in previous call; compare all items equal */ | |
10089 if (sortinfo->item_compare_func_err) | |
10090 return 0; | |
10091 | |
10092 si1 = (sortItem_T *)s1; | |
10093 si2 = (sortItem_T *)s2; | |
10094 | |
10095 if (partial == NULL) | |
10096 func_name = sortinfo->item_compare_func; | |
10097 else | |
10098 func_name = partial->pt_name; | |
10099 | |
10100 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED | |
10101 * in the copy without changing the original list items. */ | |
10102 copy_tv(&si1->item->li_tv, &argv[0]); | |
10103 copy_tv(&si2->item->li_tv, &argv[1]); | |
10104 | |
10105 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ | |
10106 res = call_func(func_name, (int)STRLEN(func_name), | |
10107 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, | |
10108 partial, sortinfo->item_compare_selfdict); | |
10109 clear_tv(&argv[0]); | |
10110 clear_tv(&argv[1]); | |
10111 | |
10112 if (res == FAIL) | |
10113 res = ITEM_COMPARE_FAIL; | |
10114 else | |
10115 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err); | |
10116 if (sortinfo->item_compare_func_err) | |
10117 res = ITEM_COMPARE_FAIL; /* return value has wrong type */ | |
10118 clear_tv(&rettv); | |
10119 | |
10120 /* When the result would be zero, compare the pointers themselves. Makes | |
10121 * the sort stable. */ | |
10122 if (res == 0 && !sortinfo->item_compare_keep_zero) | |
10123 res = si1->idx > si2->idx ? 1 : -1; | |
10124 | |
10125 return res; | |
10126 } | |
10127 | |
10128 /* | |
10129 * "sort({list})" function | |
10130 */ | |
10131 static void | |
10132 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) | |
10133 { | |
10134 list_T *l; | |
10135 listitem_T *li; | |
10136 sortItem_T *ptrs; | |
10137 sortinfo_T *old_sortinfo; | |
10138 sortinfo_T info; | |
10139 long len; | |
10140 long i; | |
10141 | |
10142 /* Pointer to current info struct used in compare function. Save and | |
10143 * restore the current one for nested calls. */ | |
10144 old_sortinfo = sortinfo; | |
10145 sortinfo = &info; | |
10146 | |
10147 if (argvars[0].v_type != VAR_LIST) | |
10148 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); | |
10149 else | |
10150 { | |
10151 l = argvars[0].vval.v_list; | |
10152 if (l == NULL || tv_check_lock(l->lv_lock, | |
10153 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), | |
10154 TRUE)) | |
10155 goto theend; | |
10156 rettv->vval.v_list = l; | |
10157 rettv->v_type = VAR_LIST; | |
10158 ++l->lv_refcount; | |
10159 | |
10160 len = list_len(l); | |
10161 if (len <= 1) | |
10162 goto theend; /* short list sorts pretty quickly */ | |
10163 | |
10164 info.item_compare_ic = FALSE; | |
10165 info.item_compare_numeric = FALSE; | |
10166 info.item_compare_numbers = FALSE; | |
10167 #ifdef FEAT_FLOAT | |
10168 info.item_compare_float = FALSE; | |
10169 #endif | |
10170 info.item_compare_func = NULL; | |
10171 info.item_compare_partial = NULL; | |
10172 info.item_compare_selfdict = NULL; | |
10173 if (argvars[1].v_type != VAR_UNKNOWN) | |
10174 { | |
10175 /* optional second argument: {func} */ | |
10176 if (argvars[1].v_type == VAR_FUNC) | |
10177 info.item_compare_func = argvars[1].vval.v_string; | |
10178 else if (argvars[1].v_type == VAR_PARTIAL) | |
10179 info.item_compare_partial = argvars[1].vval.v_partial; | |
10180 else | |
10181 { | |
10182 int error = FALSE; | |
10183 | |
10184 i = (long)get_tv_number_chk(&argvars[1], &error); | |
10185 if (error) | |
10186 goto theend; /* type error; errmsg already given */ | |
10187 if (i == 1) | |
10188 info.item_compare_ic = TRUE; | |
10189 else if (argvars[1].v_type != VAR_NUMBER) | |
10190 info.item_compare_func = get_tv_string(&argvars[1]); | |
10191 else if (i != 0) | |
10192 { | |
10193 EMSG(_(e_invarg)); | |
10194 goto theend; | |
10195 } | |
10196 if (info.item_compare_func != NULL) | |
10197 { | |
10198 if (*info.item_compare_func == NUL) | |
10199 { | |
10200 /* empty string means default sort */ | |
10201 info.item_compare_func = NULL; | |
10202 } | |
10203 else if (STRCMP(info.item_compare_func, "n") == 0) | |
10204 { | |
10205 info.item_compare_func = NULL; | |
10206 info.item_compare_numeric = TRUE; | |
10207 } | |
10208 else if (STRCMP(info.item_compare_func, "N") == 0) | |
10209 { | |
10210 info.item_compare_func = NULL; | |
10211 info.item_compare_numbers = TRUE; | |
10212 } | |
10213 #ifdef FEAT_FLOAT | |
10214 else if (STRCMP(info.item_compare_func, "f") == 0) | |
10215 { | |
10216 info.item_compare_func = NULL; | |
10217 info.item_compare_float = TRUE; | |
10218 } | |
10219 #endif | |
10220 else if (STRCMP(info.item_compare_func, "i") == 0) | |
10221 { | |
10222 info.item_compare_func = NULL; | |
10223 info.item_compare_ic = TRUE; | |
10224 } | |
10225 } | |
10226 } | |
10227 | |
10228 if (argvars[2].v_type != VAR_UNKNOWN) | |
10229 { | |
10230 /* optional third argument: {dict} */ | |
10231 if (argvars[2].v_type != VAR_DICT) | |
10232 { | |
10233 EMSG(_(e_dictreq)); | |
10234 goto theend; | |
10235 } | |
10236 info.item_compare_selfdict = argvars[2].vval.v_dict; | |
10237 } | |
10238 } | |
10239 | |
10240 /* Make an array with each entry pointing to an item in the List. */ | |
10241 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T))); | |
10242 if (ptrs == NULL) | |
10243 goto theend; | |
10244 | |
10245 i = 0; | |
10246 if (sort) | |
10247 { | |
10248 /* sort(): ptrs will be the list to sort */ | |
10249 for (li = l->lv_first; li != NULL; li = li->li_next) | |
10250 { | |
10251 ptrs[i].item = li; | |
10252 ptrs[i].idx = i; | |
10253 ++i; | |
10254 } | |
10255 | |
10256 info.item_compare_func_err = FALSE; | |
10257 info.item_compare_keep_zero = FALSE; | |
10258 /* test the compare function */ | |
10259 if ((info.item_compare_func != NULL | |
10260 || info.item_compare_partial != NULL) | |
10261 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) | |
10262 == ITEM_COMPARE_FAIL) | |
10263 EMSG(_("E702: Sort compare function failed")); | |
10264 else | |
10265 { | |
10266 /* Sort the array with item pointers. */ | |
10267 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), | |
10268 info.item_compare_func == NULL | |
10269 && info.item_compare_partial == NULL | |
10270 ? item_compare : item_compare2); | |
10271 | |
10272 if (!info.item_compare_func_err) | |
10273 { | |
10274 /* Clear the List and append the items in sorted order. */ | |
10275 l->lv_first = l->lv_last = l->lv_idx_item = NULL; | |
10276 l->lv_len = 0; | |
10277 for (i = 0; i < len; ++i) | |
10278 list_append(l, ptrs[i].item); | |
10279 } | |
10280 } | |
10281 } | |
10282 else | |
10283 { | |
10284 int (*item_compare_func_ptr)(const void *, const void *); | |
10285 | |
10286 /* f_uniq(): ptrs will be a stack of items to remove */ | |
10287 info.item_compare_func_err = FALSE; | |
10288 info.item_compare_keep_zero = TRUE; | |
10289 item_compare_func_ptr = info.item_compare_func != NULL | |
10290 || info.item_compare_partial != NULL | |
10291 ? item_compare2 : item_compare; | |
10292 | |
10293 for (li = l->lv_first; li != NULL && li->li_next != NULL; | |
10294 li = li->li_next) | |
10295 { | |
10296 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) | |
10297 == 0) | |
10298 ptrs[i++].item = li; | |
10299 if (info.item_compare_func_err) | |
10300 { | |
10301 EMSG(_("E882: Uniq compare function failed")); | |
10302 break; | |
10303 } | |
10304 } | |
10305 | |
10306 if (!info.item_compare_func_err) | |
10307 { | |
10308 while (--i >= 0) | |
10309 { | |
10310 li = ptrs[i].item->li_next; | |
10311 ptrs[i].item->li_next = li->li_next; | |
10312 if (li->li_next != NULL) | |
10313 li->li_next->li_prev = ptrs[i].item; | |
10314 else | |
10315 l->lv_last = ptrs[i].item; | |
10316 list_fix_watch(l, li); | |
10317 listitem_free(li); | |
10318 l->lv_len--; | |
10319 } | |
10320 } | |
10321 } | |
10322 | |
10323 vim_free(ptrs); | |
10324 } | |
10325 theend: | |
10326 sortinfo = old_sortinfo; | |
10327 } | |
10328 | |
10329 /* | |
10330 * "sort({list})" function | |
10331 */ | |
10332 static void | |
10333 f_sort(typval_T *argvars, typval_T *rettv) | |
10334 { | |
10335 do_sort_uniq(argvars, rettv, TRUE); | |
10336 } | |
10337 | |
10338 /* | |
10339 * "uniq({list})" function | |
10340 */ | |
10341 static void | |
10342 f_uniq(typval_T *argvars, typval_T *rettv) | |
10343 { | |
10344 do_sort_uniq(argvars, rettv, FALSE); | |
10345 } | |
10346 | |
10347 /* | |
10348 * "soundfold({word})" function | |
10349 */ | |
10350 static void | |
10351 f_soundfold(typval_T *argvars, typval_T *rettv) | |
10352 { | |
10353 char_u *s; | |
10354 | |
10355 rettv->v_type = VAR_STRING; | |
10356 s = get_tv_string(&argvars[0]); | |
10357 #ifdef FEAT_SPELL | |
10358 rettv->vval.v_string = eval_soundfold(s); | |
10359 #else | |
10360 rettv->vval.v_string = vim_strsave(s); | |
10361 #endif | |
10362 } | |
10363 | |
10364 /* | |
10365 * "spellbadword()" function | |
10366 */ | |
10367 static void | |
10368 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv) | |
10369 { | |
10370 char_u *word = (char_u *)""; | |
10371 hlf_T attr = HLF_COUNT; | |
10372 int len = 0; | |
10373 | |
10374 if (rettv_list_alloc(rettv) == FAIL) | |
10375 return; | |
10376 | |
10377 #ifdef FEAT_SPELL | |
10378 if (argvars[0].v_type == VAR_UNKNOWN) | |
10379 { | |
10380 /* Find the start and length of the badly spelled word. */ | |
10381 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); | |
10382 if (len != 0) | |
10383 word = ml_get_cursor(); | |
10384 } | |
10385 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) | |
10386 { | |
10387 char_u *str = get_tv_string_chk(&argvars[0]); | |
10388 int capcol = -1; | |
10389 | |
10390 if (str != NULL) | |
10391 { | |
10392 /* Check the argument for spelling. */ | |
10393 while (*str != NUL) | |
10394 { | |
10395 len = spell_check(curwin, str, &attr, &capcol, FALSE); | |
10396 if (attr != HLF_COUNT) | |
10397 { | |
10398 word = str; | |
10399 break; | |
10400 } | |
10401 str += len; | |
10402 } | |
10403 } | |
10404 } | |
10405 #endif | |
10406 | |
10407 list_append_string(rettv->vval.v_list, word, len); | |
10408 list_append_string(rettv->vval.v_list, (char_u *)( | |
10409 attr == HLF_SPB ? "bad" : | |
10410 attr == HLF_SPR ? "rare" : | |
10411 attr == HLF_SPL ? "local" : | |
10412 attr == HLF_SPC ? "caps" : | |
10413 ""), -1); | |
10414 } | |
10415 | |
10416 /* | |
10417 * "spellsuggest()" function | |
10418 */ | |
10419 static void | |
10420 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv) | |
10421 { | |
10422 #ifdef FEAT_SPELL | |
10423 char_u *str; | |
10424 int typeerr = FALSE; | |
10425 int maxcount; | |
10426 garray_T ga; | |
10427 int i; | |
10428 listitem_T *li; | |
10429 int need_capital = FALSE; | |
10430 #endif | |
10431 | |
10432 if (rettv_list_alloc(rettv) == FAIL) | |
10433 return; | |
10434 | |
10435 #ifdef FEAT_SPELL | |
10436 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) | |
10437 { | |
10438 str = get_tv_string(&argvars[0]); | |
10439 if (argvars[1].v_type != VAR_UNKNOWN) | |
10440 { | |
10441 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr); | |
10442 if (maxcount <= 0) | |
10443 return; | |
10444 if (argvars[2].v_type != VAR_UNKNOWN) | |
10445 { | |
10446 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr); | |
10447 if (typeerr) | |
10448 return; | |
10449 } | |
10450 } | |
10451 else | |
10452 maxcount = 25; | |
10453 | |
10454 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE); | |
10455 | |
10456 for (i = 0; i < ga.ga_len; ++i) | |
10457 { | |
10458 str = ((char_u **)ga.ga_data)[i]; | |
10459 | |
10460 li = listitem_alloc(); | |
10461 if (li == NULL) | |
10462 vim_free(str); | |
10463 else | |
10464 { | |
10465 li->li_tv.v_type = VAR_STRING; | |
10466 li->li_tv.v_lock = 0; | |
10467 li->li_tv.vval.v_string = str; | |
10468 list_append(rettv->vval.v_list, li); | |
10469 } | |
10470 } | |
10471 ga_clear(&ga); | |
10472 } | |
10473 #endif | |
10474 } | |
10475 | |
10476 static void | |
10477 f_split(typval_T *argvars, typval_T *rettv) | |
10478 { | |
10479 char_u *str; | |
10480 char_u *end; | |
10481 char_u *pat = NULL; | |
10482 regmatch_T regmatch; | |
10483 char_u patbuf[NUMBUFLEN]; | |
10484 char_u *save_cpo; | |
10485 int match; | |
10486 colnr_T col = 0; | |
10487 int keepempty = FALSE; | |
10488 int typeerr = FALSE; | |
10489 | |
10490 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
10491 save_cpo = p_cpo; | |
10492 p_cpo = (char_u *)""; | |
10493 | |
10494 str = get_tv_string(&argvars[0]); | |
10495 if (argvars[1].v_type != VAR_UNKNOWN) | |
10496 { | |
10497 pat = get_tv_string_buf_chk(&argvars[1], patbuf); | |
10498 if (pat == NULL) | |
10499 typeerr = TRUE; | |
10500 if (argvars[2].v_type != VAR_UNKNOWN) | |
10501 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr); | |
10502 } | |
10503 if (pat == NULL || *pat == NUL) | |
10504 pat = (char_u *)"[\\x01- ]\\+"; | |
10505 | |
10506 if (rettv_list_alloc(rettv) == FAIL) | |
10507 return; | |
10508 if (typeerr) | |
10509 return; | |
10510 | |
10511 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); | |
10512 if (regmatch.regprog != NULL) | |
10513 { | |
10514 regmatch.rm_ic = FALSE; | |
10515 while (*str != NUL || keepempty) | |
10516 { | |
10517 if (*str == NUL) | |
10518 match = FALSE; /* empty item at the end */ | |
10519 else | |
10520 match = vim_regexec_nl(®match, str, col); | |
10521 if (match) | |
10522 end = regmatch.startp[0]; | |
10523 else | |
10524 end = str + STRLEN(str); | |
10525 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0 | |
10526 && *str != NUL && match && end < regmatch.endp[0])) | |
10527 { | |
10528 if (list_append_string(rettv->vval.v_list, str, | |
10529 (int)(end - str)) == FAIL) | |
10530 break; | |
10531 } | |
10532 if (!match) | |
10533 break; | |
10534 /* Advance to just after the match. */ | |
10535 if (regmatch.endp[0] > str) | |
10536 col = 0; | |
10537 else | |
10538 { | |
10539 /* Don't get stuck at the same match. */ | |
10540 #ifdef FEAT_MBYTE | |
10541 col = (*mb_ptr2len)(regmatch.endp[0]); | |
10542 #else | |
10543 col = 1; | |
10544 #endif | |
10545 } | |
10546 str = regmatch.endp[0]; | |
10547 } | |
10548 | |
10549 vim_regfree(regmatch.regprog); | |
10550 } | |
10551 | |
10552 p_cpo = save_cpo; | |
10553 } | |
10554 | |
10555 #ifdef FEAT_FLOAT | |
10556 /* | |
10557 * "sqrt()" function | |
10558 */ | |
10559 static void | |
10560 f_sqrt(typval_T *argvars, typval_T *rettv) | |
10561 { | |
10562 float_T f = 0.0; | |
10563 | |
10564 rettv->v_type = VAR_FLOAT; | |
10565 if (get_float_arg(argvars, &f) == OK) | |
10566 rettv->vval.v_float = sqrt(f); | |
10567 else | |
10568 rettv->vval.v_float = 0.0; | |
10569 } | |
10570 | |
10571 /* | |
10572 * "str2float()" function | |
10573 */ | |
10574 static void | |
10575 f_str2float(typval_T *argvars, typval_T *rettv) | |
10576 { | |
10577 char_u *p = skipwhite(get_tv_string(&argvars[0])); | |
10578 | |
10579 if (*p == '+') | |
10580 p = skipwhite(p + 1); | |
10581 (void)string2float(p, &rettv->vval.v_float); | |
10582 rettv->v_type = VAR_FLOAT; | |
10583 } | |
10584 #endif | |
10585 | |
10586 /* | |
10587 * "str2nr()" function | |
10588 */ | |
10589 static void | |
10590 f_str2nr(typval_T *argvars, typval_T *rettv) | |
10591 { | |
10592 int base = 10; | |
10593 char_u *p; | |
10594 varnumber_T n; | |
10595 int what; | |
10596 | |
10597 if (argvars[1].v_type != VAR_UNKNOWN) | |
10598 { | |
10599 base = (int)get_tv_number(&argvars[1]); | |
10600 if (base != 2 && base != 8 && base != 10 && base != 16) | |
10601 { | |
10602 EMSG(_(e_invarg)); | |
10603 return; | |
10604 } | |
10605 } | |
10606 | |
10607 p = skipwhite(get_tv_string(&argvars[0])); | |
10608 if (*p == '+') | |
10609 p = skipwhite(p + 1); | |
10610 switch (base) | |
10611 { | |
10612 case 2: what = STR2NR_BIN + STR2NR_FORCE; break; | |
10613 case 8: what = STR2NR_OCT + STR2NR_FORCE; break; | |
10614 case 16: what = STR2NR_HEX + STR2NR_FORCE; break; | |
10615 default: what = 0; | |
10616 } | |
10617 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); | |
10618 rettv->vval.v_number = n; | |
10619 } | |
10620 | |
10621 #ifdef HAVE_STRFTIME | |
10622 /* | |
10623 * "strftime({format}[, {time}])" function | |
10624 */ | |
10625 static void | |
10626 f_strftime(typval_T *argvars, typval_T *rettv) | |
10627 { | |
10628 char_u result_buf[256]; | |
10629 struct tm *curtime; | |
10630 time_t seconds; | |
10631 char_u *p; | |
10632 | |
10633 rettv->v_type = VAR_STRING; | |
10634 | |
10635 p = get_tv_string(&argvars[0]); | |
10636 if (argvars[1].v_type == VAR_UNKNOWN) | |
10637 seconds = time(NULL); | |
10638 else | |
10639 seconds = (time_t)get_tv_number(&argvars[1]); | |
10640 curtime = localtime(&seconds); | |
10641 /* MSVC returns NULL for an invalid value of seconds. */ | |
10642 if (curtime == NULL) | |
10643 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); | |
10644 else | |
10645 { | |
10646 # ifdef FEAT_MBYTE | |
10647 vimconv_T conv; | |
10648 char_u *enc; | |
10649 | |
10650 conv.vc_type = CONV_NONE; | |
10651 enc = enc_locale(); | |
10652 convert_setup(&conv, p_enc, enc); | |
10653 if (conv.vc_type != CONV_NONE) | |
10654 p = string_convert(&conv, p, NULL); | |
10655 # endif | |
10656 if (p != NULL) | |
10657 (void)strftime((char *)result_buf, sizeof(result_buf), | |
10658 (char *)p, curtime); | |
10659 else | |
10660 result_buf[0] = NUL; | |
10661 | |
10662 # ifdef FEAT_MBYTE | |
10663 if (conv.vc_type != CONV_NONE) | |
10664 vim_free(p); | |
10665 convert_setup(&conv, enc, p_enc); | |
10666 if (conv.vc_type != CONV_NONE) | |
10667 rettv->vval.v_string = string_convert(&conv, result_buf, NULL); | |
10668 else | |
10669 # endif | |
10670 rettv->vval.v_string = vim_strsave(result_buf); | |
10671 | |
10672 # ifdef FEAT_MBYTE | |
10673 /* Release conversion descriptors */ | |
10674 convert_setup(&conv, NULL, NULL); | |
10675 vim_free(enc); | |
10676 # endif | |
10677 } | |
10678 } | |
10679 #endif | |
10680 | |
10681 /* | |
10682 * "strgetchar()" function | |
10683 */ | |
10684 static void | |
10685 f_strgetchar(typval_T *argvars, typval_T *rettv) | |
10686 { | |
10687 char_u *str; | |
10688 int len; | |
10689 int error = FALSE; | |
10690 int charidx; | |
10691 | |
10692 rettv->vval.v_number = -1; | |
10693 str = get_tv_string_chk(&argvars[0]); | |
10694 if (str == NULL) | |
10695 return; | |
10696 len = (int)STRLEN(str); | |
10697 charidx = (int)get_tv_number_chk(&argvars[1], &error); | |
10698 if (error) | |
10699 return; | |
10700 #ifdef FEAT_MBYTE | |
10701 { | |
10702 int byteidx = 0; | |
10703 | |
10704 while (charidx >= 0 && byteidx < len) | |
10705 { | |
10706 if (charidx == 0) | |
10707 { | |
10708 rettv->vval.v_number = mb_ptr2char(str + byteidx); | |
10709 break; | |
10710 } | |
10711 --charidx; | |
10712 byteidx += mb_cptr2len(str + byteidx); | |
10713 } | |
10714 } | |
10715 #else | |
10716 if (charidx < len) | |
10717 rettv->vval.v_number = str[charidx]; | |
10718 #endif | |
10719 } | |
10720 | |
10721 /* | |
10722 * "stridx()" function | |
10723 */ | |
10724 static void | |
10725 f_stridx(typval_T *argvars, typval_T *rettv) | |
10726 { | |
10727 char_u buf[NUMBUFLEN]; | |
10728 char_u *needle; | |
10729 char_u *haystack; | |
10730 char_u *save_haystack; | |
10731 char_u *pos; | |
10732 int start_idx; | |
10733 | |
10734 needle = get_tv_string_chk(&argvars[1]); | |
10735 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf); | |
10736 rettv->vval.v_number = -1; | |
10737 if (needle == NULL || haystack == NULL) | |
10738 return; /* type error; errmsg already given */ | |
10739 | |
10740 if (argvars[2].v_type != VAR_UNKNOWN) | |
10741 { | |
10742 int error = FALSE; | |
10743 | |
10744 start_idx = (int)get_tv_number_chk(&argvars[2], &error); | |
10745 if (error || start_idx >= (int)STRLEN(haystack)) | |
10746 return; | |
10747 if (start_idx >= 0) | |
10748 haystack += start_idx; | |
10749 } | |
10750 | |
10751 pos = (char_u *)strstr((char *)haystack, (char *)needle); | |
10752 if (pos != NULL) | |
10753 rettv->vval.v_number = (varnumber_T)(pos - save_haystack); | |
10754 } | |
10755 | |
10756 /* | |
10757 * "string()" function | |
10758 */ | |
10759 static void | |
10760 f_string(typval_T *argvars, typval_T *rettv) | |
10761 { | |
10762 char_u *tofree; | |
10763 char_u numbuf[NUMBUFLEN]; | |
10764 | |
10765 rettv->v_type = VAR_STRING; | |
10766 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, | |
10767 get_copyID()); | |
10768 /* Make a copy if we have a value but it's not in allocated memory. */ | |
10769 if (rettv->vval.v_string != NULL && tofree == NULL) | |
10770 rettv->vval.v_string = vim_strsave(rettv->vval.v_string); | |
10771 } | |
10772 | |
10773 /* | |
10774 * "strlen()" function | |
10775 */ | |
10776 static void | |
10777 f_strlen(typval_T *argvars, typval_T *rettv) | |
10778 { | |
10779 rettv->vval.v_number = (varnumber_T)(STRLEN( | |
10780 get_tv_string(&argvars[0]))); | |
10781 } | |
10782 | |
10783 /* | |
10784 * "strchars()" function | |
10785 */ | |
10786 static void | |
10787 f_strchars(typval_T *argvars, typval_T *rettv) | |
10788 { | |
10789 char_u *s = get_tv_string(&argvars[0]); | |
10790 int skipcc = 0; | |
10791 #ifdef FEAT_MBYTE | |
10792 varnumber_T len = 0; | |
10793 int (*func_mb_ptr2char_adv)(char_u **pp); | |
10794 #endif | |
10795 | |
10796 if (argvars[1].v_type != VAR_UNKNOWN) | |
10797 skipcc = (int)get_tv_number_chk(&argvars[1], NULL); | |
10798 if (skipcc < 0 || skipcc > 1) | |
10799 EMSG(_(e_invarg)); | |
10800 else | |
10801 { | |
10802 #ifdef FEAT_MBYTE | |
10803 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; | |
10804 while (*s != NUL) | |
10805 { | |
10806 func_mb_ptr2char_adv(&s); | |
10807 ++len; | |
10808 } | |
10809 rettv->vval.v_number = len; | |
10810 #else | |
10811 rettv->vval.v_number = (varnumber_T)(STRLEN(s)); | |
10812 #endif | |
10813 } | |
10814 } | |
10815 | |
10816 /* | |
10817 * "strdisplaywidth()" function | |
10818 */ | |
10819 static void | |
10820 f_strdisplaywidth(typval_T *argvars, typval_T *rettv) | |
10821 { | |
10822 char_u *s = get_tv_string(&argvars[0]); | |
10823 int col = 0; | |
10824 | |
10825 if (argvars[1].v_type != VAR_UNKNOWN) | |
10826 col = (int)get_tv_number(&argvars[1]); | |
10827 | |
10828 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col); | |
10829 } | |
10830 | |
10831 /* | |
10832 * "strwidth()" function | |
10833 */ | |
10834 static void | |
10835 f_strwidth(typval_T *argvars, typval_T *rettv) | |
10836 { | |
10837 char_u *s = get_tv_string(&argvars[0]); | |
10838 | |
10839 rettv->vval.v_number = (varnumber_T)( | |
10840 #ifdef FEAT_MBYTE | |
10841 mb_string2cells(s, -1) | |
10842 #else | |
10843 STRLEN(s) | |
10844 #endif | |
10845 ); | |
10846 } | |
10847 | |
10848 /* | |
10849 * "strcharpart()" function | |
10850 */ | |
10851 static void | |
10852 f_strcharpart(typval_T *argvars, typval_T *rettv) | |
10853 { | |
10854 #ifdef FEAT_MBYTE | |
10855 char_u *p; | |
10856 int nchar; | |
10857 int nbyte = 0; | |
10858 int charlen; | |
10859 int len = 0; | |
10860 int slen; | |
10861 int error = FALSE; | |
10862 | |
10863 p = get_tv_string(&argvars[0]); | |
10864 slen = (int)STRLEN(p); | |
10865 | |
10866 nchar = (int)get_tv_number_chk(&argvars[1], &error); | |
10867 if (!error) | |
10868 { | |
10869 if (nchar > 0) | |
10870 while (nchar > 0 && nbyte < slen) | |
10871 { | |
10872 nbyte += mb_cptr2len(p + nbyte); | |
10873 --nchar; | |
10874 } | |
10875 else | |
10876 nbyte = nchar; | |
10877 if (argvars[2].v_type != VAR_UNKNOWN) | |
10878 { | |
10879 charlen = (int)get_tv_number(&argvars[2]); | |
10880 while (charlen > 0 && nbyte + len < slen) | |
10881 { | |
10882 int off = nbyte + len; | |
10883 | |
10884 if (off < 0) | |
10885 len += 1; | |
10886 else | |
10887 len += mb_cptr2len(p + off); | |
10888 --charlen; | |
10889 } | |
10890 } | |
10891 else | |
10892 len = slen - nbyte; /* default: all bytes that are available. */ | |
10893 } | |
10894 | |
10895 /* | |
10896 * Only return the overlap between the specified part and the actual | |
10897 * string. | |
10898 */ | |
10899 if (nbyte < 0) | |
10900 { | |
10901 len += nbyte; | |
10902 nbyte = 0; | |
10903 } | |
10904 else if (nbyte > slen) | |
10905 nbyte = slen; | |
10906 if (len < 0) | |
10907 len = 0; | |
10908 else if (nbyte + len > slen) | |
10909 len = slen - nbyte; | |
10910 | |
10911 rettv->v_type = VAR_STRING; | |
10912 rettv->vval.v_string = vim_strnsave(p + nbyte, len); | |
10913 #else | |
10914 f_strpart(argvars, rettv); | |
10915 #endif | |
10916 } | |
10917 | |
10918 /* | |
10919 * "strpart()" function | |
10920 */ | |
10921 static void | |
10922 f_strpart(typval_T *argvars, typval_T *rettv) | |
10923 { | |
10924 char_u *p; | |
10925 int n; | |
10926 int len; | |
10927 int slen; | |
10928 int error = FALSE; | |
10929 | |
10930 p = get_tv_string(&argvars[0]); | |
10931 slen = (int)STRLEN(p); | |
10932 | |
10933 n = (int)get_tv_number_chk(&argvars[1], &error); | |
10934 if (error) | |
10935 len = 0; | |
10936 else if (argvars[2].v_type != VAR_UNKNOWN) | |
10937 len = (int)get_tv_number(&argvars[2]); | |
10938 else | |
10939 len = slen - n; /* default len: all bytes that are available. */ | |
10940 | |
10941 /* | |
10942 * Only return the overlap between the specified part and the actual | |
10943 * string. | |
10944 */ | |
10945 if (n < 0) | |
10946 { | |
10947 len += n; | |
10948 n = 0; | |
10949 } | |
10950 else if (n > slen) | |
10951 n = slen; | |
10952 if (len < 0) | |
10953 len = 0; | |
10954 else if (n + len > slen) | |
10955 len = slen - n; | |
10956 | |
10957 rettv->v_type = VAR_STRING; | |
10958 rettv->vval.v_string = vim_strnsave(p + n, len); | |
10959 } | |
10960 | |
10961 /* | |
10962 * "strridx()" function | |
10963 */ | |
10964 static void | |
10965 f_strridx(typval_T *argvars, typval_T *rettv) | |
10966 { | |
10967 char_u buf[NUMBUFLEN]; | |
10968 char_u *needle; | |
10969 char_u *haystack; | |
10970 char_u *rest; | |
10971 char_u *lastmatch = NULL; | |
10972 int haystack_len, end_idx; | |
10973 | |
10974 needle = get_tv_string_chk(&argvars[1]); | |
10975 haystack = get_tv_string_buf_chk(&argvars[0], buf); | |
10976 | |
10977 rettv->vval.v_number = -1; | |
10978 if (needle == NULL || haystack == NULL) | |
10979 return; /* type error; errmsg already given */ | |
10980 | |
10981 haystack_len = (int)STRLEN(haystack); | |
10982 if (argvars[2].v_type != VAR_UNKNOWN) | |
10983 { | |
10984 /* Third argument: upper limit for index */ | |
10985 end_idx = (int)get_tv_number_chk(&argvars[2], NULL); | |
10986 if (end_idx < 0) | |
10987 return; /* can never find a match */ | |
10988 } | |
10989 else | |
10990 end_idx = haystack_len; | |
10991 | |
10992 if (*needle == NUL) | |
10993 { | |
10994 /* Empty string matches past the end. */ | |
10995 lastmatch = haystack + end_idx; | |
10996 } | |
10997 else | |
10998 { | |
10999 for (rest = haystack; *rest != '\0'; ++rest) | |
11000 { | |
11001 rest = (char_u *)strstr((char *)rest, (char *)needle); | |
11002 if (rest == NULL || rest > haystack + end_idx) | |
11003 break; | |
11004 lastmatch = rest; | |
11005 } | |
11006 } | |
11007 | |
11008 if (lastmatch == NULL) | |
11009 rettv->vval.v_number = -1; | |
11010 else | |
11011 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); | |
11012 } | |
11013 | |
11014 /* | |
11015 * "strtrans()" function | |
11016 */ | |
11017 static void | |
11018 f_strtrans(typval_T *argvars, typval_T *rettv) | |
11019 { | |
11020 rettv->v_type = VAR_STRING; | |
11021 rettv->vval.v_string = transstr(get_tv_string(&argvars[0])); | |
11022 } | |
11023 | |
11024 /* | |
11025 * "submatch()" function | |
11026 */ | |
11027 static void | |
11028 f_submatch(typval_T *argvars, typval_T *rettv) | |
11029 { | |
11030 int error = FALSE; | |
11031 int no; | |
11032 int retList = 0; | |
11033 | |
11034 no = (int)get_tv_number_chk(&argvars[0], &error); | |
11035 if (error) | |
11036 return; | |
11037 error = FALSE; | |
11038 if (argvars[1].v_type != VAR_UNKNOWN) | |
11039 retList = (int)get_tv_number_chk(&argvars[1], &error); | |
11040 if (error) | |
11041 return; | |
11042 | |
11043 if (retList == 0) | |
11044 { | |
11045 rettv->v_type = VAR_STRING; | |
11046 rettv->vval.v_string = reg_submatch(no); | |
11047 } | |
11048 else | |
11049 { | |
11050 rettv->v_type = VAR_LIST; | |
11051 rettv->vval.v_list = reg_submatch_list(no); | |
11052 } | |
11053 } | |
11054 | |
11055 /* | |
11056 * "substitute()" function | |
11057 */ | |
11058 static void | |
11059 f_substitute(typval_T *argvars, typval_T *rettv) | |
11060 { | |
11061 char_u patbuf[NUMBUFLEN]; | |
11062 char_u subbuf[NUMBUFLEN]; | |
11063 char_u flagsbuf[NUMBUFLEN]; | |
11064 | |
11065 char_u *str = get_tv_string_chk(&argvars[0]); | |
11066 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf); | |
11067 char_u *sub = get_tv_string_buf_chk(&argvars[2], subbuf); | |
11068 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf); | |
11069 | |
11070 rettv->v_type = VAR_STRING; | |
11071 if (str == NULL || pat == NULL || sub == NULL || flg == NULL) | |
11072 rettv->vval.v_string = NULL; | |
11073 else | |
11074 rettv->vval.v_string = do_string_sub(str, pat, sub, flg); | |
11075 } | |
11076 | |
11077 /* | |
11078 * "synID(lnum, col, trans)" function | |
11079 */ | |
11080 static void | |
11081 f_synID(typval_T *argvars UNUSED, typval_T *rettv) | |
11082 { | |
11083 int id = 0; | |
11084 #ifdef FEAT_SYN_HL | |
11085 linenr_T lnum; | |
11086 colnr_T col; | |
11087 int trans; | |
11088 int transerr = FALSE; | |
11089 | |
11090 lnum = get_tv_lnum(argvars); /* -1 on type error */ | |
11091 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ | |
11092 trans = (int)get_tv_number_chk(&argvars[2], &transerr); | |
11093 | |
11094 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count | |
11095 && col >= 0 && col < (long)STRLEN(ml_get(lnum))) | |
11096 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE); | |
11097 #endif | |
11098 | |
11099 rettv->vval.v_number = id; | |
11100 } | |
11101 | |
11102 /* | |
11103 * "synIDattr(id, what [, mode])" function | |
11104 */ | |
11105 static void | |
11106 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) | |
11107 { | |
11108 char_u *p = NULL; | |
11109 #ifdef FEAT_SYN_HL | |
11110 int id; | |
11111 char_u *what; | |
11112 char_u *mode; | |
11113 char_u modebuf[NUMBUFLEN]; | |
11114 int modec; | |
11115 | |
11116 id = (int)get_tv_number(&argvars[0]); | |
11117 what = get_tv_string(&argvars[1]); | |
11118 if (argvars[2].v_type != VAR_UNKNOWN) | |
11119 { | |
11120 mode = get_tv_string_buf(&argvars[2], modebuf); | |
11121 modec = TOLOWER_ASC(mode[0]); | |
11122 if (modec != 't' && modec != 'c' && modec != 'g') | |
11123 modec = 0; /* replace invalid with current */ | |
11124 } | |
11125 else | |
11126 { | |
11127 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) | |
11128 if (USE_24BIT) | |
11129 modec = 'g'; | |
11130 else | |
11131 #endif | |
11132 if (t_colors > 1) | |
11133 modec = 'c'; | |
11134 else | |
11135 modec = 't'; | |
11136 } | |
11137 | |
11138 | |
11139 switch (TOLOWER_ASC(what[0])) | |
11140 { | |
11141 case 'b': | |
11142 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */ | |
11143 p = highlight_color(id, what, modec); | |
11144 else /* bold */ | |
11145 p = highlight_has_attr(id, HL_BOLD, modec); | |
11146 break; | |
11147 | |
11148 case 'f': /* fg[#] or font */ | |
11149 p = highlight_color(id, what, modec); | |
11150 break; | |
11151 | |
11152 case 'i': | |
11153 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */ | |
11154 p = highlight_has_attr(id, HL_INVERSE, modec); | |
11155 else /* italic */ | |
11156 p = highlight_has_attr(id, HL_ITALIC, modec); | |
11157 break; | |
11158 | |
11159 case 'n': /* name */ | |
11160 p = get_highlight_name(NULL, id - 1); | |
11161 break; | |
11162 | |
11163 case 'r': /* reverse */ | |
11164 p = highlight_has_attr(id, HL_INVERSE, modec); | |
11165 break; | |
11166 | |
11167 case 's': | |
11168 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */ | |
11169 p = highlight_color(id, what, modec); | |
11170 else /* standout */ | |
11171 p = highlight_has_attr(id, HL_STANDOUT, modec); | |
11172 break; | |
11173 | |
11174 case 'u': | |
11175 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') | |
11176 /* underline */ | |
11177 p = highlight_has_attr(id, HL_UNDERLINE, modec); | |
11178 else | |
11179 /* undercurl */ | |
11180 p = highlight_has_attr(id, HL_UNDERCURL, modec); | |
11181 break; | |
11182 } | |
11183 | |
11184 if (p != NULL) | |
11185 p = vim_strsave(p); | |
11186 #endif | |
11187 rettv->v_type = VAR_STRING; | |
11188 rettv->vval.v_string = p; | |
11189 } | |
11190 | |
11191 /* | |
11192 * "synIDtrans(id)" function | |
11193 */ | |
11194 static void | |
11195 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv) | |
11196 { | |
11197 int id; | |
11198 | |
11199 #ifdef FEAT_SYN_HL | |
11200 id = (int)get_tv_number(&argvars[0]); | |
11201 | |
11202 if (id > 0) | |
11203 id = syn_get_final_id(id); | |
11204 else | |
11205 #endif | |
11206 id = 0; | |
11207 | |
11208 rettv->vval.v_number = id; | |
11209 } | |
11210 | |
11211 /* | |
11212 * "synconcealed(lnum, col)" function | |
11213 */ | |
11214 static void | |
11215 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) | |
11216 { | |
11217 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) | |
11218 linenr_T lnum; | |
11219 colnr_T col; | |
11220 int syntax_flags = 0; | |
11221 int cchar; | |
11222 int matchid = 0; | |
11223 char_u str[NUMBUFLEN]; | |
11224 #endif | |
11225 | |
11226 rettv->v_type = VAR_LIST; | |
11227 rettv->vval.v_list = NULL; | |
11228 | |
11229 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) | |
11230 lnum = get_tv_lnum(argvars); /* -1 on type error */ | |
11231 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ | |
11232 | |
11233 vim_memset(str, NUL, sizeof(str)); | |
11234 | |
11235 if (rettv_list_alloc(rettv) != FAIL) | |
11236 { | |
11237 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count | |
11238 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) | |
11239 && curwin->w_p_cole > 0) | |
11240 { | |
11241 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE); | |
11242 syntax_flags = get_syntax_info(&matchid); | |
11243 | |
11244 /* get the conceal character */ | |
11245 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) | |
11246 { | |
11247 cchar = syn_get_sub_char(); | |
11248 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL) | |
11249 cchar = lcs_conceal; | |
11250 if (cchar != NUL) | |
11251 { | |
11252 # ifdef FEAT_MBYTE | |
11253 if (has_mbyte) | |
11254 (*mb_char2bytes)(cchar, str); | |
11255 else | |
11256 # endif | |
11257 str[0] = cchar; | |
11258 } | |
11259 } | |
11260 } | |
11261 | |
11262 list_append_number(rettv->vval.v_list, | |
11263 (syntax_flags & HL_CONCEAL) != 0); | |
11264 /* -1 to auto-determine strlen */ | |
11265 list_append_string(rettv->vval.v_list, str, -1); | |
11266 list_append_number(rettv->vval.v_list, matchid); | |
11267 } | |
11268 #endif | |
11269 } | |
11270 | |
11271 /* | |
11272 * "synstack(lnum, col)" function | |
11273 */ | |
11274 static void | |
11275 f_synstack(typval_T *argvars UNUSED, typval_T *rettv) | |
11276 { | |
11277 #ifdef FEAT_SYN_HL | |
11278 linenr_T lnum; | |
11279 colnr_T col; | |
11280 int i; | |
11281 int id; | |
11282 #endif | |
11283 | |
11284 rettv->v_type = VAR_LIST; | |
11285 rettv->vval.v_list = NULL; | |
11286 | |
11287 #ifdef FEAT_SYN_HL | |
11288 lnum = get_tv_lnum(argvars); /* -1 on type error */ | |
11289 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ | |
11290 | |
11291 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count | |
11292 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) | |
11293 && rettv_list_alloc(rettv) != FAIL) | |
11294 { | |
11295 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE); | |
11296 for (i = 0; ; ++i) | |
11297 { | |
11298 id = syn_get_stack_item(i); | |
11299 if (id < 0) | |
11300 break; | |
11301 if (list_append_number(rettv->vval.v_list, id) == FAIL) | |
11302 break; | |
11303 } | |
11304 } | |
11305 #endif | |
11306 } | |
11307 | |
11308 static void | |
11309 get_cmd_output_as_rettv( | |
11310 typval_T *argvars, | |
11311 typval_T *rettv, | |
11312 int retlist) | |
11313 { | |
11314 char_u *res = NULL; | |
11315 char_u *p; | |
11316 char_u *infile = NULL; | |
11317 char_u buf[NUMBUFLEN]; | |
11318 int err = FALSE; | |
11319 FILE *fd; | |
11320 list_T *list = NULL; | |
11321 int flags = SHELL_SILENT; | |
11322 | |
11323 rettv->v_type = VAR_STRING; | |
11324 rettv->vval.v_string = NULL; | |
11325 if (check_restricted() || check_secure()) | |
11326 goto errret; | |
11327 | |
11328 if (argvars[1].v_type != VAR_UNKNOWN) | |
11329 { | |
11330 /* | |
11331 * Write the string to a temp file, to be used for input of the shell | |
11332 * command. | |
11333 */ | |
11334 if ((infile = vim_tempname('i', TRUE)) == NULL) | |
11335 { | |
11336 EMSG(_(e_notmp)); | |
11337 goto errret; | |
11338 } | |
11339 | |
11340 fd = mch_fopen((char *)infile, WRITEBIN); | |
11341 if (fd == NULL) | |
11342 { | |
11343 EMSG2(_(e_notopen), infile); | |
11344 goto errret; | |
11345 } | |
11346 if (argvars[1].v_type == VAR_LIST) | |
11347 { | |
11348 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL) | |
11349 err = TRUE; | |
11350 } | |
11351 else | |
11352 { | |
11353 size_t len; | |
11354 | |
11355 p = get_tv_string_buf_chk(&argvars[1], buf); | |
11356 if (p == NULL) | |
11357 { | |
11358 fclose(fd); | |
11359 goto errret; /* type error; errmsg already given */ | |
11360 } | |
11361 len = STRLEN(p); | |
11362 if (len > 0 && fwrite(p, len, 1, fd) != 1) | |
11363 err = TRUE; | |
11364 } | |
11365 if (fclose(fd) != 0) | |
11366 err = TRUE; | |
11367 if (err) | |
11368 { | |
11369 EMSG(_("E677: Error writing temp file")); | |
11370 goto errret; | |
11371 } | |
11372 } | |
11373 | |
11374 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell | |
11375 * echoes typeahead, that messes up the display. */ | |
11376 if (!msg_silent) | |
11377 flags += SHELL_COOKED; | |
11378 | |
11379 if (retlist) | |
11380 { | |
11381 int len; | |
11382 listitem_T *li; | |
11383 char_u *s = NULL; | |
11384 char_u *start; | |
11385 char_u *end; | |
11386 int i; | |
11387 | |
11388 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len); | |
11389 if (res == NULL) | |
11390 goto errret; | |
11391 | |
11392 list = list_alloc(); | |
11393 if (list == NULL) | |
11394 goto errret; | |
11395 | |
11396 for (i = 0; i < len; ++i) | |
11397 { | |
11398 start = res + i; | |
11399 while (i < len && res[i] != NL) | |
11400 ++i; | |
11401 end = res + i; | |
11402 | |
11403 s = alloc((unsigned)(end - start + 1)); | |
11404 if (s == NULL) | |
11405 goto errret; | |
11406 | |
11407 for (p = s; start < end; ++p, ++start) | |
11408 *p = *start == NUL ? NL : *start; | |
11409 *p = NUL; | |
11410 | |
11411 li = listitem_alloc(); | |
11412 if (li == NULL) | |
11413 { | |
11414 vim_free(s); | |
11415 goto errret; | |
11416 } | |
11417 li->li_tv.v_type = VAR_STRING; | |
11418 li->li_tv.v_lock = 0; | |
11419 li->li_tv.vval.v_string = s; | |
11420 list_append(list, li); | |
11421 } | |
11422 | |
11423 ++list->lv_refcount; | |
11424 rettv->v_type = VAR_LIST; | |
11425 rettv->vval.v_list = list; | |
11426 list = NULL; | |
11427 } | |
11428 else | |
11429 { | |
11430 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL); | |
11431 #ifdef USE_CR | |
11432 /* translate <CR> into <NL> */ | |
11433 if (res != NULL) | |
11434 { | |
11435 char_u *s; | |
11436 | |
11437 for (s = res; *s; ++s) | |
11438 { | |
11439 if (*s == CAR) | |
11440 *s = NL; | |
11441 } | |
11442 } | |
11443 #else | |
11444 # ifdef USE_CRNL | |
11445 /* translate <CR><NL> into <NL> */ | |
11446 if (res != NULL) | |
11447 { | |
11448 char_u *s, *d; | |
11449 | |
11450 d = res; | |
11451 for (s = res; *s; ++s) | |
11452 { | |
11453 if (s[0] == CAR && s[1] == NL) | |
11454 ++s; | |
11455 *d++ = *s; | |
11456 } | |
11457 *d = NUL; | |
11458 } | |
11459 # endif | |
11460 #endif | |
11461 rettv->vval.v_string = res; | |
11462 res = NULL; | |
11463 } | |
11464 | |
11465 errret: | |
11466 if (infile != NULL) | |
11467 { | |
11468 mch_remove(infile); | |
11469 vim_free(infile); | |
11470 } | |
11471 if (res != NULL) | |
11472 vim_free(res); | |
11473 if (list != NULL) | |
11474 list_free(list); | |
11475 } | |
11476 | |
11477 /* | |
11478 * "system()" function | |
11479 */ | |
11480 static void | |
11481 f_system(typval_T *argvars, typval_T *rettv) | |
11482 { | |
11483 get_cmd_output_as_rettv(argvars, rettv, FALSE); | |
11484 } | |
11485 | |
11486 /* | |
11487 * "systemlist()" function | |
11488 */ | |
11489 static void | |
11490 f_systemlist(typval_T *argvars, typval_T *rettv) | |
11491 { | |
11492 get_cmd_output_as_rettv(argvars, rettv, TRUE); | |
11493 } | |
11494 | |
11495 /* | |
11496 * "tabpagebuflist()" function | |
11497 */ | |
11498 static void | |
11499 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
11500 { | |
11501 #ifdef FEAT_WINDOWS | |
11502 tabpage_T *tp; | |
11503 win_T *wp = NULL; | |
11504 | |
11505 if (argvars[0].v_type == VAR_UNKNOWN) | |
11506 wp = firstwin; | |
11507 else | |
11508 { | |
11509 tp = find_tabpage((int)get_tv_number(&argvars[0])); | |
11510 if (tp != NULL) | |
11511 wp = (tp == curtab) ? firstwin : tp->tp_firstwin; | |
11512 } | |
11513 if (wp != NULL && rettv_list_alloc(rettv) != FAIL) | |
11514 { | |
11515 for (; wp != NULL; wp = wp->w_next) | |
11516 if (list_append_number(rettv->vval.v_list, | |
11517 wp->w_buffer->b_fnum) == FAIL) | |
11518 break; | |
11519 } | |
11520 #endif | |
11521 } | |
11522 | |
11523 | |
11524 /* | |
11525 * "tabpagenr()" function | |
11526 */ | |
11527 static void | |
11528 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv) | |
11529 { | |
11530 int nr = 1; | |
11531 #ifdef FEAT_WINDOWS | |
11532 char_u *arg; | |
11533 | |
11534 if (argvars[0].v_type != VAR_UNKNOWN) | |
11535 { | |
11536 arg = get_tv_string_chk(&argvars[0]); | |
11537 nr = 0; | |
11538 if (arg != NULL) | |
11539 { | |
11540 if (STRCMP(arg, "$") == 0) | |
11541 nr = tabpage_index(NULL) - 1; | |
11542 else | |
11543 EMSG2(_(e_invexpr2), arg); | |
11544 } | |
11545 } | |
11546 else | |
11547 nr = tabpage_index(curtab); | |
11548 #endif | |
11549 rettv->vval.v_number = nr; | |
11550 } | |
11551 | |
11552 | |
11553 #ifdef FEAT_WINDOWS | |
11554 static int get_winnr(tabpage_T *tp, typval_T *argvar); | |
11555 | |
11556 /* | |
11557 * Common code for tabpagewinnr() and winnr(). | |
11558 */ | |
11559 static int | |
11560 get_winnr(tabpage_T *tp, typval_T *argvar) | |
11561 { | |
11562 win_T *twin; | |
11563 int nr = 1; | |
11564 win_T *wp; | |
11565 char_u *arg; | |
11566 | |
11567 twin = (tp == curtab) ? curwin : tp->tp_curwin; | |
11568 if (argvar->v_type != VAR_UNKNOWN) | |
11569 { | |
11570 arg = get_tv_string_chk(argvar); | |
11571 if (arg == NULL) | |
11572 nr = 0; /* type error; errmsg already given */ | |
11573 else if (STRCMP(arg, "$") == 0) | |
11574 twin = (tp == curtab) ? lastwin : tp->tp_lastwin; | |
11575 else if (STRCMP(arg, "#") == 0) | |
11576 { | |
11577 twin = (tp == curtab) ? prevwin : tp->tp_prevwin; | |
11578 if (twin == NULL) | |
11579 nr = 0; | |
11580 } | |
11581 else | |
11582 { | |
11583 EMSG2(_(e_invexpr2), arg); | |
11584 nr = 0; | |
11585 } | |
11586 } | |
11587 | |
11588 if (nr > 0) | |
11589 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; | |
11590 wp != twin; wp = wp->w_next) | |
11591 { | |
11592 if (wp == NULL) | |
11593 { | |
11594 /* didn't find it in this tabpage */ | |
11595 nr = 0; | |
11596 break; | |
11597 } | |
11598 ++nr; | |
11599 } | |
11600 return nr; | |
11601 } | |
11602 #endif | |
11603 | |
11604 /* | |
11605 * "tabpagewinnr()" function | |
11606 */ | |
11607 static void | |
11608 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) | |
11609 { | |
11610 int nr = 1; | |
11611 #ifdef FEAT_WINDOWS | |
11612 tabpage_T *tp; | |
11613 | |
11614 tp = find_tabpage((int)get_tv_number(&argvars[0])); | |
11615 if (tp == NULL) | |
11616 nr = 0; | |
11617 else | |
11618 nr = get_winnr(tp, &argvars[1]); | |
11619 #endif | |
11620 rettv->vval.v_number = nr; | |
11621 } | |
11622 | |
11623 | |
11624 /* | |
11625 * "tagfiles()" function | |
11626 */ | |
11627 static void | |
11628 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv) | |
11629 { | |
11630 char_u *fname; | |
11631 tagname_T tn; | |
11632 int first; | |
11633 | |
11634 if (rettv_list_alloc(rettv) == FAIL) | |
11635 return; | |
11636 fname = alloc(MAXPATHL); | |
11637 if (fname == NULL) | |
11638 return; | |
11639 | |
11640 for (first = TRUE; ; first = FALSE) | |
11641 if (get_tagfname(&tn, first, fname) == FAIL | |
11642 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL) | |
11643 break; | |
11644 tagname_free(&tn); | |
11645 vim_free(fname); | |
11646 } | |
11647 | |
11648 /* | |
11649 * "taglist()" function | |
11650 */ | |
11651 static void | |
11652 f_taglist(typval_T *argvars, typval_T *rettv) | |
11653 { | |
11654 char_u *tag_pattern; | |
11655 | |
11656 tag_pattern = get_tv_string(&argvars[0]); | |
11657 | |
11658 rettv->vval.v_number = FALSE; | |
11659 if (*tag_pattern == NUL) | |
11660 return; | |
11661 | |
11662 if (rettv_list_alloc(rettv) == OK) | |
11663 (void)get_tags(rettv->vval.v_list, tag_pattern); | |
11664 } | |
11665 | |
11666 /* | |
11667 * "tempname()" function | |
11668 */ | |
11669 static void | |
11670 f_tempname(typval_T *argvars UNUSED, typval_T *rettv) | |
11671 { | |
11672 static int x = 'A'; | |
11673 | |
11674 rettv->v_type = VAR_STRING; | |
11675 rettv->vval.v_string = vim_tempname(x, FALSE); | |
11676 | |
11677 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different | |
11678 * names. Skip 'I' and 'O', they are used for shell redirection. */ | |
11679 do | |
11680 { | |
11681 if (x == 'Z') | |
11682 x = '0'; | |
11683 else if (x == '9') | |
11684 x = 'A'; | |
11685 else | |
11686 { | |
11687 #ifdef EBCDIC | |
11688 if (x == 'I') | |
11689 x = 'J'; | |
11690 else if (x == 'R') | |
11691 x = 'S'; | |
11692 else | |
11693 #endif | |
11694 ++x; | |
11695 } | |
11696 } while (x == 'I' || x == 'O'); | |
11697 } | |
11698 | |
11699 #ifdef FEAT_FLOAT | |
11700 /* | |
11701 * "tan()" function | |
11702 */ | |
11703 static void | |
11704 f_tan(typval_T *argvars, typval_T *rettv) | |
11705 { | |
11706 float_T f = 0.0; | |
11707 | |
11708 rettv->v_type = VAR_FLOAT; | |
11709 if (get_float_arg(argvars, &f) == OK) | |
11710 rettv->vval.v_float = tan(f); | |
11711 else | |
11712 rettv->vval.v_float = 0.0; | |
11713 } | |
11714 | |
11715 /* | |
11716 * "tanh()" function | |
11717 */ | |
11718 static void | |
11719 f_tanh(typval_T *argvars, typval_T *rettv) | |
11720 { | |
11721 float_T f = 0.0; | |
11722 | |
11723 rettv->v_type = VAR_FLOAT; | |
11724 if (get_float_arg(argvars, &f) == OK) | |
11725 rettv->vval.v_float = tanh(f); | |
11726 else | |
11727 rettv->vval.v_float = 0.0; | |
11728 } | |
11729 #endif | |
11730 | |
11731 /* | |
11732 * "test_alloc_fail(id, countdown, repeat)" function | |
11733 */ | |
11734 static void | |
11735 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED) | |
11736 { | |
11737 if (argvars[0].v_type != VAR_NUMBER | |
11738 || argvars[0].vval.v_number <= 0 | |
11739 || argvars[1].v_type != VAR_NUMBER | |
11740 || argvars[1].vval.v_number < 0 | |
11741 || argvars[2].v_type != VAR_NUMBER) | |
11742 EMSG(_(e_invarg)); | |
11743 else | |
11744 { | |
11745 alloc_fail_id = argvars[0].vval.v_number; | |
11746 if (alloc_fail_id >= aid_last) | |
11747 EMSG(_(e_invarg)); | |
11748 alloc_fail_countdown = argvars[1].vval.v_number; | |
11749 alloc_fail_repeat = argvars[2].vval.v_number; | |
11750 did_outofmem_msg = FALSE; | |
11751 } | |
11752 } | |
11753 | |
11754 /* | |
11755 * "test_autochdir()" | |
11756 */ | |
11757 static void | |
11758 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
11759 { | |
11760 #if defined(FEAT_AUTOCHDIR) | |
11761 test_autochdir = TRUE; | |
11762 #endif | |
11763 } | |
11764 | |
11765 /* | |
11766 * "test_disable_char_avail({expr})" function | |
11767 */ | |
11768 static void | |
11769 f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED) | |
11770 { | |
11771 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]); | |
11772 } | |
11773 | |
11774 /* | |
11775 * "test_garbagecollect_now()" function | |
11776 */ | |
11777 static void | |
11778 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
11779 { | |
11780 /* This is dangerous, any Lists and Dicts used internally may be freed | |
11781 * while still in use. */ | |
11782 garbage_collect(TRUE); | |
11783 } | |
11784 | |
11785 #ifdef FEAT_JOB_CHANNEL | |
11786 static void | |
11787 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) | |
11788 { | |
11789 rettv->v_type = VAR_CHANNEL; | |
11790 rettv->vval.v_channel = NULL; | |
11791 } | |
11792 #endif | |
11793 | |
11794 static void | |
11795 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) | |
11796 { | |
11797 rettv->v_type = VAR_DICT; | |
11798 rettv->vval.v_dict = NULL; | |
11799 } | |
11800 | |
11801 #ifdef FEAT_JOB_CHANNEL | |
11802 static void | |
11803 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) | |
11804 { | |
11805 rettv->v_type = VAR_JOB; | |
11806 rettv->vval.v_job = NULL; | |
11807 } | |
11808 #endif | |
11809 | |
11810 static void | |
11811 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) | |
11812 { | |
11813 rettv->v_type = VAR_LIST; | |
11814 rettv->vval.v_list = NULL; | |
11815 } | |
11816 | |
11817 static void | |
11818 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) | |
11819 { | |
11820 rettv->v_type = VAR_PARTIAL; | |
11821 rettv->vval.v_partial = NULL; | |
11822 } | |
11823 | |
11824 static void | |
11825 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) | |
11826 { | |
11827 rettv->v_type = VAR_STRING; | |
11828 rettv->vval.v_string = NULL; | |
11829 } | |
11830 | |
11831 static void | |
11832 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) | |
11833 { | |
11834 time_for_testing = (time_t)get_tv_number(&argvars[0]); | |
11835 } | |
11836 | |
11837 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO) | |
11838 /* | |
11839 * Get a callback from "arg". It can be a Funcref or a function name. | |
11840 * When "arg" is zero return an empty string. | |
11841 * Return NULL for an invalid argument. | |
11842 */ | |
11843 char_u * | |
11844 get_callback(typval_T *arg, partial_T **pp) | |
11845 { | |
11846 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) | |
11847 { | |
11848 *pp = arg->vval.v_partial; | |
11849 ++(*pp)->pt_refcount; | |
11850 return (*pp)->pt_name; | |
11851 } | |
11852 *pp = NULL; | |
11853 if (arg->v_type == VAR_FUNC) | |
11854 { | |
11855 func_ref(arg->vval.v_string); | |
11856 return arg->vval.v_string; | |
11857 } | |
11858 if (arg->v_type == VAR_STRING) | |
11859 return arg->vval.v_string; | |
11860 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) | |
11861 return (char_u *)""; | |
11862 EMSG(_("E921: Invalid callback argument")); | |
11863 return NULL; | |
11864 } | |
11865 | |
11866 /* | |
11867 * Unref/free "callback" and "partial" retured by get_callback(). | |
11868 */ | |
11869 void | |
11870 free_callback(char_u *callback, partial_T *partial) | |
11871 { | |
11872 if (partial != NULL) | |
11873 partial_unref(partial); | |
11874 else if (callback != NULL) | |
11875 { | |
11876 func_unref(callback); | |
11877 vim_free(callback); | |
11878 } | |
11879 } | |
11880 #endif | |
11881 | |
11882 #ifdef FEAT_TIMERS | |
11883 /* | |
11884 * "timer_start(time, callback [, options])" function | |
11885 */ | |
11886 static void | |
11887 f_timer_start(typval_T *argvars, typval_T *rettv) | |
11888 { | |
11889 long msec = (long)get_tv_number(&argvars[0]); | |
11890 timer_T *timer; | |
11891 int repeat = 0; | |
11892 char_u *callback; | |
11893 dict_T *dict; | |
11894 | |
11895 if (check_secure()) | |
11896 return; | |
11897 if (argvars[2].v_type != VAR_UNKNOWN) | |
11898 { | |
11899 if (argvars[2].v_type != VAR_DICT | |
11900 || (dict = argvars[2].vval.v_dict) == NULL) | |
11901 { | |
11902 EMSG2(_(e_invarg2), get_tv_string(&argvars[2])); | |
11903 return; | |
11904 } | |
11905 if (dict_find(dict, (char_u *)"repeat", -1) != NULL) | |
11906 repeat = get_dict_number(dict, (char_u *)"repeat"); | |
11907 } | |
11908 | |
11909 timer = create_timer(msec, repeat); | |
11910 callback = get_callback(&argvars[1], &timer->tr_partial); | |
11911 if (callback == NULL) | |
11912 { | |
11913 stop_timer(timer); | |
11914 rettv->vval.v_number = -1; | |
11915 } | |
11916 else | |
11917 { | |
11918 timer->tr_callback = vim_strsave(callback); | |
11919 rettv->vval.v_number = timer->tr_id; | |
11920 } | |
11921 } | |
11922 | |
11923 /* | |
11924 * "timer_stop(timer)" function | |
11925 */ | |
11926 static void | |
11927 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) | |
11928 { | |
11929 timer_T *timer; | |
11930 | |
11931 if (argvars[0].v_type != VAR_NUMBER) | |
11932 { | |
11933 EMSG(_(e_number_exp)); | |
11934 return; | |
11935 } | |
11936 timer = find_timer((int)get_tv_number(&argvars[0])); | |
11937 if (timer != NULL) | |
11938 stop_timer(timer); | |
11939 } | |
11940 #endif | |
11941 | |
11942 /* | |
11943 * "tolower(string)" function | |
11944 */ | |
11945 static void | |
11946 f_tolower(typval_T *argvars, typval_T *rettv) | |
11947 { | |
11948 char_u *p; | |
11949 | |
11950 p = vim_strsave(get_tv_string(&argvars[0])); | |
11951 rettv->v_type = VAR_STRING; | |
11952 rettv->vval.v_string = p; | |
11953 | |
11954 if (p != NULL) | |
11955 while (*p != NUL) | |
11956 { | |
11957 #ifdef FEAT_MBYTE | |
11958 int l; | |
11959 | |
11960 if (enc_utf8) | |
11961 { | |
11962 int c, lc; | |
11963 | |
11964 c = utf_ptr2char(p); | |
11965 lc = utf_tolower(c); | |
11966 l = utf_ptr2len(p); | |
11967 /* TODO: reallocate string when byte count changes. */ | |
11968 if (utf_char2len(lc) == l) | |
11969 utf_char2bytes(lc, p); | |
11970 p += l; | |
11971 } | |
11972 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) | |
11973 p += l; /* skip multi-byte character */ | |
11974 else | |
11975 #endif | |
11976 { | |
11977 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */ | |
11978 ++p; | |
11979 } | |
11980 } | |
11981 } | |
11982 | |
11983 /* | |
11984 * "toupper(string)" function | |
11985 */ | |
11986 static void | |
11987 f_toupper(typval_T *argvars, typval_T *rettv) | |
11988 { | |
11989 rettv->v_type = VAR_STRING; | |
11990 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0])); | |
11991 } | |
11992 | |
11993 /* | |
11994 * "tr(string, fromstr, tostr)" function | |
11995 */ | |
11996 static void | |
11997 f_tr(typval_T *argvars, typval_T *rettv) | |
11998 { | |
11999 char_u *in_str; | |
12000 char_u *fromstr; | |
12001 char_u *tostr; | |
12002 char_u *p; | |
12003 #ifdef FEAT_MBYTE | |
12004 int inlen; | |
12005 int fromlen; | |
12006 int tolen; | |
12007 int idx; | |
12008 char_u *cpstr; | |
12009 int cplen; | |
12010 int first = TRUE; | |
12011 #endif | |
12012 char_u buf[NUMBUFLEN]; | |
12013 char_u buf2[NUMBUFLEN]; | |
12014 garray_T ga; | |
12015 | |
12016 in_str = get_tv_string(&argvars[0]); | |
12017 fromstr = get_tv_string_buf_chk(&argvars[1], buf); | |
12018 tostr = get_tv_string_buf_chk(&argvars[2], buf2); | |
12019 | |
12020 /* Default return value: empty string. */ | |
12021 rettv->v_type = VAR_STRING; | |
12022 rettv->vval.v_string = NULL; | |
12023 if (fromstr == NULL || tostr == NULL) | |
12024 return; /* type error; errmsg already given */ | |
12025 ga_init2(&ga, (int)sizeof(char), 80); | |
12026 | |
12027 #ifdef FEAT_MBYTE | |
12028 if (!has_mbyte) | |
12029 #endif | |
12030 /* not multi-byte: fromstr and tostr must be the same length */ | |
12031 if (STRLEN(fromstr) != STRLEN(tostr)) | |
12032 { | |
12033 #ifdef FEAT_MBYTE | |
12034 error: | |
12035 #endif | |
12036 EMSG2(_(e_invarg2), fromstr); | |
12037 ga_clear(&ga); | |
12038 return; | |
12039 } | |
12040 | |
12041 /* fromstr and tostr have to contain the same number of chars */ | |
12042 while (*in_str != NUL) | |
12043 { | |
12044 #ifdef FEAT_MBYTE | |
12045 if (has_mbyte) | |
12046 { | |
12047 inlen = (*mb_ptr2len)(in_str); | |
12048 cpstr = in_str; | |
12049 cplen = inlen; | |
12050 idx = 0; | |
12051 for (p = fromstr; *p != NUL; p += fromlen) | |
12052 { | |
12053 fromlen = (*mb_ptr2len)(p); | |
12054 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) | |
12055 { | |
12056 for (p = tostr; *p != NUL; p += tolen) | |
12057 { | |
12058 tolen = (*mb_ptr2len)(p); | |
12059 if (idx-- == 0) | |
12060 { | |
12061 cplen = tolen; | |
12062 cpstr = p; | |
12063 break; | |
12064 } | |
12065 } | |
12066 if (*p == NUL) /* tostr is shorter than fromstr */ | |
12067 goto error; | |
12068 break; | |
12069 } | |
12070 ++idx; | |
12071 } | |
12072 | |
12073 if (first && cpstr == in_str) | |
12074 { | |
12075 /* Check that fromstr and tostr have the same number of | |
12076 * (multi-byte) characters. Done only once when a character | |
12077 * of in_str doesn't appear in fromstr. */ | |
12078 first = FALSE; | |
12079 for (p = tostr; *p != NUL; p += tolen) | |
12080 { | |
12081 tolen = (*mb_ptr2len)(p); | |
12082 --idx; | |
12083 } | |
12084 if (idx != 0) | |
12085 goto error; | |
12086 } | |
12087 | |
12088 (void)ga_grow(&ga, cplen); | |
12089 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); | |
12090 ga.ga_len += cplen; | |
12091 | |
12092 in_str += inlen; | |
12093 } | |
12094 else | |
12095 #endif | |
12096 { | |
12097 /* When not using multi-byte chars we can do it faster. */ | |
12098 p = vim_strchr(fromstr, *in_str); | |
12099 if (p != NULL) | |
12100 ga_append(&ga, tostr[p - fromstr]); | |
12101 else | |
12102 ga_append(&ga, *in_str); | |
12103 ++in_str; | |
12104 } | |
12105 } | |
12106 | |
12107 /* add a terminating NUL */ | |
12108 (void)ga_grow(&ga, 1); | |
12109 ga_append(&ga, NUL); | |
12110 | |
12111 rettv->vval.v_string = ga.ga_data; | |
12112 } | |
12113 | |
12114 #ifdef FEAT_FLOAT | |
12115 /* | |
12116 * "trunc({float})" function | |
12117 */ | |
12118 static void | |
12119 f_trunc(typval_T *argvars, typval_T *rettv) | |
12120 { | |
12121 float_T f = 0.0; | |
12122 | |
12123 rettv->v_type = VAR_FLOAT; | |
12124 if (get_float_arg(argvars, &f) == OK) | |
12125 /* trunc() is not in C90, use floor() or ceil() instead. */ | |
12126 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); | |
12127 else | |
12128 rettv->vval.v_float = 0.0; | |
12129 } | |
12130 #endif | |
12131 | |
12132 /* | |
12133 * "type(expr)" function | |
12134 */ | |
12135 static void | |
12136 f_type(typval_T *argvars, typval_T *rettv) | |
12137 { | |
12138 int n = -1; | |
12139 | |
12140 switch (argvars[0].v_type) | |
12141 { | |
12142 case VAR_NUMBER: n = 0; break; | |
12143 case VAR_STRING: n = 1; break; | |
12144 case VAR_PARTIAL: | |
12145 case VAR_FUNC: n = 2; break; | |
12146 case VAR_LIST: n = 3; break; | |
12147 case VAR_DICT: n = 4; break; | |
12148 case VAR_FLOAT: n = 5; break; | |
12149 case VAR_SPECIAL: | |
12150 if (argvars[0].vval.v_number == VVAL_FALSE | |
12151 || argvars[0].vval.v_number == VVAL_TRUE) | |
12152 n = 6; | |
12153 else | |
12154 n = 7; | |
12155 break; | |
12156 case VAR_JOB: n = 8; break; | |
12157 case VAR_CHANNEL: n = 9; break; | |
12158 case VAR_UNKNOWN: | |
12159 EMSG2(_(e_intern2), "f_type(UNKNOWN)"); | |
12160 n = -1; | |
12161 break; | |
12162 } | |
12163 rettv->vval.v_number = n; | |
12164 } | |
12165 | |
12166 /* | |
12167 * "undofile(name)" function | |
12168 */ | |
12169 static void | |
12170 f_undofile(typval_T *argvars UNUSED, typval_T *rettv) | |
12171 { | |
12172 rettv->v_type = VAR_STRING; | |
12173 #ifdef FEAT_PERSISTENT_UNDO | |
12174 { | |
12175 char_u *fname = get_tv_string(&argvars[0]); | |
12176 | |
12177 if (*fname == NUL) | |
12178 { | |
12179 /* If there is no file name there will be no undo file. */ | |
12180 rettv->vval.v_string = NULL; | |
12181 } | |
12182 else | |
12183 { | |
12184 char_u *ffname = FullName_save(fname, FALSE); | |
12185 | |
12186 if (ffname != NULL) | |
12187 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE); | |
12188 vim_free(ffname); | |
12189 } | |
12190 } | |
12191 #else | |
12192 rettv->vval.v_string = NULL; | |
12193 #endif | |
12194 } | |
12195 | |
12196 /* | |
12197 * "undotree()" function | |
12198 */ | |
12199 static void | |
12200 f_undotree(typval_T *argvars UNUSED, typval_T *rettv) | |
12201 { | |
12202 if (rettv_dict_alloc(rettv) == OK) | |
12203 { | |
12204 dict_T *dict = rettv->vval.v_dict; | |
12205 list_T *list; | |
12206 | |
12207 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL); | |
12208 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL); | |
12209 dict_add_nr_str(dict, "save_last", | |
12210 (long)curbuf->b_u_save_nr_last, NULL); | |
12211 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL); | |
12212 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL); | |
12213 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL); | |
12214 | |
12215 list = list_alloc(); | |
12216 if (list != NULL) | |
12217 { | |
12218 u_eval_tree(curbuf->b_u_oldhead, list); | |
12219 dict_add_list(dict, "entries", list); | |
12220 } | |
12221 } | |
12222 } | |
12223 | |
12224 /* | |
12225 * "values(dict)" function | |
12226 */ | |
12227 static void | |
12228 f_values(typval_T *argvars, typval_T *rettv) | |
12229 { | |
12230 dict_list(argvars, rettv, 1); | |
12231 } | |
12232 | |
12233 /* | |
12234 * "virtcol(string)" function | |
12235 */ | |
12236 static void | |
12237 f_virtcol(typval_T *argvars, typval_T *rettv) | |
12238 { | |
12239 colnr_T vcol = 0; | |
12240 pos_T *fp; | |
12241 int fnum = curbuf->b_fnum; | |
12242 | |
12243 fp = var2fpos(&argvars[0], FALSE, &fnum); | |
12244 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count | |
12245 && fnum == curbuf->b_fnum) | |
12246 { | |
12247 getvvcol(curwin, fp, NULL, NULL, &vcol); | |
12248 ++vcol; | |
12249 } | |
12250 | |
12251 rettv->vval.v_number = vcol; | |
12252 } | |
12253 | |
12254 /* | |
12255 * "visualmode()" function | |
12256 */ | |
12257 static void | |
12258 f_visualmode(typval_T *argvars, typval_T *rettv) | |
12259 { | |
12260 char_u str[2]; | |
12261 | |
12262 rettv->v_type = VAR_STRING; | |
12263 str[0] = curbuf->b_visual_mode_eval; | |
12264 str[1] = NUL; | |
12265 rettv->vval.v_string = vim_strsave(str); | |
12266 | |
12267 /* A non-zero number or non-empty string argument: reset mode. */ | |
12268 if (non_zero_arg(&argvars[0])) | |
12269 curbuf->b_visual_mode_eval = NUL; | |
12270 } | |
12271 | |
12272 /* | |
12273 * "wildmenumode()" function | |
12274 */ | |
12275 static void | |
12276 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
12277 { | |
12278 #ifdef FEAT_WILDMENU | |
12279 if (wild_menu_showing) | |
12280 rettv->vval.v_number = 1; | |
12281 #endif | |
12282 } | |
12283 | |
12284 /* | |
12285 * "winbufnr(nr)" function | |
12286 */ | |
12287 static void | |
12288 f_winbufnr(typval_T *argvars, typval_T *rettv) | |
12289 { | |
12290 win_T *wp; | |
12291 | |
12292 wp = find_win_by_nr(&argvars[0], NULL); | |
12293 if (wp == NULL) | |
12294 rettv->vval.v_number = -1; | |
12295 else | |
12296 rettv->vval.v_number = wp->w_buffer->b_fnum; | |
12297 } | |
12298 | |
12299 /* | |
12300 * "wincol()" function | |
12301 */ | |
12302 static void | |
12303 f_wincol(typval_T *argvars UNUSED, typval_T *rettv) | |
12304 { | |
12305 validate_cursor(); | |
12306 rettv->vval.v_number = curwin->w_wcol + 1; | |
12307 } | |
12308 | |
12309 /* | |
12310 * "winheight(nr)" function | |
12311 */ | |
12312 static void | |
12313 f_winheight(typval_T *argvars, typval_T *rettv) | |
12314 { | |
12315 win_T *wp; | |
12316 | |
12317 wp = find_win_by_nr(&argvars[0], NULL); | |
12318 if (wp == NULL) | |
12319 rettv->vval.v_number = -1; | |
12320 else | |
12321 rettv->vval.v_number = wp->w_height; | |
12322 } | |
12323 | |
12324 /* | |
12325 * "winline()" function | |
12326 */ | |
12327 static void | |
12328 f_winline(typval_T *argvars UNUSED, typval_T *rettv) | |
12329 { | |
12330 validate_cursor(); | |
12331 rettv->vval.v_number = curwin->w_wrow + 1; | |
12332 } | |
12333 | |
12334 /* | |
12335 * "winnr()" function | |
12336 */ | |
12337 static void | |
12338 f_winnr(typval_T *argvars UNUSED, typval_T *rettv) | |
12339 { | |
12340 int nr = 1; | |
12341 | |
12342 #ifdef FEAT_WINDOWS | |
12343 nr = get_winnr(curtab, &argvars[0]); | |
12344 #endif | |
12345 rettv->vval.v_number = nr; | |
12346 } | |
12347 | |
12348 /* | |
12349 * "winrestcmd()" function | |
12350 */ | |
12351 static void | |
12352 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv) | |
12353 { | |
12354 #ifdef FEAT_WINDOWS | |
12355 win_T *wp; | |
12356 int winnr = 1; | |
12357 garray_T ga; | |
12358 char_u buf[50]; | |
12359 | |
12360 ga_init2(&ga, (int)sizeof(char), 70); | |
12361 for (wp = firstwin; wp != NULL; wp = wp->w_next) | |
12362 { | |
12363 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height); | |
12364 ga_concat(&ga, buf); | |
12365 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width); | |
12366 ga_concat(&ga, buf); | |
12367 ++winnr; | |
12368 } | |
12369 ga_append(&ga, NUL); | |
12370 | |
12371 rettv->vval.v_string = ga.ga_data; | |
12372 #else | |
12373 rettv->vval.v_string = NULL; | |
12374 #endif | |
12375 rettv->v_type = VAR_STRING; | |
12376 } | |
12377 | |
12378 /* | |
12379 * "winrestview()" function | |
12380 */ | |
12381 static void | |
12382 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED) | |
12383 { | |
12384 dict_T *dict; | |
12385 | |
12386 if (argvars[0].v_type != VAR_DICT | |
12387 || (dict = argvars[0].vval.v_dict) == NULL) | |
12388 EMSG(_(e_invarg)); | |
12389 else | |
12390 { | |
12391 if (dict_find(dict, (char_u *)"lnum", -1) != NULL) | |
12392 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum"); | |
12393 if (dict_find(dict, (char_u *)"col", -1) != NULL) | |
12394 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col"); | |
12395 #ifdef FEAT_VIRTUALEDIT | |
12396 if (dict_find(dict, (char_u *)"coladd", -1) != NULL) | |
12397 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd"); | |
12398 #endif | |
12399 if (dict_find(dict, (char_u *)"curswant", -1) != NULL) | |
12400 { | |
12401 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant"); | |
12402 curwin->w_set_curswant = FALSE; | |
12403 } | |
12404 | |
12405 if (dict_find(dict, (char_u *)"topline", -1) != NULL) | |
12406 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline")); | |
12407 #ifdef FEAT_DIFF | |
12408 if (dict_find(dict, (char_u *)"topfill", -1) != NULL) | |
12409 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill"); | |
12410 #endif | |
12411 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) | |
12412 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol"); | |
12413 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) | |
12414 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol"); | |
12415 | |
12416 check_cursor(); | |
12417 win_new_height(curwin, curwin->w_height); | |
12418 # ifdef FEAT_WINDOWS | |
12419 win_new_width(curwin, W_WIDTH(curwin)); | |
12420 # endif | |
12421 changed_window_setting(); | |
12422 | |
12423 if (curwin->w_topline <= 0) | |
12424 curwin->w_topline = 1; | |
12425 if (curwin->w_topline > curbuf->b_ml.ml_line_count) | |
12426 curwin->w_topline = curbuf->b_ml.ml_line_count; | |
12427 #ifdef FEAT_DIFF | |
12428 check_topfill(curwin, TRUE); | |
12429 #endif | |
12430 } | |
12431 } | |
12432 | |
12433 /* | |
12434 * "winsaveview()" function | |
12435 */ | |
12436 static void | |
12437 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv) | |
12438 { | |
12439 dict_T *dict; | |
12440 | |
12441 if (rettv_dict_alloc(rettv) == FAIL) | |
12442 return; | |
12443 dict = rettv->vval.v_dict; | |
12444 | |
12445 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL); | |
12446 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL); | |
12447 #ifdef FEAT_VIRTUALEDIT | |
12448 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL); | |
12449 #endif | |
12450 update_curswant(); | |
12451 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL); | |
12452 | |
12453 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL); | |
12454 #ifdef FEAT_DIFF | |
12455 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL); | |
12456 #endif | |
12457 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL); | |
12458 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL); | |
12459 } | |
12460 | |
12461 /* | |
12462 * "winwidth(nr)" function | |
12463 */ | |
12464 static void | |
12465 f_winwidth(typval_T *argvars, typval_T *rettv) | |
12466 { | |
12467 win_T *wp; | |
12468 | |
12469 wp = find_win_by_nr(&argvars[0], NULL); | |
12470 if (wp == NULL) | |
12471 rettv->vval.v_number = -1; | |
12472 else | |
12473 #ifdef FEAT_WINDOWS | |
12474 rettv->vval.v_number = wp->w_width; | |
12475 #else | |
12476 rettv->vval.v_number = Columns; | |
12477 #endif | |
12478 } | |
12479 | |
12480 /* | |
12481 * "wordcount()" function | |
12482 */ | |
12483 static void | |
12484 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv) | |
12485 { | |
12486 if (rettv_dict_alloc(rettv) == FAIL) | |
12487 return; | |
12488 cursor_pos_info(rettv->vval.v_dict); | |
12489 } | |
12490 | |
12491 /* | |
12492 * "writefile()" function | |
12493 */ | |
12494 static void | |
12495 f_writefile(typval_T *argvars, typval_T *rettv) | |
12496 { | |
12497 int binary = FALSE; | |
12498 int append = FALSE; | |
12499 char_u *fname; | |
12500 FILE *fd; | |
12501 int ret = 0; | |
12502 | |
12503 if (check_restricted() || check_secure()) | |
12504 return; | |
12505 | |
12506 if (argvars[0].v_type != VAR_LIST) | |
12507 { | |
12508 EMSG2(_(e_listarg), "writefile()"); | |
12509 return; | |
12510 } | |
12511 if (argvars[0].vval.v_list == NULL) | |
12512 return; | |
12513 | |
12514 if (argvars[2].v_type != VAR_UNKNOWN) | |
12515 { | |
12516 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL) | |
12517 binary = TRUE; | |
12518 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL) | |
12519 append = TRUE; | |
12520 } | |
12521 | |
12522 /* Always open the file in binary mode, library functions have a mind of | |
12523 * their own about CR-LF conversion. */ | |
12524 fname = get_tv_string(&argvars[1]); | |
12525 if (*fname == NUL || (fd = mch_fopen((char *)fname, | |
12526 append ? APPENDBIN : WRITEBIN)) == NULL) | |
12527 { | |
12528 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname); | |
12529 ret = -1; | |
12530 } | |
12531 else | |
12532 { | |
12533 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL) | |
12534 ret = -1; | |
12535 fclose(fd); | |
12536 } | |
12537 | |
12538 rettv->vval.v_number = ret; | |
12539 } | |
12540 | |
12541 /* | |
12542 * "xor(expr, expr)" function | |
12543 */ | |
12544 static void | |
12545 f_xor(typval_T *argvars, typval_T *rettv) | |
12546 { | |
12547 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | |
12548 ^ get_tv_number_chk(&argvars[1], NULL); | |
12549 } | |
12550 | |
12551 | |
12552 #endif /* FEAT_EVAL */ |