Mercurial > vim
comparison src/eval.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 | 86af4a48c00a |
children | 05a56bbe34a1 |
comparison
equal
deleted
inserted
replaced
9570:695186e11daa | 9571:5eaa708ab50d |
---|---|
14 | 14 |
15 #include "vim.h" | 15 #include "vim.h" |
16 | 16 |
17 #if defined(FEAT_EVAL) || defined(PROTO) | 17 #if defined(FEAT_EVAL) || defined(PROTO) |
18 | 18 |
19 #ifdef AMIGA | |
20 # include <time.h> /* for strftime() */ | |
21 #endif | |
22 | |
23 #ifdef VMS | 19 #ifdef VMS |
24 # include <float.h> | 20 # include <float.h> |
25 #endif | |
26 | |
27 #ifdef MACOS | |
28 # include <time.h> /* for time_t */ | |
29 #endif | 21 #endif |
30 | 22 |
31 #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ | 23 #define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ |
32 | 24 |
33 static char *e_letunexp = N_("E18: Unexpected characters in :let"); | 25 static char *e_letunexp = N_("E18: Unexpected characters in :let"); |
34 static char *e_undefvar = N_("E121: Undefined variable: %s"); | 26 static char *e_undefvar = N_("E121: Undefined variable: %s"); |
35 static char *e_missbrac = N_("E111: Missing ']'"); | 27 static char *e_missbrac = N_("E111: Missing ']'"); |
36 static char *e_listarg = N_("E686: Argument of %s must be a List"); | |
37 static char *e_listdictarg = N_("E712: Argument of %s must be a List or Dictionary"); | |
38 static char *e_listreq = N_("E714: List required"); | |
39 #ifdef FEAT_QUICKFIX | |
40 static char *e_stringreq = N_("E928: String required"); | |
41 #endif | |
42 static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); | 28 static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); |
43 static char *e_letwrong = N_("E734: Wrong variable type for %s="); | 29 static char *e_letwrong = N_("E734: Wrong variable type for %s="); |
44 static char *e_illvar = N_("E461: Illegal variable name: %s"); | 30 static char *e_illvar = N_("E461: Illegal variable name: %s"); |
45 #ifdef FEAT_FLOAT | 31 #ifdef FEAT_FLOAT |
46 static char *e_float_as_string = N_("E806: using Float as a String"); | 32 static char *e_float_as_string = N_("E806: using Float as a String"); |
99 * Array to hold the value of v: variables. | 85 * Array to hold the value of v: variables. |
100 * The value is in a dictitem, so that it can also be used in the v: scope. | 86 * The value is in a dictitem, so that it can also be used in the v: scope. |
101 * The reason to use this table anyway is for very quick access to the | 87 * The reason to use this table anyway is for very quick access to the |
102 * variables with the VV_ defines. | 88 * variables with the VV_ defines. |
103 */ | 89 */ |
104 #include "version.h" | |
105 | 90 |
106 /* values for vv_flags: */ | 91 /* values for vv_flags: */ |
107 #define VV_COMPAT 1 /* compatible, also used without "v:" */ | 92 #define VV_COMPAT 1 /* compatible, also used without "v:" */ |
108 #define VV_RO 2 /* read-only */ | 93 #define VV_RO 2 /* read-only */ |
109 #define VV_RO_SBX 4 /* read-only in the sandbox */ | 94 #define VV_RO_SBX 4 /* read-only in the sandbox */ |
204 #define vv_tv vv_di.di_tv | 189 #define vv_tv vv_di.di_tv |
205 | 190 |
206 static dictitem_T vimvars_var; /* variable used for v: */ | 191 static dictitem_T vimvars_var; /* variable used for v: */ |
207 #define vimvarht vimvardict.dv_hashtab | 192 #define vimvarht vimvardict.dv_hashtab |
208 | 193 |
209 static void prepare_vimvar(int idx, typval_T *save_tv); | |
210 static void restore_vimvar(int idx, typval_T *save_tv); | |
211 static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars); | 194 static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars); |
212 static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon); | 195 static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon); |
213 static char_u *skip_var_one(char_u *arg); | 196 static char_u *skip_var_one(char_u *arg); |
214 static void list_glob_vars(int *first); | 197 static void list_glob_vars(int *first); |
215 static void list_buf_vars(int *first); | 198 static void list_buf_vars(int *first); |
219 #endif | 202 #endif |
220 static void list_vim_vars(int *first); | 203 static void list_vim_vars(int *first); |
221 static void list_script_vars(int *first); | 204 static void list_script_vars(int *first); |
222 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); | 205 static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first); |
223 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op); | 206 static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op); |
224 static int check_changedtick(char_u *arg); | |
225 static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op); | 207 static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op); |
226 static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); | 208 static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); |
227 static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep); | 209 static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep); |
228 static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit); | 210 static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit); |
229 static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock); | 211 static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock); |
230 static void item_lock(typval_T *tv, int deep, int lock); | 212 static void item_lock(typval_T *tv, int deep, int lock); |
231 static int tv_islocked(typval_T *tv); | |
232 | 213 |
233 static int eval2(char_u **arg, typval_T *rettv, int evaluate); | 214 static int eval2(char_u **arg, typval_T *rettv, int evaluate); |
234 static int eval3(char_u **arg, typval_T *rettv, int evaluate); | 215 static int eval3(char_u **arg, typval_T *rettv, int evaluate); |
235 static int eval4(char_u **arg, typval_T *rettv, int evaluate); | 216 static int eval4(char_u **arg, typval_T *rettv, int evaluate); |
236 static int eval5(char_u **arg, typval_T *rettv, int evaluate); | 217 static int eval5(char_u **arg, typval_T *rettv, int evaluate); |
237 static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); | 218 static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); |
238 static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); | 219 static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); |
239 | 220 |
240 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); | 221 static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose); |
241 static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate); | |
242 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); | 222 static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate); |
243 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); | 223 static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate); |
244 static int free_unref_items(int copyID); | 224 static int free_unref_items(int copyID); |
245 static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); | 225 static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); |
246 static int non_zero_arg(typval_T *argvars); | 226 |
247 | 227 |
248 #ifdef FEAT_FLOAT | |
249 static void f_abs(typval_T *argvars, typval_T *rettv); | |
250 static void f_acos(typval_T *argvars, typval_T *rettv); | |
251 #endif | |
252 static void f_add(typval_T *argvars, typval_T *rettv); | |
253 static void f_and(typval_T *argvars, typval_T *rettv); | |
254 static void f_append(typval_T *argvars, typval_T *rettv); | |
255 static void f_argc(typval_T *argvars, typval_T *rettv); | |
256 static void f_argidx(typval_T *argvars, typval_T *rettv); | |
257 static void f_arglistid(typval_T *argvars, typval_T *rettv); | |
258 static void f_argv(typval_T *argvars, typval_T *rettv); | |
259 static void f_assert_equal(typval_T *argvars, typval_T *rettv); | |
260 static void f_assert_exception(typval_T *argvars, typval_T *rettv); | |
261 static void f_assert_fails(typval_T *argvars, typval_T *rettv); | |
262 static void f_assert_false(typval_T *argvars, typval_T *rettv); | |
263 static void f_assert_match(typval_T *argvars, typval_T *rettv); | |
264 static void f_assert_notequal(typval_T *argvars, typval_T *rettv); | |
265 static void f_assert_notmatch(typval_T *argvars, typval_T *rettv); | |
266 static void f_assert_true(typval_T *argvars, typval_T *rettv); | |
267 #ifdef FEAT_FLOAT | |
268 static void f_asin(typval_T *argvars, typval_T *rettv); | |
269 static void f_atan(typval_T *argvars, typval_T *rettv); | |
270 static void f_atan2(typval_T *argvars, typval_T *rettv); | |
271 #endif | |
272 static void f_browse(typval_T *argvars, typval_T *rettv); | |
273 static void f_browsedir(typval_T *argvars, typval_T *rettv); | |
274 static void f_bufexists(typval_T *argvars, typval_T *rettv); | |
275 static void f_buflisted(typval_T *argvars, typval_T *rettv); | |
276 static void f_bufloaded(typval_T *argvars, typval_T *rettv); | |
277 static void f_bufname(typval_T *argvars, typval_T *rettv); | |
278 static void f_bufnr(typval_T *argvars, typval_T *rettv); | |
279 static void f_bufwinid(typval_T *argvars, typval_T *rettv); | |
280 static void f_bufwinnr(typval_T *argvars, typval_T *rettv); | |
281 static void f_byte2line(typval_T *argvars, typval_T *rettv); | |
282 static void byteidx(typval_T *argvars, typval_T *rettv, int comp); | |
283 static void f_byteidx(typval_T *argvars, typval_T *rettv); | |
284 static void f_byteidxcomp(typval_T *argvars, typval_T *rettv); | |
285 static void f_call(typval_T *argvars, typval_T *rettv); | |
286 #ifdef FEAT_FLOAT | |
287 static void f_ceil(typval_T *argvars, typval_T *rettv); | |
288 #endif | |
289 #ifdef FEAT_JOB_CHANNEL | |
290 static void f_ch_close(typval_T *argvars, typval_T *rettv); | |
291 static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv); | |
292 static void f_ch_evalraw(typval_T *argvars, typval_T *rettv); | |
293 static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv); | |
294 static void f_ch_getjob(typval_T *argvars, typval_T *rettv); | |
295 static void f_ch_info(typval_T *argvars, typval_T *rettv); | |
296 static void f_ch_log(typval_T *argvars, typval_T *rettv); | |
297 static void f_ch_logfile(typval_T *argvars, typval_T *rettv); | |
298 static void f_ch_open(typval_T *argvars, typval_T *rettv); | |
299 static void f_ch_read(typval_T *argvars, typval_T *rettv); | |
300 static void f_ch_readraw(typval_T *argvars, typval_T *rettv); | |
301 static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv); | |
302 static void f_ch_sendraw(typval_T *argvars, typval_T *rettv); | |
303 static void f_ch_setoptions(typval_T *argvars, typval_T *rettv); | |
304 static void f_ch_status(typval_T *argvars, typval_T *rettv); | |
305 #endif | |
306 static void f_changenr(typval_T *argvars, typval_T *rettv); | |
307 static void f_char2nr(typval_T *argvars, typval_T *rettv); | |
308 static void f_cindent(typval_T *argvars, typval_T *rettv); | |
309 static void f_clearmatches(typval_T *argvars, typval_T *rettv); | |
310 static void f_col(typval_T *argvars, typval_T *rettv); | |
311 #if defined(FEAT_INS_EXPAND) | |
312 static void f_complete(typval_T *argvars, typval_T *rettv); | |
313 static void f_complete_add(typval_T *argvars, typval_T *rettv); | |
314 static void f_complete_check(typval_T *argvars, typval_T *rettv); | |
315 #endif | |
316 static void f_confirm(typval_T *argvars, typval_T *rettv); | |
317 static void f_copy(typval_T *argvars, typval_T *rettv); | |
318 #ifdef FEAT_FLOAT | |
319 static void f_cos(typval_T *argvars, typval_T *rettv); | |
320 static void f_cosh(typval_T *argvars, typval_T *rettv); | |
321 #endif | |
322 static void f_count(typval_T *argvars, typval_T *rettv); | |
323 static void f_cscope_connection(typval_T *argvars, typval_T *rettv); | |
324 static void f_cursor(typval_T *argsvars, typval_T *rettv); | |
325 static void f_deepcopy(typval_T *argvars, typval_T *rettv); | |
326 static void f_delete(typval_T *argvars, typval_T *rettv); | |
327 static void f_did_filetype(typval_T *argvars, typval_T *rettv); | |
328 static void f_diff_filler(typval_T *argvars, typval_T *rettv); | |
329 static void f_diff_hlID(typval_T *argvars, typval_T *rettv); | |
330 static void f_empty(typval_T *argvars, typval_T *rettv); | |
331 static void f_escape(typval_T *argvars, typval_T *rettv); | |
332 static void f_eval(typval_T *argvars, typval_T *rettv); | |
333 static void f_eventhandler(typval_T *argvars, typval_T *rettv); | |
334 static void f_executable(typval_T *argvars, typval_T *rettv); | |
335 static void f_execute(typval_T *argvars, typval_T *rettv); | |
336 static void f_exepath(typval_T *argvars, typval_T *rettv); | |
337 static void f_exists(typval_T *argvars, typval_T *rettv); | |
338 #ifdef FEAT_FLOAT | |
339 static void f_exp(typval_T *argvars, typval_T *rettv); | |
340 #endif | |
341 static void f_expand(typval_T *argvars, typval_T *rettv); | |
342 static void f_extend(typval_T *argvars, typval_T *rettv); | |
343 static void f_feedkeys(typval_T *argvars, typval_T *rettv); | |
344 static void f_filereadable(typval_T *argvars, typval_T *rettv); | |
345 static void f_filewritable(typval_T *argvars, typval_T *rettv); | |
346 static void f_filter(typval_T *argvars, typval_T *rettv); | |
347 static void f_finddir(typval_T *argvars, typval_T *rettv); | |
348 static void f_findfile(typval_T *argvars, typval_T *rettv); | |
349 #ifdef FEAT_FLOAT | |
350 static void f_float2nr(typval_T *argvars, typval_T *rettv); | |
351 static void f_floor(typval_T *argvars, typval_T *rettv); | |
352 static void f_fmod(typval_T *argvars, typval_T *rettv); | |
353 #endif | |
354 static void f_fnameescape(typval_T *argvars, typval_T *rettv); | |
355 static void f_fnamemodify(typval_T *argvars, typval_T *rettv); | |
356 static void f_foldclosed(typval_T *argvars, typval_T *rettv); | |
357 static void f_foldclosedend(typval_T *argvars, typval_T *rettv); | |
358 static void f_foldlevel(typval_T *argvars, typval_T *rettv); | |
359 static void f_foldtext(typval_T *argvars, typval_T *rettv); | |
360 static void f_foldtextresult(typval_T *argvars, typval_T *rettv); | |
361 static void f_foreground(typval_T *argvars, typval_T *rettv); | |
362 static void f_function(typval_T *argvars, typval_T *rettv); | |
363 static void f_garbagecollect(typval_T *argvars, typval_T *rettv); | |
364 static void f_get(typval_T *argvars, typval_T *rettv); | |
365 static void f_getbufline(typval_T *argvars, typval_T *rettv); | |
366 static void f_getbufvar(typval_T *argvars, typval_T *rettv); | |
367 static void f_getchar(typval_T *argvars, typval_T *rettv); | |
368 static void f_getcharmod(typval_T *argvars, typval_T *rettv); | |
369 static void f_getcharsearch(typval_T *argvars, typval_T *rettv); | |
370 static void f_getcmdline(typval_T *argvars, typval_T *rettv); | |
371 #if defined(FEAT_CMDL_COMPL) | |
372 static void f_getcompletion(typval_T *argvars, typval_T *rettv); | |
373 #endif | |
374 static void f_getcmdpos(typval_T *argvars, typval_T *rettv); | |
375 static void f_getcmdtype(typval_T *argvars, typval_T *rettv); | |
376 static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); | |
377 static void f_getcwd(typval_T *argvars, typval_T *rettv); | |
378 static void f_getfontname(typval_T *argvars, typval_T *rettv); | |
379 static void f_getfperm(typval_T *argvars, typval_T *rettv); | |
380 static void f_getfsize(typval_T *argvars, typval_T *rettv); | |
381 static void f_getftime(typval_T *argvars, typval_T *rettv); | |
382 static void f_getftype(typval_T *argvars, typval_T *rettv); | |
383 static void f_getline(typval_T *argvars, typval_T *rettv); | |
384 static void f_getmatches(typval_T *argvars, typval_T *rettv); | |
385 static void f_getpid(typval_T *argvars, typval_T *rettv); | |
386 static void f_getcurpos(typval_T *argvars, typval_T *rettv); | |
387 static void f_getpos(typval_T *argvars, typval_T *rettv); | |
388 static void f_getqflist(typval_T *argvars, typval_T *rettv); | |
389 static void f_getreg(typval_T *argvars, typval_T *rettv); | |
390 static void f_getregtype(typval_T *argvars, typval_T *rettv); | |
391 static void f_gettabvar(typval_T *argvars, typval_T *rettv); | |
392 static void f_gettabwinvar(typval_T *argvars, typval_T *rettv); | |
393 static void f_getwinposx(typval_T *argvars, typval_T *rettv); | |
394 static void f_getwinposy(typval_T *argvars, typval_T *rettv); | |
395 static void f_getwinvar(typval_T *argvars, typval_T *rettv); | |
396 static void f_glob(typval_T *argvars, typval_T *rettv); | |
397 static void f_globpath(typval_T *argvars, typval_T *rettv); | |
398 static void f_glob2regpat(typval_T *argvars, typval_T *rettv); | |
399 static void f_has(typval_T *argvars, typval_T *rettv); | |
400 static void f_has_key(typval_T *argvars, typval_T *rettv); | |
401 static void f_haslocaldir(typval_T *argvars, typval_T *rettv); | |
402 static void f_hasmapto(typval_T *argvars, typval_T *rettv); | |
403 static void f_histadd(typval_T *argvars, typval_T *rettv); | |
404 static void f_histdel(typval_T *argvars, typval_T *rettv); | |
405 static void f_histget(typval_T *argvars, typval_T *rettv); | |
406 static void f_histnr(typval_T *argvars, typval_T *rettv); | |
407 static void f_hlID(typval_T *argvars, typval_T *rettv); | |
408 static void f_hlexists(typval_T *argvars, typval_T *rettv); | |
409 static void f_hostname(typval_T *argvars, typval_T *rettv); | |
410 static void f_iconv(typval_T *argvars, typval_T *rettv); | |
411 static void f_indent(typval_T *argvars, typval_T *rettv); | |
412 static void f_index(typval_T *argvars, typval_T *rettv); | |
413 static void f_input(typval_T *argvars, typval_T *rettv); | |
414 static void f_inputdialog(typval_T *argvars, typval_T *rettv); | |
415 static void f_inputlist(typval_T *argvars, typval_T *rettv); | |
416 static void f_inputrestore(typval_T *argvars, typval_T *rettv); | |
417 static void f_inputsave(typval_T *argvars, typval_T *rettv); | |
418 static void f_inputsecret(typval_T *argvars, typval_T *rettv); | |
419 static void f_insert(typval_T *argvars, typval_T *rettv); | |
420 static void f_invert(typval_T *argvars, typval_T *rettv); | |
421 static void f_isdirectory(typval_T *argvars, typval_T *rettv); | |
422 static void f_islocked(typval_T *argvars, typval_T *rettv); | |
423 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | |
424 static void f_isnan(typval_T *argvars, typval_T *rettv); | |
425 #endif | |
426 static void f_items(typval_T *argvars, typval_T *rettv); | |
427 #ifdef FEAT_JOB_CHANNEL | |
428 static void f_job_getchannel(typval_T *argvars, typval_T *rettv); | |
429 static void f_job_info(typval_T *argvars, typval_T *rettv); | |
430 static void f_job_setoptions(typval_T *argvars, typval_T *rettv); | |
431 static void f_job_start(typval_T *argvars, typval_T *rettv); | |
432 static void f_job_stop(typval_T *argvars, typval_T *rettv); | |
433 static void f_job_status(typval_T *argvars, typval_T *rettv); | |
434 #endif | |
435 static void f_join(typval_T *argvars, typval_T *rettv); | |
436 static void f_js_decode(typval_T *argvars, typval_T *rettv); | |
437 static void f_js_encode(typval_T *argvars, typval_T *rettv); | |
438 static void f_json_decode(typval_T *argvars, typval_T *rettv); | |
439 static void f_json_encode(typval_T *argvars, typval_T *rettv); | |
440 static void f_keys(typval_T *argvars, typval_T *rettv); | |
441 static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv); | |
442 static void f_len(typval_T *argvars, typval_T *rettv); | |
443 static void f_libcall(typval_T *argvars, typval_T *rettv); | |
444 static void f_libcallnr(typval_T *argvars, typval_T *rettv); | |
445 static void f_line(typval_T *argvars, typval_T *rettv); | |
446 static void f_line2byte(typval_T *argvars, typval_T *rettv); | |
447 static void f_lispindent(typval_T *argvars, typval_T *rettv); | |
448 static void f_localtime(typval_T *argvars, typval_T *rettv); | |
449 #ifdef FEAT_FLOAT | |
450 static void f_log(typval_T *argvars, typval_T *rettv); | |
451 static void f_log10(typval_T *argvars, typval_T *rettv); | |
452 #endif | |
453 #ifdef FEAT_LUA | |
454 static void f_luaeval(typval_T *argvars, typval_T *rettv); | |
455 #endif | |
456 static void f_map(typval_T *argvars, typval_T *rettv); | |
457 static void f_maparg(typval_T *argvars, typval_T *rettv); | |
458 static void f_mapcheck(typval_T *argvars, typval_T *rettv); | |
459 static void f_match(typval_T *argvars, typval_T *rettv); | |
460 static void f_matchadd(typval_T *argvars, typval_T *rettv); | |
461 static void f_matchaddpos(typval_T *argvars, typval_T *rettv); | |
462 static void f_matcharg(typval_T *argvars, typval_T *rettv); | |
463 static void f_matchdelete(typval_T *argvars, typval_T *rettv); | |
464 static void f_matchend(typval_T *argvars, typval_T *rettv); | |
465 static void f_matchlist(typval_T *argvars, typval_T *rettv); | |
466 static void f_matchstr(typval_T *argvars, typval_T *rettv); | |
467 static void f_matchstrpos(typval_T *argvars, typval_T *rettv); | |
468 static void f_max(typval_T *argvars, typval_T *rettv); | |
469 static void f_min(typval_T *argvars, typval_T *rettv); | |
470 #ifdef vim_mkdir | |
471 static void f_mkdir(typval_T *argvars, typval_T *rettv); | |
472 #endif | |
473 static void f_mode(typval_T *argvars, typval_T *rettv); | |
474 #ifdef FEAT_MZSCHEME | |
475 static void f_mzeval(typval_T *argvars, typval_T *rettv); | |
476 #endif | |
477 static void f_nextnonblank(typval_T *argvars, typval_T *rettv); | |
478 static void f_nr2char(typval_T *argvars, typval_T *rettv); | |
479 static void f_or(typval_T *argvars, typval_T *rettv); | |
480 static void f_pathshorten(typval_T *argvars, typval_T *rettv); | |
481 #ifdef FEAT_PERL | |
482 static void f_perleval(typval_T *argvars, typval_T *rettv); | |
483 #endif | |
484 #ifdef FEAT_FLOAT | |
485 static void f_pow(typval_T *argvars, typval_T *rettv); | |
486 #endif | |
487 static void f_prevnonblank(typval_T *argvars, typval_T *rettv); | |
488 static void f_printf(typval_T *argvars, typval_T *rettv); | |
489 static void f_pumvisible(typval_T *argvars, typval_T *rettv); | |
490 #ifdef FEAT_PYTHON3 | |
491 static void f_py3eval(typval_T *argvars, typval_T *rettv); | |
492 #endif | |
493 #ifdef FEAT_PYTHON | |
494 static void f_pyeval(typval_T *argvars, typval_T *rettv); | |
495 #endif | |
496 static void f_range(typval_T *argvars, typval_T *rettv); | |
497 static void f_readfile(typval_T *argvars, typval_T *rettv); | |
498 static void f_reltime(typval_T *argvars, typval_T *rettv); | |
499 #ifdef FEAT_FLOAT | |
500 static void f_reltimefloat(typval_T *argvars, typval_T *rettv); | |
501 #endif | |
502 static void f_reltimestr(typval_T *argvars, typval_T *rettv); | |
503 static void f_remote_expr(typval_T *argvars, typval_T *rettv); | |
504 static void f_remote_foreground(typval_T *argvars, typval_T *rettv); | |
505 static void f_remote_peek(typval_T *argvars, typval_T *rettv); | |
506 static void f_remote_read(typval_T *argvars, typval_T *rettv); | |
507 static void f_remote_send(typval_T *argvars, typval_T *rettv); | |
508 static void f_remove(typval_T *argvars, typval_T *rettv); | |
509 static void f_rename(typval_T *argvars, typval_T *rettv); | |
510 static void f_repeat(typval_T *argvars, typval_T *rettv); | |
511 static void f_resolve(typval_T *argvars, typval_T *rettv); | |
512 static void f_reverse(typval_T *argvars, typval_T *rettv); | |
513 #ifdef FEAT_FLOAT | |
514 static void f_round(typval_T *argvars, typval_T *rettv); | |
515 #endif | |
516 static void f_screenattr(typval_T *argvars, typval_T *rettv); | |
517 static void f_screenchar(typval_T *argvars, typval_T *rettv); | |
518 static void f_screencol(typval_T *argvars, typval_T *rettv); | |
519 static void f_screenrow(typval_T *argvars, typval_T *rettv); | |
520 static void f_search(typval_T *argvars, typval_T *rettv); | |
521 static void f_searchdecl(typval_T *argvars, typval_T *rettv); | |
522 static void f_searchpair(typval_T *argvars, typval_T *rettv); | |
523 static void f_searchpairpos(typval_T *argvars, typval_T *rettv); | |
524 static void f_searchpos(typval_T *argvars, typval_T *rettv); | |
525 static void f_server2client(typval_T *argvars, typval_T *rettv); | |
526 static void f_serverlist(typval_T *argvars, typval_T *rettv); | |
527 static void f_setbufvar(typval_T *argvars, typval_T *rettv); | |
528 static void f_setcharsearch(typval_T *argvars, typval_T *rettv); | |
529 static void f_setcmdpos(typval_T *argvars, typval_T *rettv); | |
530 static void f_setfperm(typval_T *argvars, typval_T *rettv); | |
531 static void f_setline(typval_T *argvars, typval_T *rettv); | |
532 static void f_setloclist(typval_T *argvars, typval_T *rettv); | |
533 static void f_setmatches(typval_T *argvars, typval_T *rettv); | |
534 static void f_setpos(typval_T *argvars, typval_T *rettv); | |
535 static void f_setqflist(typval_T *argvars, typval_T *rettv); | |
536 static void f_setreg(typval_T *argvars, typval_T *rettv); | |
537 static void f_settabvar(typval_T *argvars, typval_T *rettv); | |
538 static void f_settabwinvar(typval_T *argvars, typval_T *rettv); | |
539 static void f_setwinvar(typval_T *argvars, typval_T *rettv); | |
540 #ifdef FEAT_CRYPT | |
541 static void f_sha256(typval_T *argvars, typval_T *rettv); | |
542 #endif /* FEAT_CRYPT */ | |
543 static void f_shellescape(typval_T *argvars, typval_T *rettv); | |
544 static void f_shiftwidth(typval_T *argvars, typval_T *rettv); | |
545 static void f_simplify(typval_T *argvars, typval_T *rettv); | |
546 #ifdef FEAT_FLOAT | |
547 static void f_sin(typval_T *argvars, typval_T *rettv); | |
548 static void f_sinh(typval_T *argvars, typval_T *rettv); | |
549 #endif | |
550 static void f_sort(typval_T *argvars, typval_T *rettv); | |
551 static void f_soundfold(typval_T *argvars, typval_T *rettv); | |
552 static void f_spellbadword(typval_T *argvars, typval_T *rettv); | |
553 static void f_spellsuggest(typval_T *argvars, typval_T *rettv); | |
554 static void f_split(typval_T *argvars, typval_T *rettv); | |
555 #ifdef FEAT_FLOAT | |
556 static void f_sqrt(typval_T *argvars, typval_T *rettv); | |
557 static void f_str2float(typval_T *argvars, typval_T *rettv); | |
558 #endif | |
559 static void f_str2nr(typval_T *argvars, typval_T *rettv); | |
560 static void f_strchars(typval_T *argvars, typval_T *rettv); | |
561 #ifdef HAVE_STRFTIME | |
562 static void f_strftime(typval_T *argvars, typval_T *rettv); | |
563 #endif | |
564 static void f_strgetchar(typval_T *argvars, typval_T *rettv); | |
565 static void f_stridx(typval_T *argvars, typval_T *rettv); | |
566 static void f_string(typval_T *argvars, typval_T *rettv); | |
567 static void f_strlen(typval_T *argvars, typval_T *rettv); | |
568 static void f_strcharpart(typval_T *argvars, typval_T *rettv); | |
569 static void f_strpart(typval_T *argvars, typval_T *rettv); | |
570 static void f_strridx(typval_T *argvars, typval_T *rettv); | |
571 static void f_strtrans(typval_T *argvars, typval_T *rettv); | |
572 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); | |
573 static void f_strwidth(typval_T *argvars, typval_T *rettv); | |
574 static void f_submatch(typval_T *argvars, typval_T *rettv); | |
575 static void f_substitute(typval_T *argvars, typval_T *rettv); | |
576 static void f_synID(typval_T *argvars, typval_T *rettv); | |
577 static void f_synIDattr(typval_T *argvars, typval_T *rettv); | |
578 static void f_synIDtrans(typval_T *argvars, typval_T *rettv); | |
579 static void f_synstack(typval_T *argvars, typval_T *rettv); | |
580 static void f_synconcealed(typval_T *argvars, typval_T *rettv); | |
581 static void f_system(typval_T *argvars, typval_T *rettv); | |
582 static void f_systemlist(typval_T *argvars, typval_T *rettv); | |
583 static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv); | |
584 static void f_tabpagenr(typval_T *argvars, typval_T *rettv); | |
585 static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv); | |
586 static void f_taglist(typval_T *argvars, typval_T *rettv); | |
587 static void f_tagfiles(typval_T *argvars, typval_T *rettv); | |
588 static void f_tempname(typval_T *argvars, typval_T *rettv); | |
589 static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); | |
590 static void f_test_autochdir(typval_T *argvars, typval_T *rettv); | |
591 static void f_test_disable_char_avail(typval_T *argvars, typval_T *rettv); | |
592 static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv); | |
593 #ifdef FEAT_JOB_CHANNEL | |
594 static void f_test_null_channel(typval_T *argvars, typval_T *rettv); | |
595 #endif | |
596 static void f_test_null_dict(typval_T *argvars, typval_T *rettv); | |
597 #ifdef FEAT_JOB_CHANNEL | |
598 static void f_test_null_job(typval_T *argvars, typval_T *rettv); | |
599 #endif | |
600 static void f_test_null_list(typval_T *argvars, typval_T *rettv); | |
601 static void f_test_null_partial(typval_T *argvars, typval_T *rettv); | |
602 static void f_test_null_string(typval_T *argvars, typval_T *rettv); | |
603 static void f_test_settime(typval_T *argvars, typval_T *rettv); | |
604 #ifdef FEAT_FLOAT | |
605 static void f_tan(typval_T *argvars, typval_T *rettv); | |
606 static void f_tanh(typval_T *argvars, typval_T *rettv); | |
607 #endif | |
608 #ifdef FEAT_TIMERS | |
609 static void f_timer_start(typval_T *argvars, typval_T *rettv); | |
610 static void f_timer_stop(typval_T *argvars, typval_T *rettv); | |
611 #endif | |
612 static void f_tolower(typval_T *argvars, typval_T *rettv); | |
613 static void f_toupper(typval_T *argvars, typval_T *rettv); | |
614 static void f_tr(typval_T *argvars, typval_T *rettv); | |
615 #ifdef FEAT_FLOAT | |
616 static void f_trunc(typval_T *argvars, typval_T *rettv); | |
617 #endif | |
618 static void f_type(typval_T *argvars, typval_T *rettv); | |
619 static void f_undofile(typval_T *argvars, typval_T *rettv); | |
620 static void f_undotree(typval_T *argvars, typval_T *rettv); | |
621 static void f_uniq(typval_T *argvars, typval_T *rettv); | |
622 static void f_values(typval_T *argvars, typval_T *rettv); | |
623 static void f_virtcol(typval_T *argvars, typval_T *rettv); | |
624 static void f_visualmode(typval_T *argvars, typval_T *rettv); | |
625 static void f_wildmenumode(typval_T *argvars, typval_T *rettv); | |
626 static void f_win_findbuf(typval_T *argvars, typval_T *rettv); | |
627 static void f_win_getid(typval_T *argvars, typval_T *rettv); | |
628 static void f_win_gotoid(typval_T *argvars, typval_T *rettv); | |
629 static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); | |
630 static void f_win_id2win(typval_T *argvars, typval_T *rettv); | |
631 static void f_winbufnr(typval_T *argvars, typval_T *rettv); | |
632 static void f_wincol(typval_T *argvars, typval_T *rettv); | |
633 static void f_winheight(typval_T *argvars, typval_T *rettv); | |
634 static void f_winline(typval_T *argvars, typval_T *rettv); | |
635 static void f_winnr(typval_T *argvars, typval_T *rettv); | |
636 static void f_winrestcmd(typval_T *argvars, typval_T *rettv); | |
637 static void f_winrestview(typval_T *argvars, typval_T *rettv); | |
638 static void f_winsaveview(typval_T *argvars, typval_T *rettv); | |
639 static void f_winwidth(typval_T *argvars, typval_T *rettv); | |
640 static void f_writefile(typval_T *argvars, typval_T *rettv); | |
641 static void f_wordcount(typval_T *argvars, typval_T *rettv); | |
642 static void f_xor(typval_T *argvars, typval_T *rettv); | |
643 | |
644 static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp); | |
645 static pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum); | |
646 static int get_env_len(char_u **arg); | 228 static int get_env_len(char_u **arg); |
647 static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose); | |
648 static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); | 229 static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end); |
649 static int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload); | |
650 static typval_T *alloc_string_tv(char_u *string); | 230 static typval_T *alloc_string_tv(char_u *string); |
651 static void init_tv(typval_T *varp); | |
652 #ifdef FEAT_FLOAT | |
653 static float_T get_tv_float(typval_T *varp); | |
654 #endif | |
655 static linenr_T get_tv_lnum(typval_T *argvars); | |
656 static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf); | |
657 static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload); | |
658 static hashtab_T *find_var_ht(char_u *name, char_u **varname); | 231 static hashtab_T *find_var_ht(char_u *name, char_u **varname); |
659 static void delete_var(hashtab_T *ht, hashitem_T *hi); | 232 static void delete_var(hashtab_T *ht, hashitem_T *hi); |
660 static void list_one_var(dictitem_T *v, char_u *prefix, int *first); | 233 static void list_one_var(dictitem_T *v, char_u *prefix, int *first); |
661 static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first); | 234 static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first); |
662 static void set_var(char_u *name, typval_T *varp, int copy); | |
663 static int var_check_fixed(int flags, char_u *name, int use_gettext); | |
664 static char_u *find_option_end(char_u **arg, int *opt_flags); | 235 static char_u *find_option_end(char_u **arg, int *opt_flags); |
665 static win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp); | |
666 static win_T *find_tabwin(typval_T *wvp, typval_T *tvp); | |
667 static void getwinvar(typval_T *argvars, typval_T *rettv, int off); | |
668 static int searchpair_cmn(typval_T *argvars, pos_T *match_pos); | |
669 static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp); | |
670 static void setwinvar(typval_T *argvars, typval_T *rettv, int off); | |
671 static int write_list(FILE *fd, list_T *list, int binary); | |
672 static void get_cmd_output_as_rettv(typval_T *argvars, typval_T *rettv, int retlist); | |
673 | |
674 | 236 |
675 #ifdef EBCDIC | 237 #ifdef EBCDIC |
676 static int compare_func_name(const void *s1, const void *s2); | 238 static int compare_func_name(const void *s1, const void *s2); |
677 static void sortFunctions(); | 239 static void sortFunctions(); |
678 #endif | 240 #endif |
241 | |
242 /* for VIM_VERSION_ defines */ | |
243 #include "version.h" | |
679 | 244 |
680 /* | 245 /* |
681 * Initialize the global and v: variables. | 246 * Initialize the global and v: variables. |
682 */ | 247 */ |
683 void | 248 void |
2198 } | 1763 } |
2199 | 1764 |
2200 /* | 1765 /* |
2201 * If "arg" is equal to "b:changedtick" give an error and return TRUE. | 1766 * If "arg" is equal to "b:changedtick" give an error and return TRUE. |
2202 */ | 1767 */ |
2203 static int | 1768 int |
2204 check_changedtick(char_u *arg) | 1769 check_changedtick(char_u *arg) |
2205 { | 1770 { |
2206 if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13])) | 1771 if (STRNCMP(arg, "b:changedtick", 13) == 0 && !eval_isnamec(arg[13])) |
2207 { | 1772 { |
2208 EMSG2(_(e_readonlyvar), arg); | 1773 EMSG2(_(e_readonlyvar), arg); |
3411 } | 2976 } |
3412 } | 2977 } |
3413 --recurse; | 2978 --recurse; |
3414 } | 2979 } |
3415 | 2980 |
3416 /* | |
3417 * Return TRUE if typeval "tv" is locked: Either that value is locked itself | |
3418 * or it refers to a List or Dictionary that is locked. | |
3419 */ | |
3420 static int | |
3421 tv_islocked(typval_T *tv) | |
3422 { | |
3423 return (tv->v_lock & VAR_LOCKED) | |
3424 || (tv->v_type == VAR_LIST | |
3425 && tv->vval.v_list != NULL | |
3426 && (tv->vval.v_list->lv_lock & VAR_LOCKED)) | |
3427 || (tv->v_type == VAR_DICT | |
3428 && tv->vval.v_dict != NULL | |
3429 && (tv->vval.v_dict->dv_lock & VAR_LOCKED)); | |
3430 } | |
3431 | |
3432 #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO) | 2981 #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO) |
3433 /* | 2982 /* |
3434 * Delete all "menutrans_" variables. | 2983 * Delete all "menutrans_" variables. |
3435 */ | 2984 */ |
3436 void | 2985 void |
5157 * Get an option value. | 4706 * Get an option value. |
5158 * "arg" points to the '&' or '+' before the option name. | 4707 * "arg" points to the '&' or '+' before the option name. |
5159 * "arg" is advanced to character after the option name. | 4708 * "arg" is advanced to character after the option name. |
5160 * Return OK or FAIL. | 4709 * Return OK or FAIL. |
5161 */ | 4710 */ |
5162 static int | 4711 int |
5163 get_option_tv( | 4712 get_option_tv( |
5164 char_u **arg, | 4713 char_u **arg, |
5165 typval_T *rettv, /* when NULL, only check if option exists */ | 4714 typval_T *rettv, /* when NULL, only check if option exists */ |
5166 int evaluate) | 4715 int evaluate) |
5167 { | 4716 { |
6419 } | 5968 } |
6420 | 5969 |
6421 return OK; | 5970 return OK; |
6422 } | 5971 } |
6423 | 5972 |
6424 /* | |
6425 * Array with names and number of arguments of all internal functions | |
6426 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! | |
6427 */ | |
6428 static struct fst | |
6429 { | |
6430 char *f_name; /* function name */ | |
6431 char f_min_argc; /* minimal number of arguments */ | |
6432 char f_max_argc; /* maximal number of arguments */ | |
6433 void (*f_func)(typval_T *args, typval_T *rvar); | |
6434 /* implementation of function */ | |
6435 } functions[] = | |
6436 { | |
6437 #ifdef FEAT_FLOAT | |
6438 {"abs", 1, 1, f_abs}, | |
6439 {"acos", 1, 1, f_acos}, /* WJMc */ | |
6440 #endif | |
6441 {"add", 2, 2, f_add}, | |
6442 {"and", 2, 2, f_and}, | |
6443 {"append", 2, 2, f_append}, | |
6444 {"argc", 0, 0, f_argc}, | |
6445 {"argidx", 0, 0, f_argidx}, | |
6446 {"arglistid", 0, 2, f_arglistid}, | |
6447 {"argv", 0, 1, f_argv}, | |
6448 #ifdef FEAT_FLOAT | |
6449 {"asin", 1, 1, f_asin}, /* WJMc */ | |
6450 #endif | |
6451 {"assert_equal", 2, 3, f_assert_equal}, | |
6452 {"assert_exception", 1, 2, f_assert_exception}, | |
6453 {"assert_fails", 1, 2, f_assert_fails}, | |
6454 {"assert_false", 1, 2, f_assert_false}, | |
6455 {"assert_match", 2, 3, f_assert_match}, | |
6456 {"assert_notequal", 2, 3, f_assert_notequal}, | |
6457 {"assert_notmatch", 2, 3, f_assert_notmatch}, | |
6458 {"assert_true", 1, 2, f_assert_true}, | |
6459 #ifdef FEAT_FLOAT | |
6460 {"atan", 1, 1, f_atan}, | |
6461 {"atan2", 2, 2, f_atan2}, | |
6462 #endif | |
6463 {"browse", 4, 4, f_browse}, | |
6464 {"browsedir", 2, 2, f_browsedir}, | |
6465 {"bufexists", 1, 1, f_bufexists}, | |
6466 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */ | |
6467 {"buffer_name", 1, 1, f_bufname}, /* obsolete */ | |
6468 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */ | |
6469 {"buflisted", 1, 1, f_buflisted}, | |
6470 {"bufloaded", 1, 1, f_bufloaded}, | |
6471 {"bufname", 1, 1, f_bufname}, | |
6472 {"bufnr", 1, 2, f_bufnr}, | |
6473 {"bufwinid", 1, 1, f_bufwinid}, | |
6474 {"bufwinnr", 1, 1, f_bufwinnr}, | |
6475 {"byte2line", 1, 1, f_byte2line}, | |
6476 {"byteidx", 2, 2, f_byteidx}, | |
6477 {"byteidxcomp", 2, 2, f_byteidxcomp}, | |
6478 {"call", 2, 3, f_call}, | |
6479 #ifdef FEAT_FLOAT | |
6480 {"ceil", 1, 1, f_ceil}, | |
6481 #endif | |
6482 #ifdef FEAT_JOB_CHANNEL | |
6483 {"ch_close", 1, 1, f_ch_close}, | |
6484 {"ch_evalexpr", 2, 3, f_ch_evalexpr}, | |
6485 {"ch_evalraw", 2, 3, f_ch_evalraw}, | |
6486 {"ch_getbufnr", 2, 2, f_ch_getbufnr}, | |
6487 {"ch_getjob", 1, 1, f_ch_getjob}, | |
6488 {"ch_info", 1, 1, f_ch_info}, | |
6489 {"ch_log", 1, 2, f_ch_log}, | |
6490 {"ch_logfile", 1, 2, f_ch_logfile}, | |
6491 {"ch_open", 1, 2, f_ch_open}, | |
6492 {"ch_read", 1, 2, f_ch_read}, | |
6493 {"ch_readraw", 1, 2, f_ch_readraw}, | |
6494 {"ch_sendexpr", 2, 3, f_ch_sendexpr}, | |
6495 {"ch_sendraw", 2, 3, f_ch_sendraw}, | |
6496 {"ch_setoptions", 2, 2, f_ch_setoptions}, | |
6497 {"ch_status", 1, 1, f_ch_status}, | |
6498 #endif | |
6499 {"changenr", 0, 0, f_changenr}, | |
6500 {"char2nr", 1, 2, f_char2nr}, | |
6501 {"cindent", 1, 1, f_cindent}, | |
6502 {"clearmatches", 0, 0, f_clearmatches}, | |
6503 {"col", 1, 1, f_col}, | |
6504 #if defined(FEAT_INS_EXPAND) | |
6505 {"complete", 2, 2, f_complete}, | |
6506 {"complete_add", 1, 1, f_complete_add}, | |
6507 {"complete_check", 0, 0, f_complete_check}, | |
6508 #endif | |
6509 {"confirm", 1, 4, f_confirm}, | |
6510 {"copy", 1, 1, f_copy}, | |
6511 #ifdef FEAT_FLOAT | |
6512 {"cos", 1, 1, f_cos}, | |
6513 {"cosh", 1, 1, f_cosh}, | |
6514 #endif | |
6515 {"count", 2, 4, f_count}, | |
6516 {"cscope_connection",0,3, f_cscope_connection}, | |
6517 {"cursor", 1, 3, f_cursor}, | |
6518 {"deepcopy", 1, 2, f_deepcopy}, | |
6519 {"delete", 1, 2, f_delete}, | |
6520 {"did_filetype", 0, 0, f_did_filetype}, | |
6521 {"diff_filler", 1, 1, f_diff_filler}, | |
6522 {"diff_hlID", 2, 2, f_diff_hlID}, | |
6523 {"empty", 1, 1, f_empty}, | |
6524 {"escape", 2, 2, f_escape}, | |
6525 {"eval", 1, 1, f_eval}, | |
6526 {"eventhandler", 0, 0, f_eventhandler}, | |
6527 {"executable", 1, 1, f_executable}, | |
6528 {"execute", 1, 2, f_execute}, | |
6529 {"exepath", 1, 1, f_exepath}, | |
6530 {"exists", 1, 1, f_exists}, | |
6531 #ifdef FEAT_FLOAT | |
6532 {"exp", 1, 1, f_exp}, | |
6533 #endif | |
6534 {"expand", 1, 3, f_expand}, | |
6535 {"extend", 2, 3, f_extend}, | |
6536 {"feedkeys", 1, 2, f_feedkeys}, | |
6537 {"file_readable", 1, 1, f_filereadable}, /* obsolete */ | |
6538 {"filereadable", 1, 1, f_filereadable}, | |
6539 {"filewritable", 1, 1, f_filewritable}, | |
6540 {"filter", 2, 2, f_filter}, | |
6541 {"finddir", 1, 3, f_finddir}, | |
6542 {"findfile", 1, 3, f_findfile}, | |
6543 #ifdef FEAT_FLOAT | |
6544 {"float2nr", 1, 1, f_float2nr}, | |
6545 {"floor", 1, 1, f_floor}, | |
6546 {"fmod", 2, 2, f_fmod}, | |
6547 #endif | |
6548 {"fnameescape", 1, 1, f_fnameescape}, | |
6549 {"fnamemodify", 2, 2, f_fnamemodify}, | |
6550 {"foldclosed", 1, 1, f_foldclosed}, | |
6551 {"foldclosedend", 1, 1, f_foldclosedend}, | |
6552 {"foldlevel", 1, 1, f_foldlevel}, | |
6553 {"foldtext", 0, 0, f_foldtext}, | |
6554 {"foldtextresult", 1, 1, f_foldtextresult}, | |
6555 {"foreground", 0, 0, f_foreground}, | |
6556 {"function", 1, 3, f_function}, | |
6557 {"garbagecollect", 0, 1, f_garbagecollect}, | |
6558 {"get", 2, 3, f_get}, | |
6559 {"getbufline", 2, 3, f_getbufline}, | |
6560 {"getbufvar", 2, 3, f_getbufvar}, | |
6561 {"getchar", 0, 1, f_getchar}, | |
6562 {"getcharmod", 0, 0, f_getcharmod}, | |
6563 {"getcharsearch", 0, 0, f_getcharsearch}, | |
6564 {"getcmdline", 0, 0, f_getcmdline}, | |
6565 {"getcmdpos", 0, 0, f_getcmdpos}, | |
6566 {"getcmdtype", 0, 0, f_getcmdtype}, | |
6567 {"getcmdwintype", 0, 0, f_getcmdwintype}, | |
6568 #if defined(FEAT_CMDL_COMPL) | |
6569 {"getcompletion", 2, 2, f_getcompletion}, | |
6570 #endif | |
6571 {"getcurpos", 0, 0, f_getcurpos}, | |
6572 {"getcwd", 0, 2, f_getcwd}, | |
6573 {"getfontname", 0, 1, f_getfontname}, | |
6574 {"getfperm", 1, 1, f_getfperm}, | |
6575 {"getfsize", 1, 1, f_getfsize}, | |
6576 {"getftime", 1, 1, f_getftime}, | |
6577 {"getftype", 1, 1, f_getftype}, | |
6578 {"getline", 1, 2, f_getline}, | |
6579 {"getloclist", 1, 1, f_getqflist}, | |
6580 {"getmatches", 0, 0, f_getmatches}, | |
6581 {"getpid", 0, 0, f_getpid}, | |
6582 {"getpos", 1, 1, f_getpos}, | |
6583 {"getqflist", 0, 0, f_getqflist}, | |
6584 {"getreg", 0, 3, f_getreg}, | |
6585 {"getregtype", 0, 1, f_getregtype}, | |
6586 {"gettabvar", 2, 3, f_gettabvar}, | |
6587 {"gettabwinvar", 3, 4, f_gettabwinvar}, | |
6588 {"getwinposx", 0, 0, f_getwinposx}, | |
6589 {"getwinposy", 0, 0, f_getwinposy}, | |
6590 {"getwinvar", 2, 3, f_getwinvar}, | |
6591 {"glob", 1, 4, f_glob}, | |
6592 {"glob2regpat", 1, 1, f_glob2regpat}, | |
6593 {"globpath", 2, 5, f_globpath}, | |
6594 {"has", 1, 1, f_has}, | |
6595 {"has_key", 2, 2, f_has_key}, | |
6596 {"haslocaldir", 0, 2, f_haslocaldir}, | |
6597 {"hasmapto", 1, 3, f_hasmapto}, | |
6598 {"highlightID", 1, 1, f_hlID}, /* obsolete */ | |
6599 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */ | |
6600 {"histadd", 2, 2, f_histadd}, | |
6601 {"histdel", 1, 2, f_histdel}, | |
6602 {"histget", 1, 2, f_histget}, | |
6603 {"histnr", 1, 1, f_histnr}, | |
6604 {"hlID", 1, 1, f_hlID}, | |
6605 {"hlexists", 1, 1, f_hlexists}, | |
6606 {"hostname", 0, 0, f_hostname}, | |
6607 {"iconv", 3, 3, f_iconv}, | |
6608 {"indent", 1, 1, f_indent}, | |
6609 {"index", 2, 4, f_index}, | |
6610 {"input", 1, 3, f_input}, | |
6611 {"inputdialog", 1, 3, f_inputdialog}, | |
6612 {"inputlist", 1, 1, f_inputlist}, | |
6613 {"inputrestore", 0, 0, f_inputrestore}, | |
6614 {"inputsave", 0, 0, f_inputsave}, | |
6615 {"inputsecret", 1, 2, f_inputsecret}, | |
6616 {"insert", 2, 3, f_insert}, | |
6617 {"invert", 1, 1, f_invert}, | |
6618 {"isdirectory", 1, 1, f_isdirectory}, | |
6619 {"islocked", 1, 1, f_islocked}, | |
6620 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | |
6621 {"isnan", 1, 1, f_isnan}, | |
6622 #endif | |
6623 {"items", 1, 1, f_items}, | |
6624 #ifdef FEAT_JOB_CHANNEL | |
6625 {"job_getchannel", 1, 1, f_job_getchannel}, | |
6626 {"job_info", 1, 1, f_job_info}, | |
6627 {"job_setoptions", 2, 2, f_job_setoptions}, | |
6628 {"job_start", 1, 2, f_job_start}, | |
6629 {"job_status", 1, 1, f_job_status}, | |
6630 {"job_stop", 1, 2, f_job_stop}, | |
6631 #endif | |
6632 {"join", 1, 2, f_join}, | |
6633 {"js_decode", 1, 1, f_js_decode}, | |
6634 {"js_encode", 1, 1, f_js_encode}, | |
6635 {"json_decode", 1, 1, f_json_decode}, | |
6636 {"json_encode", 1, 1, f_json_encode}, | |
6637 {"keys", 1, 1, f_keys}, | |
6638 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */ | |
6639 {"len", 1, 1, f_len}, | |
6640 {"libcall", 3, 3, f_libcall}, | |
6641 {"libcallnr", 3, 3, f_libcallnr}, | |
6642 {"line", 1, 1, f_line}, | |
6643 {"line2byte", 1, 1, f_line2byte}, | |
6644 {"lispindent", 1, 1, f_lispindent}, | |
6645 {"localtime", 0, 0, f_localtime}, | |
6646 #ifdef FEAT_FLOAT | |
6647 {"log", 1, 1, f_log}, | |
6648 {"log10", 1, 1, f_log10}, | |
6649 #endif | |
6650 #ifdef FEAT_LUA | |
6651 {"luaeval", 1, 2, f_luaeval}, | |
6652 #endif | |
6653 {"map", 2, 2, f_map}, | |
6654 {"maparg", 1, 4, f_maparg}, | |
6655 {"mapcheck", 1, 3, f_mapcheck}, | |
6656 {"match", 2, 4, f_match}, | |
6657 {"matchadd", 2, 5, f_matchadd}, | |
6658 {"matchaddpos", 2, 5, f_matchaddpos}, | |
6659 {"matcharg", 1, 1, f_matcharg}, | |
6660 {"matchdelete", 1, 1, f_matchdelete}, | |
6661 {"matchend", 2, 4, f_matchend}, | |
6662 {"matchlist", 2, 4, f_matchlist}, | |
6663 {"matchstr", 2, 4, f_matchstr}, | |
6664 {"matchstrpos", 2, 4, f_matchstrpos}, | |
6665 {"max", 1, 1, f_max}, | |
6666 {"min", 1, 1, f_min}, | |
6667 #ifdef vim_mkdir | |
6668 {"mkdir", 1, 3, f_mkdir}, | |
6669 #endif | |
6670 {"mode", 0, 1, f_mode}, | |
6671 #ifdef FEAT_MZSCHEME | |
6672 {"mzeval", 1, 1, f_mzeval}, | |
6673 #endif | |
6674 {"nextnonblank", 1, 1, f_nextnonblank}, | |
6675 {"nr2char", 1, 2, f_nr2char}, | |
6676 {"or", 2, 2, f_or}, | |
6677 {"pathshorten", 1, 1, f_pathshorten}, | |
6678 #ifdef FEAT_PERL | |
6679 {"perleval", 1, 1, f_perleval}, | |
6680 #endif | |
6681 #ifdef FEAT_FLOAT | |
6682 {"pow", 2, 2, f_pow}, | |
6683 #endif | |
6684 {"prevnonblank", 1, 1, f_prevnonblank}, | |
6685 {"printf", 2, 19, f_printf}, | |
6686 {"pumvisible", 0, 0, f_pumvisible}, | |
6687 #ifdef FEAT_PYTHON3 | |
6688 {"py3eval", 1, 1, f_py3eval}, | |
6689 #endif | |
6690 #ifdef FEAT_PYTHON | |
6691 {"pyeval", 1, 1, f_pyeval}, | |
6692 #endif | |
6693 {"range", 1, 3, f_range}, | |
6694 {"readfile", 1, 3, f_readfile}, | |
6695 {"reltime", 0, 2, f_reltime}, | |
6696 #ifdef FEAT_FLOAT | |
6697 {"reltimefloat", 1, 1, f_reltimefloat}, | |
6698 #endif | |
6699 {"reltimestr", 1, 1, f_reltimestr}, | |
6700 {"remote_expr", 2, 3, f_remote_expr}, | |
6701 {"remote_foreground", 1, 1, f_remote_foreground}, | |
6702 {"remote_peek", 1, 2, f_remote_peek}, | |
6703 {"remote_read", 1, 1, f_remote_read}, | |
6704 {"remote_send", 2, 3, f_remote_send}, | |
6705 {"remove", 2, 3, f_remove}, | |
6706 {"rename", 2, 2, f_rename}, | |
6707 {"repeat", 2, 2, f_repeat}, | |
6708 {"resolve", 1, 1, f_resolve}, | |
6709 {"reverse", 1, 1, f_reverse}, | |
6710 #ifdef FEAT_FLOAT | |
6711 {"round", 1, 1, f_round}, | |
6712 #endif | |
6713 {"screenattr", 2, 2, f_screenattr}, | |
6714 {"screenchar", 2, 2, f_screenchar}, | |
6715 {"screencol", 0, 0, f_screencol}, | |
6716 {"screenrow", 0, 0, f_screenrow}, | |
6717 {"search", 1, 4, f_search}, | |
6718 {"searchdecl", 1, 3, f_searchdecl}, | |
6719 {"searchpair", 3, 7, f_searchpair}, | |
6720 {"searchpairpos", 3, 7, f_searchpairpos}, | |
6721 {"searchpos", 1, 4, f_searchpos}, | |
6722 {"server2client", 2, 2, f_server2client}, | |
6723 {"serverlist", 0, 0, f_serverlist}, | |
6724 {"setbufvar", 3, 3, f_setbufvar}, | |
6725 {"setcharsearch", 1, 1, f_setcharsearch}, | |
6726 {"setcmdpos", 1, 1, f_setcmdpos}, | |
6727 {"setfperm", 2, 2, f_setfperm}, | |
6728 {"setline", 2, 2, f_setline}, | |
6729 {"setloclist", 2, 3, f_setloclist}, | |
6730 {"setmatches", 1, 1, f_setmatches}, | |
6731 {"setpos", 2, 2, f_setpos}, | |
6732 {"setqflist", 1, 2, f_setqflist}, | |
6733 {"setreg", 2, 3, f_setreg}, | |
6734 {"settabvar", 3, 3, f_settabvar}, | |
6735 {"settabwinvar", 4, 4, f_settabwinvar}, | |
6736 {"setwinvar", 3, 3, f_setwinvar}, | |
6737 #ifdef FEAT_CRYPT | |
6738 {"sha256", 1, 1, f_sha256}, | |
6739 #endif | |
6740 {"shellescape", 1, 2, f_shellescape}, | |
6741 {"shiftwidth", 0, 0, f_shiftwidth}, | |
6742 {"simplify", 1, 1, f_simplify}, | |
6743 #ifdef FEAT_FLOAT | |
6744 {"sin", 1, 1, f_sin}, | |
6745 {"sinh", 1, 1, f_sinh}, | |
6746 #endif | |
6747 {"sort", 1, 3, f_sort}, | |
6748 {"soundfold", 1, 1, f_soundfold}, | |
6749 {"spellbadword", 0, 1, f_spellbadword}, | |
6750 {"spellsuggest", 1, 3, f_spellsuggest}, | |
6751 {"split", 1, 3, f_split}, | |
6752 #ifdef FEAT_FLOAT | |
6753 {"sqrt", 1, 1, f_sqrt}, | |
6754 {"str2float", 1, 1, f_str2float}, | |
6755 #endif | |
6756 {"str2nr", 1, 2, f_str2nr}, | |
6757 {"strcharpart", 2, 3, f_strcharpart}, | |
6758 {"strchars", 1, 2, f_strchars}, | |
6759 {"strdisplaywidth", 1, 2, f_strdisplaywidth}, | |
6760 #ifdef HAVE_STRFTIME | |
6761 {"strftime", 1, 2, f_strftime}, | |
6762 #endif | |
6763 {"strgetchar", 2, 2, f_strgetchar}, | |
6764 {"stridx", 2, 3, f_stridx}, | |
6765 {"string", 1, 1, f_string}, | |
6766 {"strlen", 1, 1, f_strlen}, | |
6767 {"strpart", 2, 3, f_strpart}, | |
6768 {"strridx", 2, 3, f_strridx}, | |
6769 {"strtrans", 1, 1, f_strtrans}, | |
6770 {"strwidth", 1, 1, f_strwidth}, | |
6771 {"submatch", 1, 2, f_submatch}, | |
6772 {"substitute", 4, 4, f_substitute}, | |
6773 {"synID", 3, 3, f_synID}, | |
6774 {"synIDattr", 2, 3, f_synIDattr}, | |
6775 {"synIDtrans", 1, 1, f_synIDtrans}, | |
6776 {"synconcealed", 2, 2, f_synconcealed}, | |
6777 {"synstack", 2, 2, f_synstack}, | |
6778 {"system", 1, 2, f_system}, | |
6779 {"systemlist", 1, 2, f_systemlist}, | |
6780 {"tabpagebuflist", 0, 1, f_tabpagebuflist}, | |
6781 {"tabpagenr", 0, 1, f_tabpagenr}, | |
6782 {"tabpagewinnr", 1, 2, f_tabpagewinnr}, | |
6783 {"tagfiles", 0, 0, f_tagfiles}, | |
6784 {"taglist", 1, 1, f_taglist}, | |
6785 #ifdef FEAT_FLOAT | |
6786 {"tan", 1, 1, f_tan}, | |
6787 {"tanh", 1, 1, f_tanh}, | |
6788 #endif | |
6789 {"tempname", 0, 0, f_tempname}, | |
6790 {"test_alloc_fail", 3, 3, f_test_alloc_fail}, | |
6791 {"test_autochdir", 0, 0, f_test_autochdir}, | |
6792 {"test_disable_char_avail", 1, 1, f_test_disable_char_avail}, | |
6793 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now}, | |
6794 #ifdef FEAT_JOB_CHANNEL | |
6795 {"test_null_channel", 0, 0, f_test_null_channel}, | |
6796 #endif | |
6797 {"test_null_dict", 0, 0, f_test_null_dict}, | |
6798 #ifdef FEAT_JOB_CHANNEL | |
6799 {"test_null_job", 0, 0, f_test_null_job}, | |
6800 #endif | |
6801 {"test_null_list", 0, 0, f_test_null_list}, | |
6802 {"test_null_partial", 0, 0, f_test_null_partial}, | |
6803 {"test_null_string", 0, 0, f_test_null_string}, | |
6804 {"test_settime", 1, 1, f_test_settime}, | |
6805 #ifdef FEAT_TIMERS | |
6806 {"timer_start", 2, 3, f_timer_start}, | |
6807 {"timer_stop", 1, 1, f_timer_stop}, | |
6808 #endif | |
6809 {"tolower", 1, 1, f_tolower}, | |
6810 {"toupper", 1, 1, f_toupper}, | |
6811 {"tr", 3, 3, f_tr}, | |
6812 #ifdef FEAT_FLOAT | |
6813 {"trunc", 1, 1, f_trunc}, | |
6814 #endif | |
6815 {"type", 1, 1, f_type}, | |
6816 {"undofile", 1, 1, f_undofile}, | |
6817 {"undotree", 0, 0, f_undotree}, | |
6818 {"uniq", 1, 3, f_uniq}, | |
6819 {"values", 1, 1, f_values}, | |
6820 {"virtcol", 1, 1, f_virtcol}, | |
6821 {"visualmode", 0, 1, f_visualmode}, | |
6822 {"wildmenumode", 0, 0, f_wildmenumode}, | |
6823 {"win_findbuf", 1, 1, f_win_findbuf}, | |
6824 {"win_getid", 0, 2, f_win_getid}, | |
6825 {"win_gotoid", 1, 1, f_win_gotoid}, | |
6826 {"win_id2tabwin", 1, 1, f_win_id2tabwin}, | |
6827 {"win_id2win", 1, 1, f_win_id2win}, | |
6828 {"winbufnr", 1, 1, f_winbufnr}, | |
6829 {"wincol", 0, 0, f_wincol}, | |
6830 {"winheight", 1, 1, f_winheight}, | |
6831 {"winline", 0, 0, f_winline}, | |
6832 {"winnr", 0, 1, f_winnr}, | |
6833 {"winrestcmd", 0, 0, f_winrestcmd}, | |
6834 {"winrestview", 1, 1, f_winrestview}, | |
6835 {"winsaveview", 0, 0, f_winsaveview}, | |
6836 {"winwidth", 1, 1, f_winwidth}, | |
6837 {"wordcount", 0, 0, f_wordcount}, | |
6838 {"writefile", 2, 3, f_writefile}, | |
6839 {"xor", 2, 2, f_xor}, | |
6840 }; | |
6841 | |
6842 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) | |
6843 | |
6844 /* | |
6845 * Function given to ExpandGeneric() to obtain the list of internal | |
6846 * or user defined function names. | |
6847 */ | |
6848 char_u * | |
6849 get_function_name(expand_T *xp, int idx) | |
6850 { | |
6851 static int intidx = -1; | |
6852 char_u *name; | |
6853 | |
6854 if (idx == 0) | |
6855 intidx = -1; | |
6856 if (intidx < 0) | |
6857 { | |
6858 name = get_user_func_name(xp, idx); | |
6859 if (name != NULL) | |
6860 return name; | |
6861 } | |
6862 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst))) | |
6863 { | |
6864 STRCPY(IObuff, functions[intidx].f_name); | |
6865 STRCAT(IObuff, "("); | |
6866 if (functions[intidx].f_max_argc == 0) | |
6867 STRCAT(IObuff, ")"); | |
6868 return IObuff; | |
6869 } | |
6870 | |
6871 return NULL; | |
6872 } | |
6873 | |
6874 /* | |
6875 * Function given to ExpandGeneric() to obtain the list of internal or | |
6876 * user defined variable or function names. | |
6877 */ | |
6878 char_u * | |
6879 get_expr_name(expand_T *xp, int idx) | |
6880 { | |
6881 static int intidx = -1; | |
6882 char_u *name; | |
6883 | |
6884 if (idx == 0) | |
6885 intidx = -1; | |
6886 if (intidx < 0) | |
6887 { | |
6888 name = get_function_name(xp, idx); | |
6889 if (name != NULL) | |
6890 return name; | |
6891 } | |
6892 return get_user_var_name(xp, ++intidx); | |
6893 } | |
6894 | |
6895 #endif /* FEAT_CMDL_COMPL */ | |
6896 | |
6897 #if defined(EBCDIC) || defined(PROTO) | |
6898 /* | |
6899 * Compare struct fst by function name. | |
6900 */ | |
6901 static int | |
6902 compare_func_name(const void *s1, const void *s2) | |
6903 { | |
6904 struct fst *p1 = (struct fst *)s1; | |
6905 struct fst *p2 = (struct fst *)s2; | |
6906 | |
6907 return STRCMP(p1->f_name, p2->f_name); | |
6908 } | |
6909 | |
6910 /* | |
6911 * Sort the function table by function name. | |
6912 * The sorting of the table above is ASCII dependant. | |
6913 * On machines using EBCDIC we have to sort it. | |
6914 */ | |
6915 static void | |
6916 sortFunctions(void) | |
6917 { | |
6918 int funcCnt = (int)(sizeof(functions) / sizeof(struct fst)) - 1; | |
6919 | |
6920 qsort(functions, (size_t)funcCnt, sizeof(struct fst), compare_func_name); | |
6921 } | |
6922 #endif | |
6923 | |
6924 | |
6925 /* | |
6926 * Find internal function in table above. | |
6927 * Return index, or -1 if not found | |
6928 */ | |
6929 int | |
6930 find_internal_func( | |
6931 char_u *name) /* name of the function */ | |
6932 { | |
6933 int first = 0; | |
6934 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1; | |
6935 int cmp; | |
6936 int x; | |
6937 | |
6938 /* | |
6939 * Find the function name in the table. Binary search. | |
6940 */ | |
6941 while (first <= last) | |
6942 { | |
6943 x = first + ((unsigned)(last - first) >> 1); | |
6944 cmp = STRCMP(name, functions[x].f_name); | |
6945 if (cmp < 0) | |
6946 last = x - 1; | |
6947 else if (cmp > 0) | |
6948 first = x + 1; | |
6949 else | |
6950 return x; | |
6951 } | |
6952 return -1; | |
6953 } | |
6954 | |
6955 int | |
6956 call_internal_func( | |
6957 char_u *name, | |
6958 int argcount, | |
6959 typval_T *argvars, | |
6960 typval_T *rettv) | |
6961 { | |
6962 int i; | |
6963 | |
6964 i = find_internal_func(name); | |
6965 if (i < 0) | |
6966 return ERROR_UNKNOWN; | |
6967 if (argcount < functions[i].f_min_argc) | |
6968 return ERROR_TOOFEW; | |
6969 if (argcount > functions[i].f_max_argc) | |
6970 return ERROR_TOOMANY; | |
6971 argvars[argcount].v_type = VAR_UNKNOWN; | |
6972 functions[i].f_func(argvars, rettv); | |
6973 return ERROR_NONE; | |
6974 } | |
6975 | |
6976 /* | |
6977 * Return TRUE for a non-zero Number and a non-empty String. | |
6978 */ | |
6979 static int | |
6980 non_zero_arg(typval_T *argvars) | |
6981 { | |
6982 return ((argvars[0].v_type == VAR_NUMBER | |
6983 && argvars[0].vval.v_number != 0) | |
6984 || (argvars[0].v_type == VAR_SPECIAL | |
6985 && argvars[0].vval.v_number == VVAL_TRUE) | |
6986 || (argvars[0].v_type == VAR_STRING | |
6987 && argvars[0].vval.v_string != NULL | |
6988 && *argvars[0].vval.v_string != NUL)); | |
6989 } | |
6990 | |
6991 /********************************************* | |
6992 * Implementation of the built-in functions | |
6993 */ | |
6994 | |
6995 #ifdef FEAT_FLOAT | |
6996 static int get_float_arg(typval_T *argvars, float_T *f); | |
6997 | |
6998 /* | |
6999 * Get the float value of "argvars[0]" into "f". | |
7000 * Returns FAIL when the argument is not a Number or Float. | |
7001 */ | |
7002 static int | |
7003 get_float_arg(typval_T *argvars, float_T *f) | |
7004 { | |
7005 if (argvars[0].v_type == VAR_FLOAT) | |
7006 { | |
7007 *f = argvars[0].vval.v_float; | |
7008 return OK; | |
7009 } | |
7010 if (argvars[0].v_type == VAR_NUMBER) | |
7011 { | |
7012 *f = (float_T)argvars[0].vval.v_number; | |
7013 return OK; | |
7014 } | |
7015 EMSG(_("E808: Number or Float required")); | |
7016 return FAIL; | |
7017 } | |
7018 | |
7019 /* | |
7020 * "abs(expr)" function | |
7021 */ | |
7022 static void | |
7023 f_abs(typval_T *argvars, typval_T *rettv) | |
7024 { | |
7025 if (argvars[0].v_type == VAR_FLOAT) | |
7026 { | |
7027 rettv->v_type = VAR_FLOAT; | |
7028 rettv->vval.v_float = fabs(argvars[0].vval.v_float); | |
7029 } | |
7030 else | |
7031 { | |
7032 varnumber_T n; | |
7033 int error = FALSE; | |
7034 | |
7035 n = get_tv_number_chk(&argvars[0], &error); | |
7036 if (error) | |
7037 rettv->vval.v_number = -1; | |
7038 else if (n > 0) | |
7039 rettv->vval.v_number = n; | |
7040 else | |
7041 rettv->vval.v_number = -n; | |
7042 } | |
7043 } | |
7044 | |
7045 /* | |
7046 * "acos()" function | |
7047 */ | |
7048 static void | |
7049 f_acos(typval_T *argvars, typval_T *rettv) | |
7050 { | |
7051 float_T f = 0.0; | |
7052 | |
7053 rettv->v_type = VAR_FLOAT; | |
7054 if (get_float_arg(argvars, &f) == OK) | |
7055 rettv->vval.v_float = acos(f); | |
7056 else | |
7057 rettv->vval.v_float = 0.0; | |
7058 } | |
7059 #endif | |
7060 | |
7061 /* | |
7062 * "add(list, item)" function | |
7063 */ | |
7064 static void | |
7065 f_add(typval_T *argvars, typval_T *rettv) | |
7066 { | |
7067 list_T *l; | |
7068 | |
7069 rettv->vval.v_number = 1; /* Default: Failed */ | |
7070 if (argvars[0].v_type == VAR_LIST) | |
7071 { | |
7072 if ((l = argvars[0].vval.v_list) != NULL | |
7073 && !tv_check_lock(l->lv_lock, | |
7074 (char_u *)N_("add() argument"), TRUE) | |
7075 && list_append_tv(l, &argvars[1]) == OK) | |
7076 copy_tv(&argvars[0], rettv); | |
7077 } | |
7078 else | |
7079 EMSG(_(e_listreq)); | |
7080 } | |
7081 | |
7082 /* | |
7083 * "and(expr, expr)" function | |
7084 */ | |
7085 static void | |
7086 f_and(typval_T *argvars, typval_T *rettv) | |
7087 { | |
7088 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | |
7089 & get_tv_number_chk(&argvars[1], NULL); | |
7090 } | |
7091 | |
7092 /* | |
7093 * "append(lnum, string/list)" function | |
7094 */ | |
7095 static void | |
7096 f_append(typval_T *argvars, typval_T *rettv) | |
7097 { | |
7098 long lnum; | |
7099 char_u *line; | |
7100 list_T *l = NULL; | |
7101 listitem_T *li = NULL; | |
7102 typval_T *tv; | |
7103 long added = 0; | |
7104 | |
7105 /* When coming here from Insert mode, sync undo, so that this can be | |
7106 * undone separately from what was previously inserted. */ | |
7107 if (u_sync_once == 2) | |
7108 { | |
7109 u_sync_once = 1; /* notify that u_sync() was called */ | |
7110 u_sync(TRUE); | |
7111 } | |
7112 | |
7113 lnum = get_tv_lnum(argvars); | |
7114 if (lnum >= 0 | |
7115 && lnum <= curbuf->b_ml.ml_line_count | |
7116 && u_save(lnum, lnum + 1) == OK) | |
7117 { | |
7118 if (argvars[1].v_type == VAR_LIST) | |
7119 { | |
7120 l = argvars[1].vval.v_list; | |
7121 if (l == NULL) | |
7122 return; | |
7123 li = l->lv_first; | |
7124 } | |
7125 for (;;) | |
7126 { | |
7127 if (l == NULL) | |
7128 tv = &argvars[1]; /* append a string */ | |
7129 else if (li == NULL) | |
7130 break; /* end of list */ | |
7131 else | |
7132 tv = &li->li_tv; /* append item from list */ | |
7133 line = get_tv_string_chk(tv); | |
7134 if (line == NULL) /* type error */ | |
7135 { | |
7136 rettv->vval.v_number = 1; /* Failed */ | |
7137 break; | |
7138 } | |
7139 ml_append(lnum + added, line, (colnr_T)0, FALSE); | |
7140 ++added; | |
7141 if (l == NULL) | |
7142 break; | |
7143 li = li->li_next; | |
7144 } | |
7145 | |
7146 appended_lines_mark(lnum, added); | |
7147 if (curwin->w_cursor.lnum > lnum) | |
7148 curwin->w_cursor.lnum += added; | |
7149 } | |
7150 else | |
7151 rettv->vval.v_number = 1; /* Failed */ | |
7152 } | |
7153 | |
7154 /* | |
7155 * "argc()" function | |
7156 */ | |
7157 static void | |
7158 f_argc(typval_T *argvars UNUSED, typval_T *rettv) | |
7159 { | |
7160 rettv->vval.v_number = ARGCOUNT; | |
7161 } | |
7162 | |
7163 /* | |
7164 * "argidx()" function | |
7165 */ | |
7166 static void | |
7167 f_argidx(typval_T *argvars UNUSED, typval_T *rettv) | |
7168 { | |
7169 rettv->vval.v_number = curwin->w_arg_idx; | |
7170 } | |
7171 | |
7172 /* | |
7173 * "arglistid()" function | |
7174 */ | |
7175 static void | |
7176 f_arglistid(typval_T *argvars, typval_T *rettv) | |
7177 { | |
7178 win_T *wp; | |
7179 | |
7180 rettv->vval.v_number = -1; | |
7181 wp = find_tabwin(&argvars[0], &argvars[1]); | |
7182 if (wp != NULL) | |
7183 rettv->vval.v_number = wp->w_alist->id; | |
7184 } | |
7185 | |
7186 /* | |
7187 * "argv(nr)" function | |
7188 */ | |
7189 static void | |
7190 f_argv(typval_T *argvars, typval_T *rettv) | |
7191 { | |
7192 int idx; | |
7193 | |
7194 if (argvars[0].v_type != VAR_UNKNOWN) | |
7195 { | |
7196 idx = (int)get_tv_number_chk(&argvars[0], NULL); | |
7197 if (idx >= 0 && idx < ARGCOUNT) | |
7198 rettv->vval.v_string = vim_strsave(alist_name(&ARGLIST[idx])); | |
7199 else | |
7200 rettv->vval.v_string = NULL; | |
7201 rettv->v_type = VAR_STRING; | |
7202 } | |
7203 else if (rettv_list_alloc(rettv) == OK) | |
7204 for (idx = 0; idx < ARGCOUNT; ++idx) | |
7205 list_append_string(rettv->vval.v_list, | |
7206 alist_name(&ARGLIST[idx]), -1); | |
7207 } | |
7208 | |
7209 typedef enum | |
7210 { | |
7211 ASSERT_EQUAL, | |
7212 ASSERT_NOTEQUAL, | |
7213 ASSERT_MATCH, | |
7214 ASSERT_NOTMATCH, | |
7215 ASSERT_OTHER | |
7216 } assert_type_T; | |
7217 | |
7218 static void prepare_assert_error(garray_T*gap); | |
7219 static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv, typval_T *got_tv, assert_type_T is_match); | |
7220 static void assert_error(garray_T *gap); | |
7221 static void assert_bool(typval_T *argvars, int isTrue); | |
7222 | |
7223 /* | |
7224 * Prepare "gap" for an assert error and add the sourcing position. | |
7225 */ | |
7226 static void | |
7227 prepare_assert_error(garray_T *gap) | |
7228 { | |
7229 char buf[NUMBUFLEN]; | |
7230 | |
7231 ga_init2(gap, 1, 100); | |
7232 if (sourcing_name != NULL) | |
7233 { | |
7234 ga_concat(gap, sourcing_name); | |
7235 if (sourcing_lnum > 0) | |
7236 ga_concat(gap, (char_u *)" "); | |
7237 } | |
7238 if (sourcing_lnum > 0) | |
7239 { | |
7240 sprintf(buf, "line %ld", (long)sourcing_lnum); | |
7241 ga_concat(gap, (char_u *)buf); | |
7242 } | |
7243 if (sourcing_name != NULL || sourcing_lnum > 0) | |
7244 ga_concat(gap, (char_u *)": "); | |
7245 } | |
7246 | |
7247 /* | |
7248 * Append "str" to "gap", escaping unprintable characters. | |
7249 * Changes NL to \n, CR to \r, etc. | |
7250 */ | |
7251 static void | |
7252 ga_concat_esc(garray_T *gap, char_u *str) | |
7253 { | |
7254 char_u *p; | |
7255 char_u buf[NUMBUFLEN]; | |
7256 | |
7257 if (str == NULL) | |
7258 { | |
7259 ga_concat(gap, (char_u *)"NULL"); | |
7260 return; | |
7261 } | |
7262 | |
7263 for (p = str; *p != NUL; ++p) | |
7264 switch (*p) | |
7265 { | |
7266 case BS: ga_concat(gap, (char_u *)"\\b"); break; | |
7267 case ESC: ga_concat(gap, (char_u *)"\\e"); break; | |
7268 case FF: ga_concat(gap, (char_u *)"\\f"); break; | |
7269 case NL: ga_concat(gap, (char_u *)"\\n"); break; | |
7270 case TAB: ga_concat(gap, (char_u *)"\\t"); break; | |
7271 case CAR: ga_concat(gap, (char_u *)"\\r"); break; | |
7272 case '\\': ga_concat(gap, (char_u *)"\\\\"); break; | |
7273 default: | |
7274 if (*p < ' ') | |
7275 { | |
7276 vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p); | |
7277 ga_concat(gap, buf); | |
7278 } | |
7279 else | |
7280 ga_append(gap, *p); | |
7281 break; | |
7282 } | |
7283 } | |
7284 | |
7285 /* | |
7286 * Fill "gap" with information about an assert error. | |
7287 */ | |
7288 static void | |
7289 fill_assert_error( | |
7290 garray_T *gap, | |
7291 typval_T *opt_msg_tv, | |
7292 char_u *exp_str, | |
7293 typval_T *exp_tv, | |
7294 typval_T *got_tv, | |
7295 assert_type_T atype) | |
7296 { | |
7297 char_u numbuf[NUMBUFLEN]; | |
7298 char_u *tofree; | |
7299 | |
7300 if (opt_msg_tv->v_type != VAR_UNKNOWN) | |
7301 { | |
7302 ga_concat(gap, tv2string(opt_msg_tv, &tofree, numbuf, 0)); | |
7303 vim_free(tofree); | |
7304 } | |
7305 else | |
7306 { | |
7307 if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) | |
7308 ga_concat(gap, (char_u *)"Pattern "); | |
7309 else | |
7310 ga_concat(gap, (char_u *)"Expected "); | |
7311 if (exp_str == NULL) | |
7312 { | |
7313 ga_concat_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0)); | |
7314 vim_free(tofree); | |
7315 } | |
7316 else | |
7317 ga_concat_esc(gap, exp_str); | |
7318 if (atype == ASSERT_MATCH) | |
7319 ga_concat(gap, (char_u *)" does not match "); | |
7320 else if (atype == ASSERT_NOTMATCH) | |
7321 ga_concat(gap, (char_u *)" does match "); | |
7322 else if (atype == ASSERT_NOTEQUAL) | |
7323 ga_concat(gap, (char_u *)" differs from "); | |
7324 else | |
7325 ga_concat(gap, (char_u *)" but got "); | |
7326 ga_concat_esc(gap, tv2string(got_tv, &tofree, numbuf, 0)); | |
7327 vim_free(tofree); | |
7328 } | |
7329 } | |
7330 | |
7331 /* | |
7332 * Add an assert error to v:errors. | |
7333 */ | |
7334 static void | |
7335 assert_error(garray_T *gap) | |
7336 { | |
7337 struct vimvar *vp = &vimvars[VV_ERRORS]; | |
7338 | |
7339 if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) | |
7340 /* Make sure v:errors is a list. */ | |
7341 set_vim_var_list(VV_ERRORS, list_alloc()); | |
7342 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len); | |
7343 } | |
7344 | |
7345 static void | |
7346 assert_equal_common(typval_T *argvars, assert_type_T atype) | |
7347 { | |
7348 garray_T ga; | |
7349 | |
7350 if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE) | |
7351 != (atype == ASSERT_EQUAL)) | |
7352 { | |
7353 prepare_assert_error(&ga); | |
7354 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], | |
7355 atype); | |
7356 assert_error(&ga); | |
7357 ga_clear(&ga); | |
7358 } | |
7359 } | |
7360 | |
7361 /* | |
7362 * "assert_equal(expected, actual[, msg])" function | |
7363 */ | |
7364 static void | |
7365 f_assert_equal(typval_T *argvars, typval_T *rettv UNUSED) | |
7366 { | |
7367 assert_equal_common(argvars, ASSERT_EQUAL); | |
7368 } | |
7369 | |
7370 /* | |
7371 * "assert_notequal(expected, actual[, msg])" function | |
7372 */ | |
7373 static void | |
7374 f_assert_notequal(typval_T *argvars, typval_T *rettv UNUSED) | |
7375 { | |
7376 assert_equal_common(argvars, ASSERT_NOTEQUAL); | |
7377 } | |
7378 | |
7379 /* | |
7380 * "assert_exception(string[, msg])" function | |
7381 */ | |
7382 static void | |
7383 f_assert_exception(typval_T *argvars, typval_T *rettv UNUSED) | |
7384 { | |
7385 garray_T ga; | |
7386 char *error; | |
7387 | |
7388 error = (char *)get_tv_string_chk(&argvars[0]); | |
7389 if (vimvars[VV_EXCEPTION].vv_str == NULL) | |
7390 { | |
7391 prepare_assert_error(&ga); | |
7392 ga_concat(&ga, (char_u *)"v:exception is not set"); | |
7393 assert_error(&ga); | |
7394 ga_clear(&ga); | |
7395 } | |
7396 else if (error != NULL | |
7397 && strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) | |
7398 { | |
7399 prepare_assert_error(&ga); | |
7400 fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], | |
7401 &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER); | |
7402 assert_error(&ga); | |
7403 ga_clear(&ga); | |
7404 } | |
7405 } | |
7406 | |
7407 /* | |
7408 * "assert_fails(cmd [, error])" function | |
7409 */ | |
7410 static void | |
7411 f_assert_fails(typval_T *argvars, typval_T *rettv UNUSED) | |
7412 { | |
7413 char_u *cmd = get_tv_string_chk(&argvars[0]); | |
7414 garray_T ga; | |
7415 | |
7416 called_emsg = FALSE; | |
7417 suppress_errthrow = TRUE; | |
7418 emsg_silent = TRUE; | |
7419 do_cmdline_cmd(cmd); | |
7420 if (!called_emsg) | |
7421 { | |
7422 prepare_assert_error(&ga); | |
7423 ga_concat(&ga, (char_u *)"command did not fail: "); | |
7424 ga_concat(&ga, cmd); | |
7425 assert_error(&ga); | |
7426 ga_clear(&ga); | |
7427 } | |
7428 else if (argvars[1].v_type != VAR_UNKNOWN) | |
7429 { | |
7430 char_u buf[NUMBUFLEN]; | |
7431 char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf); | |
7432 | |
7433 if (error == NULL | |
7434 || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) | |
7435 { | |
7436 prepare_assert_error(&ga); | |
7437 fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], | |
7438 &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER); | |
7439 assert_error(&ga); | |
7440 ga_clear(&ga); | |
7441 } | |
7442 } | |
7443 | |
7444 called_emsg = FALSE; | |
7445 suppress_errthrow = FALSE; | |
7446 emsg_silent = FALSE; | |
7447 emsg_on_display = FALSE; | |
7448 set_vim_var_string(VV_ERRMSG, NULL, 0); | |
7449 } | |
7450 | |
7451 /* | |
7452 * Common for assert_true() and assert_false(). | |
7453 */ | |
7454 static void | |
7455 assert_bool(typval_T *argvars, int isTrue) | |
7456 { | |
7457 int error = FALSE; | |
7458 garray_T ga; | |
7459 | |
7460 if (argvars[0].v_type == VAR_SPECIAL | |
7461 && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE)) | |
7462 return; | |
7463 if (argvars[0].v_type != VAR_NUMBER | |
7464 || (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue | |
7465 || error) | |
7466 { | |
7467 prepare_assert_error(&ga); | |
7468 fill_assert_error(&ga, &argvars[1], | |
7469 (char_u *)(isTrue ? "True" : "False"), | |
7470 NULL, &argvars[0], ASSERT_OTHER); | |
7471 assert_error(&ga); | |
7472 ga_clear(&ga); | |
7473 } | |
7474 } | |
7475 | |
7476 /* | |
7477 * "assert_false(actual[, msg])" function | |
7478 */ | |
7479 static void | |
7480 f_assert_false(typval_T *argvars, typval_T *rettv UNUSED) | |
7481 { | |
7482 assert_bool(argvars, FALSE); | |
7483 } | |
7484 | |
7485 static void | |
7486 assert_match_common(typval_T *argvars, assert_type_T atype) | |
7487 { | |
7488 garray_T ga; | |
7489 char_u buf1[NUMBUFLEN]; | |
7490 char_u buf2[NUMBUFLEN]; | |
7491 char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1); | |
7492 char_u *text = get_tv_string_buf_chk(&argvars[1], buf2); | |
7493 | |
7494 if (pat == NULL || text == NULL) | |
7495 EMSG(_(e_invarg)); | |
7496 else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH)) | |
7497 { | |
7498 prepare_assert_error(&ga); | |
7499 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], | |
7500 atype); | |
7501 assert_error(&ga); | |
7502 ga_clear(&ga); | |
7503 } | |
7504 } | |
7505 | |
7506 /* | |
7507 * "assert_match(pattern, actual[, msg])" function | |
7508 */ | |
7509 static void | |
7510 f_assert_match(typval_T *argvars, typval_T *rettv UNUSED) | |
7511 { | |
7512 assert_match_common(argvars, ASSERT_MATCH); | |
7513 } | |
7514 | |
7515 /* | |
7516 * "assert_notmatch(pattern, actual[, msg])" function | |
7517 */ | |
7518 static void | |
7519 f_assert_notmatch(typval_T *argvars, typval_T *rettv UNUSED) | |
7520 { | |
7521 assert_match_common(argvars, ASSERT_NOTMATCH); | |
7522 } | |
7523 | |
7524 /* | |
7525 * "assert_true(actual[, msg])" function | |
7526 */ | |
7527 static void | |
7528 f_assert_true(typval_T *argvars, typval_T *rettv UNUSED) | |
7529 { | |
7530 assert_bool(argvars, TRUE); | |
7531 } | |
7532 | |
7533 #ifdef FEAT_FLOAT | |
7534 /* | |
7535 * "asin()" function | |
7536 */ | |
7537 static void | |
7538 f_asin(typval_T *argvars, typval_T *rettv) | |
7539 { | |
7540 float_T f = 0.0; | |
7541 | |
7542 rettv->v_type = VAR_FLOAT; | |
7543 if (get_float_arg(argvars, &f) == OK) | |
7544 rettv->vval.v_float = asin(f); | |
7545 else | |
7546 rettv->vval.v_float = 0.0; | |
7547 } | |
7548 | |
7549 /* | |
7550 * "atan()" function | |
7551 */ | |
7552 static void | |
7553 f_atan(typval_T *argvars, typval_T *rettv) | |
7554 { | |
7555 float_T f = 0.0; | |
7556 | |
7557 rettv->v_type = VAR_FLOAT; | |
7558 if (get_float_arg(argvars, &f) == OK) | |
7559 rettv->vval.v_float = atan(f); | |
7560 else | |
7561 rettv->vval.v_float = 0.0; | |
7562 } | |
7563 | |
7564 /* | |
7565 * "atan2()" function | |
7566 */ | |
7567 static void | |
7568 f_atan2(typval_T *argvars, typval_T *rettv) | |
7569 { | |
7570 float_T fx = 0.0, fy = 0.0; | |
7571 | |
7572 rettv->v_type = VAR_FLOAT; | |
7573 if (get_float_arg(argvars, &fx) == OK | |
7574 && get_float_arg(&argvars[1], &fy) == OK) | |
7575 rettv->vval.v_float = atan2(fx, fy); | |
7576 else | |
7577 rettv->vval.v_float = 0.0; | |
7578 } | |
7579 #endif | |
7580 | |
7581 /* | |
7582 * "browse(save, title, initdir, default)" function | |
7583 */ | |
7584 static void | |
7585 f_browse(typval_T *argvars UNUSED, typval_T *rettv) | |
7586 { | |
7587 #ifdef FEAT_BROWSE | |
7588 int save; | |
7589 char_u *title; | |
7590 char_u *initdir; | |
7591 char_u *defname; | |
7592 char_u buf[NUMBUFLEN]; | |
7593 char_u buf2[NUMBUFLEN]; | |
7594 int error = FALSE; | |
7595 | |
7596 save = (int)get_tv_number_chk(&argvars[0], &error); | |
7597 title = get_tv_string_chk(&argvars[1]); | |
7598 initdir = get_tv_string_buf_chk(&argvars[2], buf); | |
7599 defname = get_tv_string_buf_chk(&argvars[3], buf2); | |
7600 | |
7601 if (error || title == NULL || initdir == NULL || defname == NULL) | |
7602 rettv->vval.v_string = NULL; | |
7603 else | |
7604 rettv->vval.v_string = | |
7605 do_browse(save ? BROWSE_SAVE : 0, | |
7606 title, defname, NULL, initdir, NULL, curbuf); | |
7607 #else | |
7608 rettv->vval.v_string = NULL; | |
7609 #endif | |
7610 rettv->v_type = VAR_STRING; | |
7611 } | |
7612 | |
7613 /* | |
7614 * "browsedir(title, initdir)" function | |
7615 */ | |
7616 static void | |
7617 f_browsedir(typval_T *argvars UNUSED, typval_T *rettv) | |
7618 { | |
7619 #ifdef FEAT_BROWSE | |
7620 char_u *title; | |
7621 char_u *initdir; | |
7622 char_u buf[NUMBUFLEN]; | |
7623 | |
7624 title = get_tv_string_chk(&argvars[0]); | |
7625 initdir = get_tv_string_buf_chk(&argvars[1], buf); | |
7626 | |
7627 if (title == NULL || initdir == NULL) | |
7628 rettv->vval.v_string = NULL; | |
7629 else | |
7630 rettv->vval.v_string = do_browse(BROWSE_DIR, | |
7631 title, NULL, NULL, initdir, NULL, curbuf); | |
7632 #else | |
7633 rettv->vval.v_string = NULL; | |
7634 #endif | |
7635 rettv->v_type = VAR_STRING; | |
7636 } | |
7637 | |
7638 static buf_T *find_buffer(typval_T *avar); | |
7639 | |
7640 /* | |
7641 * Find a buffer by number or exact name. | |
7642 */ | |
7643 static buf_T * | |
7644 find_buffer(typval_T *avar) | |
7645 { | |
7646 buf_T *buf = NULL; | |
7647 | |
7648 if (avar->v_type == VAR_NUMBER) | |
7649 buf = buflist_findnr((int)avar->vval.v_number); | |
7650 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) | |
7651 { | |
7652 buf = buflist_findname_exp(avar->vval.v_string); | |
7653 if (buf == NULL) | |
7654 { | |
7655 /* No full path name match, try a match with a URL or a "nofile" | |
7656 * buffer, these don't use the full path. */ | |
7657 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
7658 if (buf->b_fname != NULL | |
7659 && (path_with_url(buf->b_fname) | |
7660 #ifdef FEAT_QUICKFIX | |
7661 || bt_nofile(buf) | |
7662 #endif | |
7663 ) | |
7664 && STRCMP(buf->b_fname, avar->vval.v_string) == 0) | |
7665 break; | |
7666 } | |
7667 } | |
7668 return buf; | |
7669 } | |
7670 | |
7671 /* | |
7672 * "bufexists(expr)" function | |
7673 */ | |
7674 static void | |
7675 f_bufexists(typval_T *argvars, typval_T *rettv) | |
7676 { | |
7677 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL); | |
7678 } | |
7679 | |
7680 /* | |
7681 * "buflisted(expr)" function | |
7682 */ | |
7683 static void | |
7684 f_buflisted(typval_T *argvars, typval_T *rettv) | |
7685 { | |
7686 buf_T *buf; | |
7687 | |
7688 buf = find_buffer(&argvars[0]); | |
7689 rettv->vval.v_number = (buf != NULL && buf->b_p_bl); | |
7690 } | |
7691 | |
7692 /* | |
7693 * "bufloaded(expr)" function | |
7694 */ | |
7695 static void | |
7696 f_bufloaded(typval_T *argvars, typval_T *rettv) | |
7697 { | |
7698 buf_T *buf; | |
7699 | |
7700 buf = find_buffer(&argvars[0]); | |
7701 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL); | |
7702 } | |
7703 | |
7704 buf_T * | |
7705 buflist_find_by_name(char_u *name, int curtab_only) | |
7706 { | |
7707 int save_magic; | |
7708 char_u *save_cpo; | |
7709 buf_T *buf; | |
7710 | |
7711 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */ | |
7712 save_magic = p_magic; | |
7713 p_magic = TRUE; | |
7714 save_cpo = p_cpo; | |
7715 p_cpo = (char_u *)""; | |
7716 | |
7717 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name), | |
7718 TRUE, FALSE, curtab_only)); | |
7719 | |
7720 p_magic = save_magic; | |
7721 p_cpo = save_cpo; | |
7722 return buf; | |
7723 } | |
7724 | |
7725 /* | |
7726 * Get buffer by number or pattern. | |
7727 */ | |
7728 static buf_T * | |
7729 get_buf_tv(typval_T *tv, int curtab_only) | |
7730 { | |
7731 char_u *name = tv->vval.v_string; | |
7732 buf_T *buf; | |
7733 | |
7734 if (tv->v_type == VAR_NUMBER) | |
7735 return buflist_findnr((int)tv->vval.v_number); | |
7736 if (tv->v_type != VAR_STRING) | |
7737 return NULL; | |
7738 if (name == NULL || *name == NUL) | |
7739 return curbuf; | |
7740 if (name[0] == '$' && name[1] == NUL) | |
7741 return lastbuf; | |
7742 | |
7743 buf = buflist_find_by_name(name, curtab_only); | |
7744 | |
7745 /* If not found, try expanding the name, like done for bufexists(). */ | |
7746 if (buf == NULL) | |
7747 buf = find_buffer(tv); | |
7748 | |
7749 return buf; | |
7750 } | |
7751 | |
7752 /* | |
7753 * "bufname(expr)" function | |
7754 */ | |
7755 static void | |
7756 f_bufname(typval_T *argvars, typval_T *rettv) | |
7757 { | |
7758 buf_T *buf; | |
7759 | |
7760 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
7761 ++emsg_off; | |
7762 buf = get_buf_tv(&argvars[0], FALSE); | |
7763 rettv->v_type = VAR_STRING; | |
7764 if (buf != NULL && buf->b_fname != NULL) | |
7765 rettv->vval.v_string = vim_strsave(buf->b_fname); | |
7766 else | |
7767 rettv->vval.v_string = NULL; | |
7768 --emsg_off; | |
7769 } | |
7770 | |
7771 /* | |
7772 * "bufnr(expr)" function | |
7773 */ | |
7774 static void | |
7775 f_bufnr(typval_T *argvars, typval_T *rettv) | |
7776 { | |
7777 buf_T *buf; | |
7778 int error = FALSE; | |
7779 char_u *name; | |
7780 | |
7781 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
7782 ++emsg_off; | |
7783 buf = get_buf_tv(&argvars[0], FALSE); | |
7784 --emsg_off; | |
7785 | |
7786 /* If the buffer isn't found and the second argument is not zero create a | |
7787 * new buffer. */ | |
7788 if (buf == NULL | |
7789 && argvars[1].v_type != VAR_UNKNOWN | |
7790 && get_tv_number_chk(&argvars[1], &error) != 0 | |
7791 && !error | |
7792 && (name = get_tv_string_chk(&argvars[0])) != NULL | |
7793 && !error) | |
7794 buf = buflist_new(name, NULL, (linenr_T)1, 0); | |
7795 | |
7796 if (buf != NULL) | |
7797 rettv->vval.v_number = buf->b_fnum; | |
7798 else | |
7799 rettv->vval.v_number = -1; | |
7800 } | |
7801 | |
7802 static void | |
7803 buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr) | |
7804 { | |
7805 #ifdef FEAT_WINDOWS | |
7806 win_T *wp; | |
7807 int winnr = 0; | |
7808 #endif | |
7809 buf_T *buf; | |
7810 | |
7811 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
7812 ++emsg_off; | |
7813 buf = get_buf_tv(&argvars[0], TRUE); | |
7814 #ifdef FEAT_WINDOWS | |
7815 for (wp = firstwin; wp; wp = wp->w_next) | |
7816 { | |
7817 ++winnr; | |
7818 if (wp->w_buffer == buf) | |
7819 break; | |
7820 } | |
7821 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1); | |
7822 #else | |
7823 rettv->vval.v_number = (curwin->w_buffer == buf | |
7824 ? (get_nr ? 1 : curwin->w_id) : -1); | |
7825 #endif | |
7826 --emsg_off; | |
7827 } | |
7828 | |
7829 /* | |
7830 * "bufwinid(nr)" function | |
7831 */ | |
7832 static void | |
7833 f_bufwinid(typval_T *argvars, typval_T *rettv) | |
7834 { | |
7835 buf_win_common(argvars, rettv, FALSE); | |
7836 } | |
7837 | |
7838 /* | |
7839 * "bufwinnr(nr)" function | |
7840 */ | |
7841 static void | |
7842 f_bufwinnr(typval_T *argvars, typval_T *rettv) | |
7843 { | |
7844 buf_win_common(argvars, rettv, TRUE); | |
7845 } | |
7846 | |
7847 /* | |
7848 * "byte2line(byte)" function | |
7849 */ | |
7850 static void | |
7851 f_byte2line(typval_T *argvars UNUSED, typval_T *rettv) | |
7852 { | |
7853 #ifndef FEAT_BYTEOFF | |
7854 rettv->vval.v_number = -1; | |
7855 #else | |
7856 long boff = 0; | |
7857 | |
7858 boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */ | |
7859 if (boff < 0) | |
7860 rettv->vval.v_number = -1; | |
7861 else | |
7862 rettv->vval.v_number = ml_find_line_or_offset(curbuf, | |
7863 (linenr_T)0, &boff); | |
7864 #endif | |
7865 } | |
7866 | |
7867 static void | |
7868 byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED) | |
7869 { | |
7870 #ifdef FEAT_MBYTE | |
7871 char_u *t; | |
7872 #endif | |
7873 char_u *str; | |
7874 varnumber_T idx; | |
7875 | |
7876 str = get_tv_string_chk(&argvars[0]); | |
7877 idx = get_tv_number_chk(&argvars[1], NULL); | |
7878 rettv->vval.v_number = -1; | |
7879 if (str == NULL || idx < 0) | |
7880 return; | |
7881 | |
7882 #ifdef FEAT_MBYTE | |
7883 t = str; | |
7884 for ( ; idx > 0; idx--) | |
7885 { | |
7886 if (*t == NUL) /* EOL reached */ | |
7887 return; | |
7888 if (enc_utf8 && comp) | |
7889 t += utf_ptr2len(t); | |
7890 else | |
7891 t += (*mb_ptr2len)(t); | |
7892 } | |
7893 rettv->vval.v_number = (varnumber_T)(t - str); | |
7894 #else | |
7895 if ((size_t)idx <= STRLEN(str)) | |
7896 rettv->vval.v_number = idx; | |
7897 #endif | |
7898 } | |
7899 | |
7900 /* | |
7901 * "byteidx()" function | |
7902 */ | |
7903 static void | |
7904 f_byteidx(typval_T *argvars, typval_T *rettv) | |
7905 { | |
7906 byteidx(argvars, rettv, FALSE); | |
7907 } | |
7908 | |
7909 /* | |
7910 * "byteidxcomp()" function | |
7911 */ | |
7912 static void | |
7913 f_byteidxcomp(typval_T *argvars, typval_T *rettv) | |
7914 { | |
7915 byteidx(argvars, rettv, TRUE); | |
7916 } | |
7917 | |
7918 /* | |
7919 * "call(func, arglist [, dict])" function | |
7920 */ | |
7921 static void | |
7922 f_call(typval_T *argvars, typval_T *rettv) | |
7923 { | |
7924 char_u *func; | |
7925 partial_T *partial = NULL; | |
7926 dict_T *selfdict = NULL; | |
7927 | |
7928 if (argvars[1].v_type != VAR_LIST) | |
7929 { | |
7930 EMSG(_(e_listreq)); | |
7931 return; | |
7932 } | |
7933 if (argvars[1].vval.v_list == NULL) | |
7934 return; | |
7935 | |
7936 if (argvars[0].v_type == VAR_FUNC) | |
7937 func = argvars[0].vval.v_string; | |
7938 else if (argvars[0].v_type == VAR_PARTIAL) | |
7939 { | |
7940 partial = argvars[0].vval.v_partial; | |
7941 func = partial->pt_name; | |
7942 } | |
7943 else | |
7944 func = get_tv_string(&argvars[0]); | |
7945 if (*func == NUL) | |
7946 return; /* type error or empty name */ | |
7947 | |
7948 if (argvars[2].v_type != VAR_UNKNOWN) | |
7949 { | |
7950 if (argvars[2].v_type != VAR_DICT) | |
7951 { | |
7952 EMSG(_(e_dictreq)); | |
7953 return; | |
7954 } | |
7955 selfdict = argvars[2].vval.v_dict; | |
7956 } | |
7957 | |
7958 (void)func_call(func, &argvars[1], partial, selfdict, rettv); | |
7959 } | |
7960 | |
7961 #ifdef FEAT_FLOAT | |
7962 /* | |
7963 * "ceil({float})" function | |
7964 */ | |
7965 static void | |
7966 f_ceil(typval_T *argvars, typval_T *rettv) | |
7967 { | |
7968 float_T f = 0.0; | |
7969 | |
7970 rettv->v_type = VAR_FLOAT; | |
7971 if (get_float_arg(argvars, &f) == OK) | |
7972 rettv->vval.v_float = ceil(f); | |
7973 else | |
7974 rettv->vval.v_float = 0.0; | |
7975 } | |
7976 #endif | |
7977 | |
7978 #ifdef FEAT_JOB_CHANNEL | |
7979 /* | |
7980 * "ch_close()" function | |
7981 */ | |
7982 static void | |
7983 f_ch_close(typval_T *argvars, typval_T *rettv UNUSED) | |
7984 { | |
7985 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0); | |
7986 | |
7987 if (channel != NULL) | |
7988 { | |
7989 channel_close(channel, FALSE); | |
7990 channel_clear(channel); | |
7991 } | |
7992 } | |
7993 | |
7994 /* | |
7995 * "ch_getbufnr()" function | |
7996 */ | |
7997 static void | |
7998 f_ch_getbufnr(typval_T *argvars, typval_T *rettv) | |
7999 { | |
8000 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
8001 | |
8002 rettv->vval.v_number = -1; | |
8003 if (channel != NULL) | |
8004 { | |
8005 char_u *what = get_tv_string(&argvars[1]); | |
8006 int part; | |
8007 | |
8008 if (STRCMP(what, "err") == 0) | |
8009 part = PART_ERR; | |
8010 else if (STRCMP(what, "out") == 0) | |
8011 part = PART_OUT; | |
8012 else if (STRCMP(what, "in") == 0) | |
8013 part = PART_IN; | |
8014 else | |
8015 part = PART_SOCK; | |
8016 if (channel->ch_part[part].ch_bufref.br_buf != NULL) | |
8017 rettv->vval.v_number = | |
8018 channel->ch_part[part].ch_bufref.br_buf->b_fnum; | |
8019 } | |
8020 } | |
8021 | |
8022 /* | |
8023 * "ch_getjob()" function | |
8024 */ | |
8025 static void | |
8026 f_ch_getjob(typval_T *argvars, typval_T *rettv) | |
8027 { | |
8028 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
8029 | |
8030 if (channel != NULL) | |
8031 { | |
8032 rettv->v_type = VAR_JOB; | |
8033 rettv->vval.v_job = channel->ch_job; | |
8034 if (channel->ch_job != NULL) | |
8035 ++channel->ch_job->jv_refcount; | |
8036 } | |
8037 } | |
8038 | |
8039 /* | |
8040 * "ch_info()" function | |
8041 */ | |
8042 static void | |
8043 f_ch_info(typval_T *argvars, typval_T *rettv UNUSED) | |
8044 { | |
8045 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
8046 | |
8047 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL) | |
8048 channel_info(channel, rettv->vval.v_dict); | |
8049 } | |
8050 | |
8051 /* | |
8052 * "ch_log()" function | |
8053 */ | |
8054 static void | |
8055 f_ch_log(typval_T *argvars, typval_T *rettv UNUSED) | |
8056 { | |
8057 char_u *msg = get_tv_string(&argvars[0]); | |
8058 channel_T *channel = NULL; | |
8059 | |
8060 if (argvars[1].v_type != VAR_UNKNOWN) | |
8061 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0); | |
8062 | |
8063 ch_log(channel, (char *)msg); | |
8064 } | |
8065 | |
8066 /* | |
8067 * "ch_logfile()" function | |
8068 */ | |
8069 static void | |
8070 f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED) | |
8071 { | |
8072 char_u *fname; | |
8073 char_u *opt = (char_u *)""; | |
8074 char_u buf[NUMBUFLEN]; | |
8075 | |
8076 fname = get_tv_string(&argvars[0]); | |
8077 if (argvars[1].v_type == VAR_STRING) | |
8078 opt = get_tv_string_buf(&argvars[1], buf); | |
8079 ch_logfile(fname, opt); | |
8080 } | |
8081 | |
8082 /* | |
8083 * "ch_open()" function | |
8084 */ | |
8085 static void | |
8086 f_ch_open(typval_T *argvars, typval_T *rettv) | |
8087 { | |
8088 rettv->v_type = VAR_CHANNEL; | |
8089 if (check_restricted() || check_secure()) | |
8090 return; | |
8091 rettv->vval.v_channel = channel_open_func(argvars); | |
8092 } | |
8093 | |
8094 /* | |
8095 * "ch_read()" function | |
8096 */ | |
8097 static void | |
8098 f_ch_read(typval_T *argvars, typval_T *rettv) | |
8099 { | |
8100 common_channel_read(argvars, rettv, FALSE); | |
8101 } | |
8102 | |
8103 /* | |
8104 * "ch_readraw()" function | |
8105 */ | |
8106 static void | |
8107 f_ch_readraw(typval_T *argvars, typval_T *rettv) | |
8108 { | |
8109 common_channel_read(argvars, rettv, TRUE); | |
8110 } | |
8111 | |
8112 /* | |
8113 * "ch_evalexpr()" function | |
8114 */ | |
8115 static void | |
8116 f_ch_evalexpr(typval_T *argvars, typval_T *rettv) | |
8117 { | |
8118 ch_expr_common(argvars, rettv, TRUE); | |
8119 } | |
8120 | |
8121 /* | |
8122 * "ch_sendexpr()" function | |
8123 */ | |
8124 static void | |
8125 f_ch_sendexpr(typval_T *argvars, typval_T *rettv) | |
8126 { | |
8127 ch_expr_common(argvars, rettv, FALSE); | |
8128 } | |
8129 | |
8130 /* | |
8131 * "ch_evalraw()" function | |
8132 */ | |
8133 static void | |
8134 f_ch_evalraw(typval_T *argvars, typval_T *rettv) | |
8135 { | |
8136 ch_raw_common(argvars, rettv, TRUE); | |
8137 } | |
8138 | |
8139 /* | |
8140 * "ch_sendraw()" function | |
8141 */ | |
8142 static void | |
8143 f_ch_sendraw(typval_T *argvars, typval_T *rettv) | |
8144 { | |
8145 ch_raw_common(argvars, rettv, FALSE); | |
8146 } | |
8147 | |
8148 /* | |
8149 * "ch_setoptions()" function | |
8150 */ | |
8151 static void | |
8152 f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED) | |
8153 { | |
8154 channel_T *channel; | |
8155 jobopt_T opt; | |
8156 | |
8157 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
8158 if (channel == NULL) | |
8159 return; | |
8160 clear_job_options(&opt); | |
8161 if (get_job_options(&argvars[1], &opt, | |
8162 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL) == OK) | |
8163 channel_set_options(channel, &opt); | |
8164 free_job_options(&opt); | |
8165 } | |
8166 | |
8167 /* | |
8168 * "ch_status()" function | |
8169 */ | |
8170 static void | |
8171 f_ch_status(typval_T *argvars, typval_T *rettv) | |
8172 { | |
8173 channel_T *channel; | |
8174 | |
8175 /* return an empty string by default */ | |
8176 rettv->v_type = VAR_STRING; | |
8177 rettv->vval.v_string = NULL; | |
8178 | |
8179 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0); | |
8180 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel)); | |
8181 } | |
8182 #endif | |
8183 | |
8184 /* | |
8185 * "changenr()" function | |
8186 */ | |
8187 static void | |
8188 f_changenr(typval_T *argvars UNUSED, typval_T *rettv) | |
8189 { | |
8190 rettv->vval.v_number = curbuf->b_u_seq_cur; | |
8191 } | |
8192 | |
8193 /* | |
8194 * "char2nr(string)" function | |
8195 */ | |
8196 static void | |
8197 f_char2nr(typval_T *argvars, typval_T *rettv) | |
8198 { | |
8199 #ifdef FEAT_MBYTE | |
8200 if (has_mbyte) | |
8201 { | |
8202 int utf8 = 0; | |
8203 | |
8204 if (argvars[1].v_type != VAR_UNKNOWN) | |
8205 utf8 = (int)get_tv_number_chk(&argvars[1], NULL); | |
8206 | |
8207 if (utf8) | |
8208 rettv->vval.v_number = (*utf_ptr2char)(get_tv_string(&argvars[0])); | |
8209 else | |
8210 rettv->vval.v_number = (*mb_ptr2char)(get_tv_string(&argvars[0])); | |
8211 } | |
8212 else | |
8213 #endif | |
8214 rettv->vval.v_number = get_tv_string(&argvars[0])[0]; | |
8215 } | |
8216 | |
8217 /* | |
8218 * "cindent(lnum)" function | |
8219 */ | |
8220 static void | |
8221 f_cindent(typval_T *argvars UNUSED, typval_T *rettv) | |
8222 { | |
8223 #ifdef FEAT_CINDENT | |
8224 pos_T pos; | |
8225 linenr_T lnum; | |
8226 | |
8227 pos = curwin->w_cursor; | |
8228 lnum = get_tv_lnum(argvars); | |
8229 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
8230 { | |
8231 curwin->w_cursor.lnum = lnum; | |
8232 rettv->vval.v_number = get_c_indent(); | |
8233 curwin->w_cursor = pos; | |
8234 } | |
8235 else | |
8236 #endif | |
8237 rettv->vval.v_number = -1; | |
8238 } | |
8239 | |
8240 /* | |
8241 * "clearmatches()" function | |
8242 */ | |
8243 static void | |
8244 f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8245 { | |
8246 #ifdef FEAT_SEARCH_EXTRA | |
8247 clear_matches(curwin); | |
8248 #endif | |
8249 } | |
8250 | |
8251 /* | |
8252 * "col(string)" function | |
8253 */ | |
8254 static void | |
8255 f_col(typval_T *argvars, typval_T *rettv) | |
8256 { | |
8257 colnr_T col = 0; | |
8258 pos_T *fp; | |
8259 int fnum = curbuf->b_fnum; | |
8260 | |
8261 fp = var2fpos(&argvars[0], FALSE, &fnum); | |
8262 if (fp != NULL && fnum == curbuf->b_fnum) | |
8263 { | |
8264 if (fp->col == MAXCOL) | |
8265 { | |
8266 /* '> can be MAXCOL, get the length of the line then */ | |
8267 if (fp->lnum <= curbuf->b_ml.ml_line_count) | |
8268 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; | |
8269 else | |
8270 col = MAXCOL; | |
8271 } | |
8272 else | |
8273 { | |
8274 col = fp->col + 1; | |
8275 #ifdef FEAT_VIRTUALEDIT | |
8276 /* col(".") when the cursor is on the NUL at the end of the line | |
8277 * because of "coladd" can be seen as an extra column. */ | |
8278 if (virtual_active() && fp == &curwin->w_cursor) | |
8279 { | |
8280 char_u *p = ml_get_cursor(); | |
8281 | |
8282 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p, | |
8283 curwin->w_virtcol - curwin->w_cursor.coladd)) | |
8284 { | |
8285 # ifdef FEAT_MBYTE | |
8286 int l; | |
8287 | |
8288 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) | |
8289 col += l; | |
8290 # else | |
8291 if (*p != NUL && p[1] == NUL) | |
8292 ++col; | |
8293 # endif | |
8294 } | |
8295 } | |
8296 #endif | |
8297 } | |
8298 } | |
8299 rettv->vval.v_number = col; | |
8300 } | |
8301 | |
8302 #if defined(FEAT_INS_EXPAND) | |
8303 /* | |
8304 * "complete()" function | |
8305 */ | |
8306 static void | |
8307 f_complete(typval_T *argvars, typval_T *rettv UNUSED) | |
8308 { | |
8309 int startcol; | |
8310 | |
8311 if ((State & INSERT) == 0) | |
8312 { | |
8313 EMSG(_("E785: complete() can only be used in Insert mode")); | |
8314 return; | |
8315 } | |
8316 | |
8317 /* Check for undo allowed here, because if something was already inserted | |
8318 * the line was already saved for undo and this check isn't done. */ | |
8319 if (!undo_allowed()) | |
8320 return; | |
8321 | |
8322 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) | |
8323 { | |
8324 EMSG(_(e_invarg)); | |
8325 return; | |
8326 } | |
8327 | |
8328 startcol = (int)get_tv_number_chk(&argvars[0], NULL); | |
8329 if (startcol <= 0) | |
8330 return; | |
8331 | |
8332 set_completion(startcol - 1, argvars[1].vval.v_list); | |
8333 } | |
8334 | |
8335 /* | |
8336 * "complete_add()" function | |
8337 */ | |
8338 static void | |
8339 f_complete_add(typval_T *argvars, typval_T *rettv) | |
8340 { | |
8341 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); | |
8342 } | |
8343 | |
8344 /* | |
8345 * "complete_check()" function | |
8346 */ | |
8347 static void | |
8348 f_complete_check(typval_T *argvars UNUSED, typval_T *rettv) | |
8349 { | |
8350 int saved = RedrawingDisabled; | |
8351 | |
8352 RedrawingDisabled = 0; | |
8353 ins_compl_check_keys(0); | |
8354 rettv->vval.v_number = compl_interrupted; | |
8355 RedrawingDisabled = saved; | |
8356 } | |
8357 #endif | |
8358 | |
8359 /* | |
8360 * "confirm(message, buttons[, default [, type]])" function | |
8361 */ | |
8362 static void | |
8363 f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8364 { | |
8365 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) | |
8366 char_u *message; | |
8367 char_u *buttons = NULL; | |
8368 char_u buf[NUMBUFLEN]; | |
8369 char_u buf2[NUMBUFLEN]; | |
8370 int def = 1; | |
8371 int type = VIM_GENERIC; | |
8372 char_u *typestr; | |
8373 int error = FALSE; | |
8374 | |
8375 message = get_tv_string_chk(&argvars[0]); | |
8376 if (message == NULL) | |
8377 error = TRUE; | |
8378 if (argvars[1].v_type != VAR_UNKNOWN) | |
8379 { | |
8380 buttons = get_tv_string_buf_chk(&argvars[1], buf); | |
8381 if (buttons == NULL) | |
8382 error = TRUE; | |
8383 if (argvars[2].v_type != VAR_UNKNOWN) | |
8384 { | |
8385 def = (int)get_tv_number_chk(&argvars[2], &error); | |
8386 if (argvars[3].v_type != VAR_UNKNOWN) | |
8387 { | |
8388 typestr = get_tv_string_buf_chk(&argvars[3], buf2); | |
8389 if (typestr == NULL) | |
8390 error = TRUE; | |
8391 else | |
8392 { | |
8393 switch (TOUPPER_ASC(*typestr)) | |
8394 { | |
8395 case 'E': type = VIM_ERROR; break; | |
8396 case 'Q': type = VIM_QUESTION; break; | |
8397 case 'I': type = VIM_INFO; break; | |
8398 case 'W': type = VIM_WARNING; break; | |
8399 case 'G': type = VIM_GENERIC; break; | |
8400 } | |
8401 } | |
8402 } | |
8403 } | |
8404 } | |
8405 | |
8406 if (buttons == NULL || *buttons == NUL) | |
8407 buttons = (char_u *)_("&Ok"); | |
8408 | |
8409 if (!error) | |
8410 rettv->vval.v_number = do_dialog(type, NULL, message, buttons, | |
8411 def, NULL, FALSE); | |
8412 #endif | |
8413 } | |
8414 | |
8415 /* | |
8416 * "copy()" function | |
8417 */ | |
8418 static void | |
8419 f_copy(typval_T *argvars, typval_T *rettv) | |
8420 { | |
8421 item_copy(&argvars[0], rettv, FALSE, 0); | |
8422 } | |
8423 | |
8424 #ifdef FEAT_FLOAT | |
8425 /* | |
8426 * "cos()" function | |
8427 */ | |
8428 static void | |
8429 f_cos(typval_T *argvars, typval_T *rettv) | |
8430 { | |
8431 float_T f = 0.0; | |
8432 | |
8433 rettv->v_type = VAR_FLOAT; | |
8434 if (get_float_arg(argvars, &f) == OK) | |
8435 rettv->vval.v_float = cos(f); | |
8436 else | |
8437 rettv->vval.v_float = 0.0; | |
8438 } | |
8439 | |
8440 /* | |
8441 * "cosh()" function | |
8442 */ | |
8443 static void | |
8444 f_cosh(typval_T *argvars, typval_T *rettv) | |
8445 { | |
8446 float_T f = 0.0; | |
8447 | |
8448 rettv->v_type = VAR_FLOAT; | |
8449 if (get_float_arg(argvars, &f) == OK) | |
8450 rettv->vval.v_float = cosh(f); | |
8451 else | |
8452 rettv->vval.v_float = 0.0; | |
8453 } | |
8454 #endif | |
8455 | |
8456 /* | |
8457 * "count()" function | |
8458 */ | |
8459 static void | |
8460 f_count(typval_T *argvars, typval_T *rettv) | |
8461 { | |
8462 long n = 0; | |
8463 int ic = FALSE; | |
8464 | |
8465 if (argvars[0].v_type == VAR_LIST) | |
8466 { | |
8467 listitem_T *li; | |
8468 list_T *l; | |
8469 long idx; | |
8470 | |
8471 if ((l = argvars[0].vval.v_list) != NULL) | |
8472 { | |
8473 li = l->lv_first; | |
8474 if (argvars[2].v_type != VAR_UNKNOWN) | |
8475 { | |
8476 int error = FALSE; | |
8477 | |
8478 ic = (int)get_tv_number_chk(&argvars[2], &error); | |
8479 if (argvars[3].v_type != VAR_UNKNOWN) | |
8480 { | |
8481 idx = (long)get_tv_number_chk(&argvars[3], &error); | |
8482 if (!error) | |
8483 { | |
8484 li = list_find(l, idx); | |
8485 if (li == NULL) | |
8486 EMSGN(_(e_listidx), idx); | |
8487 } | |
8488 } | |
8489 if (error) | |
8490 li = NULL; | |
8491 } | |
8492 | |
8493 for ( ; li != NULL; li = li->li_next) | |
8494 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE)) | |
8495 ++n; | |
8496 } | |
8497 } | |
8498 else if (argvars[0].v_type == VAR_DICT) | |
8499 { | |
8500 int todo; | |
8501 dict_T *d; | |
8502 hashitem_T *hi; | |
8503 | |
8504 if ((d = argvars[0].vval.v_dict) != NULL) | |
8505 { | |
8506 int error = FALSE; | |
8507 | |
8508 if (argvars[2].v_type != VAR_UNKNOWN) | |
8509 { | |
8510 ic = (int)get_tv_number_chk(&argvars[2], &error); | |
8511 if (argvars[3].v_type != VAR_UNKNOWN) | |
8512 EMSG(_(e_invarg)); | |
8513 } | |
8514 | |
8515 todo = error ? 0 : (int)d->dv_hashtab.ht_used; | |
8516 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | |
8517 { | |
8518 if (!HASHITEM_EMPTY(hi)) | |
8519 { | |
8520 --todo; | |
8521 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE)) | |
8522 ++n; | |
8523 } | |
8524 } | |
8525 } | |
8526 } | |
8527 else | |
8528 EMSG2(_(e_listdictarg), "count()"); | |
8529 rettv->vval.v_number = n; | |
8530 } | |
8531 | |
8532 /* | |
8533 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function | |
8534 * | |
8535 * Checks the existence of a cscope connection. | |
8536 */ | |
8537 static void | |
8538 f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8539 { | |
8540 #ifdef FEAT_CSCOPE | |
8541 int num = 0; | |
8542 char_u *dbpath = NULL; | |
8543 char_u *prepend = NULL; | |
8544 char_u buf[NUMBUFLEN]; | |
8545 | |
8546 if (argvars[0].v_type != VAR_UNKNOWN | |
8547 && argvars[1].v_type != VAR_UNKNOWN) | |
8548 { | |
8549 num = (int)get_tv_number(&argvars[0]); | |
8550 dbpath = get_tv_string(&argvars[1]); | |
8551 if (argvars[2].v_type != VAR_UNKNOWN) | |
8552 prepend = get_tv_string_buf(&argvars[2], buf); | |
8553 } | |
8554 | |
8555 rettv->vval.v_number = cs_connection(num, dbpath, prepend); | |
8556 #endif | |
8557 } | |
8558 | |
8559 /* | |
8560 * "cursor(lnum, col)" function, or | |
8561 * "cursor(list)" | |
8562 * | |
8563 * Moves the cursor to the specified line and column. | |
8564 * Returns 0 when the position could be set, -1 otherwise. | |
8565 */ | |
8566 static void | |
8567 f_cursor(typval_T *argvars, typval_T *rettv) | |
8568 { | |
8569 long line, col; | |
8570 #ifdef FEAT_VIRTUALEDIT | |
8571 long coladd = 0; | |
8572 #endif | |
8573 int set_curswant = TRUE; | |
8574 | |
8575 rettv->vval.v_number = -1; | |
8576 if (argvars[1].v_type == VAR_UNKNOWN) | |
8577 { | |
8578 pos_T pos; | |
8579 colnr_T curswant = -1; | |
8580 | |
8581 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) | |
8582 { | |
8583 EMSG(_(e_invarg)); | |
8584 return; | |
8585 } | |
8586 line = pos.lnum; | |
8587 col = pos.col; | |
8588 #ifdef FEAT_VIRTUALEDIT | |
8589 coladd = pos.coladd; | |
8590 #endif | |
8591 if (curswant >= 0) | |
8592 { | |
8593 curwin->w_curswant = curswant - 1; | |
8594 set_curswant = FALSE; | |
8595 } | |
8596 } | |
8597 else | |
8598 { | |
8599 line = get_tv_lnum(argvars); | |
8600 col = (long)get_tv_number_chk(&argvars[1], NULL); | |
8601 #ifdef FEAT_VIRTUALEDIT | |
8602 if (argvars[2].v_type != VAR_UNKNOWN) | |
8603 coladd = (long)get_tv_number_chk(&argvars[2], NULL); | |
8604 #endif | |
8605 } | |
8606 if (line < 0 || col < 0 | |
8607 #ifdef FEAT_VIRTUALEDIT | |
8608 || coladd < 0 | |
8609 #endif | |
8610 ) | |
8611 return; /* type error; errmsg already given */ | |
8612 if (line > 0) | |
8613 curwin->w_cursor.lnum = line; | |
8614 if (col > 0) | |
8615 curwin->w_cursor.col = col - 1; | |
8616 #ifdef FEAT_VIRTUALEDIT | |
8617 curwin->w_cursor.coladd = coladd; | |
8618 #endif | |
8619 | |
8620 /* Make sure the cursor is in a valid position. */ | |
8621 check_cursor(); | |
8622 #ifdef FEAT_MBYTE | |
8623 /* Correct cursor for multi-byte character. */ | |
8624 if (has_mbyte) | |
8625 mb_adjust_cursor(); | |
8626 #endif | |
8627 | |
8628 curwin->w_set_curswant = set_curswant; | |
8629 rettv->vval.v_number = 0; | |
8630 } | |
8631 | |
8632 /* | |
8633 * "deepcopy()" function | |
8634 */ | |
8635 static void | |
8636 f_deepcopy(typval_T *argvars, typval_T *rettv) | |
8637 { | |
8638 int noref = 0; | |
8639 | |
8640 if (argvars[1].v_type != VAR_UNKNOWN) | |
8641 noref = (int)get_tv_number_chk(&argvars[1], NULL); | |
8642 if (noref < 0 || noref > 1) | |
8643 EMSG(_(e_invarg)); | |
8644 else | |
8645 { | |
8646 current_copyID += COPYID_INC; | |
8647 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? current_copyID : 0); | |
8648 } | |
8649 } | |
8650 | |
8651 /* | |
8652 * "delete()" function | |
8653 */ | |
8654 static void | |
8655 f_delete(typval_T *argvars, typval_T *rettv) | |
8656 { | |
8657 char_u nbuf[NUMBUFLEN]; | |
8658 char_u *name; | |
8659 char_u *flags; | |
8660 | |
8661 rettv->vval.v_number = -1; | |
8662 if (check_restricted() || check_secure()) | |
8663 return; | |
8664 | |
8665 name = get_tv_string(&argvars[0]); | |
8666 if (name == NULL || *name == NUL) | |
8667 { | |
8668 EMSG(_(e_invarg)); | |
8669 return; | |
8670 } | |
8671 | |
8672 if (argvars[1].v_type != VAR_UNKNOWN) | |
8673 flags = get_tv_string_buf(&argvars[1], nbuf); | |
8674 else | |
8675 flags = (char_u *)""; | |
8676 | |
8677 if (*flags == NUL) | |
8678 /* delete a file */ | |
8679 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1; | |
8680 else if (STRCMP(flags, "d") == 0) | |
8681 /* delete an empty directory */ | |
8682 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; | |
8683 else if (STRCMP(flags, "rf") == 0) | |
8684 /* delete a directory recursively */ | |
8685 rettv->vval.v_number = delete_recursive(name); | |
8686 else | |
8687 EMSG2(_(e_invexpr2), flags); | |
8688 } | |
8689 | |
8690 /* | |
8691 * "did_filetype()" function | |
8692 */ | |
8693 static void | |
8694 f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8695 { | |
8696 #ifdef FEAT_AUTOCMD | |
8697 rettv->vval.v_number = did_filetype; | |
8698 #endif | |
8699 } | |
8700 | |
8701 /* | |
8702 * "diff_filler()" function | |
8703 */ | |
8704 static void | |
8705 f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8706 { | |
8707 #ifdef FEAT_DIFF | |
8708 rettv->vval.v_number = diff_check_fill(curwin, get_tv_lnum(argvars)); | |
8709 #endif | |
8710 } | |
8711 | |
8712 /* | |
8713 * "diff_hlID()" function | |
8714 */ | |
8715 static void | |
8716 f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
8717 { | |
8718 #ifdef FEAT_DIFF | |
8719 linenr_T lnum = get_tv_lnum(argvars); | |
8720 static linenr_T prev_lnum = 0; | |
8721 static int changedtick = 0; | |
8722 static int fnum = 0; | |
8723 static int change_start = 0; | |
8724 static int change_end = 0; | |
8725 static hlf_T hlID = (hlf_T)0; | |
8726 int filler_lines; | |
8727 int col; | |
8728 | |
8729 if (lnum < 0) /* ignore type error in {lnum} arg */ | |
8730 lnum = 0; | |
8731 if (lnum != prev_lnum | |
8732 || changedtick != curbuf->b_changedtick | |
8733 || fnum != curbuf->b_fnum) | |
8734 { | |
8735 /* New line, buffer, change: need to get the values. */ | |
8736 filler_lines = diff_check(curwin, lnum); | |
8737 if (filler_lines < 0) | |
8738 { | |
8739 if (filler_lines == -1) | |
8740 { | |
8741 change_start = MAXCOL; | |
8742 change_end = -1; | |
8743 if (diff_find_change(curwin, lnum, &change_start, &change_end)) | |
8744 hlID = HLF_ADD; /* added line */ | |
8745 else | |
8746 hlID = HLF_CHD; /* changed line */ | |
8747 } | |
8748 else | |
8749 hlID = HLF_ADD; /* added line */ | |
8750 } | |
8751 else | |
8752 hlID = (hlf_T)0; | |
8753 prev_lnum = lnum; | |
8754 changedtick = curbuf->b_changedtick; | |
8755 fnum = curbuf->b_fnum; | |
8756 } | |
8757 | |
8758 if (hlID == HLF_CHD || hlID == HLF_TXD) | |
8759 { | |
8760 col = get_tv_number(&argvars[1]) - 1; /* ignore type error in {col} */ | |
8761 if (col >= change_start && col <= change_end) | |
8762 hlID = HLF_TXD; /* changed text */ | |
8763 else | |
8764 hlID = HLF_CHD; /* changed line */ | |
8765 } | |
8766 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID; | |
8767 #endif | |
8768 } | |
8769 | |
8770 /* | |
8771 * "empty({expr})" function | |
8772 */ | |
8773 static void | |
8774 f_empty(typval_T *argvars, typval_T *rettv) | |
8775 { | |
8776 int n = FALSE; | |
8777 | |
8778 switch (argvars[0].v_type) | |
8779 { | |
8780 case VAR_STRING: | |
8781 case VAR_FUNC: | |
8782 n = argvars[0].vval.v_string == NULL | |
8783 || *argvars[0].vval.v_string == NUL; | |
8784 break; | |
8785 case VAR_PARTIAL: | |
8786 n = FALSE; | |
8787 break; | |
8788 case VAR_NUMBER: | |
8789 n = argvars[0].vval.v_number == 0; | |
8790 break; | |
8791 case VAR_FLOAT: | |
8792 #ifdef FEAT_FLOAT | |
8793 n = argvars[0].vval.v_float == 0.0; | |
8794 break; | |
8795 #endif | |
8796 case VAR_LIST: | |
8797 n = argvars[0].vval.v_list == NULL | |
8798 || argvars[0].vval.v_list->lv_first == NULL; | |
8799 break; | |
8800 case VAR_DICT: | |
8801 n = argvars[0].vval.v_dict == NULL | |
8802 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0; | |
8803 break; | |
8804 case VAR_SPECIAL: | |
8805 n = argvars[0].vval.v_number != VVAL_TRUE; | |
8806 break; | |
8807 | |
8808 case VAR_JOB: | |
8809 #ifdef FEAT_JOB_CHANNEL | |
8810 n = argvars[0].vval.v_job == NULL | |
8811 || argvars[0].vval.v_job->jv_status != JOB_STARTED; | |
8812 break; | |
8813 #endif | |
8814 case VAR_CHANNEL: | |
8815 #ifdef FEAT_JOB_CHANNEL | |
8816 n = argvars[0].vval.v_channel == NULL | |
8817 || !channel_is_open(argvars[0].vval.v_channel); | |
8818 break; | |
8819 #endif | |
8820 case VAR_UNKNOWN: | |
8821 EMSG2(_(e_intern2), "f_empty(UNKNOWN)"); | |
8822 n = TRUE; | |
8823 break; | |
8824 } | |
8825 | |
8826 rettv->vval.v_number = n; | |
8827 } | |
8828 | |
8829 /* | |
8830 * "escape({string}, {chars})" function | |
8831 */ | |
8832 static void | |
8833 f_escape(typval_T *argvars, typval_T *rettv) | |
8834 { | |
8835 char_u buf[NUMBUFLEN]; | |
8836 | |
8837 rettv->vval.v_string = vim_strsave_escaped(get_tv_string(&argvars[0]), | |
8838 get_tv_string_buf(&argvars[1], buf)); | |
8839 rettv->v_type = VAR_STRING; | |
8840 } | |
8841 | |
8842 /* | |
8843 * "eval()" function | |
8844 */ | |
8845 static void | |
8846 f_eval(typval_T *argvars, typval_T *rettv) | |
8847 { | |
8848 char_u *s, *p; | |
8849 | |
8850 s = get_tv_string_chk(&argvars[0]); | |
8851 if (s != NULL) | |
8852 s = skipwhite(s); | |
8853 | |
8854 p = s; | |
8855 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) | |
8856 { | |
8857 if (p != NULL && !aborting()) | |
8858 EMSG2(_(e_invexpr2), p); | |
8859 need_clr_eos = FALSE; | |
8860 rettv->v_type = VAR_NUMBER; | |
8861 rettv->vval.v_number = 0; | |
8862 } | |
8863 else if (*s != NUL) | |
8864 EMSG(_(e_trailing)); | |
8865 } | |
8866 | |
8867 /* | |
8868 * "eventhandler()" function | |
8869 */ | |
8870 static void | |
8871 f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) | |
8872 { | |
8873 rettv->vval.v_number = vgetc_busy; | |
8874 } | |
8875 | |
8876 /* | |
8877 * "executable()" function | |
8878 */ | |
8879 static void | |
8880 f_executable(typval_T *argvars, typval_T *rettv) | |
8881 { | |
8882 char_u *name = get_tv_string(&argvars[0]); | |
8883 | |
8884 /* Check in $PATH and also check directly if there is a directory name. */ | |
8885 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE) | |
8886 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE)); | |
8887 } | |
8888 | |
8889 static garray_T redir_execute_ga; | |
8890 | |
8891 /* | |
8892 * Append "value[value_len]" to the execute() output. | |
8893 */ | |
8894 void | |
8895 execute_redir_str(char_u *value, int value_len) | |
8896 { | |
8897 int len; | |
8898 | |
8899 if (value_len == -1) | |
8900 len = (int)STRLEN(value); /* Append the entire string */ | |
8901 else | |
8902 len = value_len; /* Append only "value_len" characters */ | |
8903 if (ga_grow(&redir_execute_ga, len) == OK) | |
8904 { | |
8905 mch_memmove((char *)redir_execute_ga.ga_data | |
8906 + redir_execute_ga.ga_len, value, len); | |
8907 redir_execute_ga.ga_len += len; | |
8908 } | |
8909 } | |
8910 | |
8911 /* | |
8912 * Get next line from a list. | |
8913 * Called by do_cmdline() to get the next line. | |
8914 * Returns allocated string, or NULL for end of function. | |
8915 */ | |
8916 | |
8917 static char_u * | |
8918 get_list_line( | |
8919 int c UNUSED, | |
8920 void *cookie, | |
8921 int indent UNUSED) | |
8922 { | |
8923 listitem_T **p = (listitem_T **)cookie; | |
8924 listitem_T *item = *p; | |
8925 char_u buf[NUMBUFLEN]; | |
8926 char_u *s; | |
8927 | |
8928 if (item == NULL) | |
8929 return NULL; | |
8930 s = get_tv_string_buf_chk(&item->li_tv, buf); | |
8931 *p = item->li_next; | |
8932 return s == NULL ? NULL : vim_strsave(s); | |
8933 } | |
8934 | |
8935 /* | |
8936 * "execute()" function | |
8937 */ | |
8938 static void | |
8939 f_execute(typval_T *argvars, typval_T *rettv) | |
8940 { | |
8941 char_u *cmd = NULL; | |
8942 list_T *list = NULL; | |
8943 int save_msg_silent = msg_silent; | |
8944 int save_emsg_silent = emsg_silent; | |
8945 int save_emsg_noredir = emsg_noredir; | |
8946 int save_redir_execute = redir_execute; | |
8947 garray_T save_ga; | |
8948 | |
8949 rettv->vval.v_string = NULL; | |
8950 rettv->v_type = VAR_STRING; | |
8951 | |
8952 if (argvars[0].v_type == VAR_LIST) | |
8953 { | |
8954 list = argvars[0].vval.v_list; | |
8955 if (list == NULL || list->lv_first == NULL) | |
8956 /* empty list, no commands, empty output */ | |
8957 return; | |
8958 ++list->lv_refcount; | |
8959 } | |
8960 else | |
8961 { | |
8962 cmd = get_tv_string_chk(&argvars[0]); | |
8963 if (cmd == NULL) | |
8964 return; | |
8965 } | |
8966 | |
8967 if (argvars[1].v_type != VAR_UNKNOWN) | |
8968 { | |
8969 char_u buf[NUMBUFLEN]; | |
8970 char_u *s = get_tv_string_buf_chk(&argvars[1], buf); | |
8971 | |
8972 if (s == NULL) | |
8973 return; | |
8974 if (STRNCMP(s, "silent", 6) == 0) | |
8975 ++msg_silent; | |
8976 if (STRCMP(s, "silent!") == 0) | |
8977 { | |
8978 emsg_silent = TRUE; | |
8979 emsg_noredir = TRUE; | |
8980 } | |
8981 } | |
8982 else | |
8983 ++msg_silent; | |
8984 | |
8985 if (redir_execute) | |
8986 save_ga = redir_execute_ga; | |
8987 ga_init2(&redir_execute_ga, (int)sizeof(char), 500); | |
8988 redir_execute = TRUE; | |
8989 | |
8990 if (cmd != NULL) | |
8991 do_cmdline_cmd(cmd); | |
8992 else | |
8993 { | |
8994 listitem_T *item = list->lv_first; | |
8995 | |
8996 do_cmdline(NULL, get_list_line, (void *)&item, | |
8997 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); | |
8998 --list->lv_refcount; | |
8999 } | |
9000 | |
9001 rettv->vval.v_string = redir_execute_ga.ga_data; | |
9002 msg_silent = save_msg_silent; | |
9003 emsg_silent = save_emsg_silent; | |
9004 emsg_noredir = save_emsg_noredir; | |
9005 | |
9006 redir_execute = save_redir_execute; | |
9007 if (redir_execute) | |
9008 redir_execute_ga = save_ga; | |
9009 | |
9010 /* "silent reg" or "silent echo x" leaves msg_col somewhere in the | |
9011 * line. Put it back in the first column. */ | |
9012 msg_col = 0; | |
9013 } | |
9014 | |
9015 /* | |
9016 * "exepath()" function | |
9017 */ | |
9018 static void | |
9019 f_exepath(typval_T *argvars, typval_T *rettv) | |
9020 { | |
9021 char_u *p = NULL; | |
9022 | |
9023 (void)mch_can_exe(get_tv_string(&argvars[0]), &p, TRUE); | |
9024 rettv->v_type = VAR_STRING; | |
9025 rettv->vval.v_string = p; | |
9026 } | |
9027 | |
9028 /* | |
9029 * "exists()" function | |
9030 */ | |
9031 static void | |
9032 f_exists(typval_T *argvars, typval_T *rettv) | |
9033 { | |
9034 char_u *p; | |
9035 char_u *name; | |
9036 int n = FALSE; | |
9037 int len = 0; | |
9038 | |
9039 p = get_tv_string(&argvars[0]); | |
9040 if (*p == '$') /* environment variable */ | |
9041 { | |
9042 /* first try "normal" environment variables (fast) */ | |
9043 if (mch_getenv(p + 1) != NULL) | |
9044 n = TRUE; | |
9045 else | |
9046 { | |
9047 /* try expanding things like $VIM and ${HOME} */ | |
9048 p = expand_env_save(p); | |
9049 if (p != NULL && *p != '$') | |
9050 n = TRUE; | |
9051 vim_free(p); | |
9052 } | |
9053 } | |
9054 else if (*p == '&' || *p == '+') /* option */ | |
9055 { | |
9056 n = (get_option_tv(&p, NULL, TRUE) == OK); | |
9057 if (*skipwhite(p) != NUL) | |
9058 n = FALSE; /* trailing garbage */ | |
9059 } | |
9060 else if (*p == '*') /* internal or user defined function */ | |
9061 { | |
9062 n = function_exists(p + 1); | |
9063 } | |
9064 else if (*p == ':') | |
9065 { | |
9066 n = cmd_exists(p + 1); | |
9067 } | |
9068 else if (*p == '#') | |
9069 { | |
9070 #ifdef FEAT_AUTOCMD | |
9071 if (p[1] == '#') | |
9072 n = autocmd_supported(p + 2); | |
9073 else | |
9074 n = au_exists(p + 1); | |
9075 #endif | |
9076 } | |
9077 else /* internal variable */ | |
9078 { | |
9079 char_u *tofree; | |
9080 typval_T tv; | |
9081 | |
9082 /* get_name_len() takes care of expanding curly braces */ | |
9083 name = p; | |
9084 len = get_name_len(&p, &tofree, TRUE, FALSE); | |
9085 if (len > 0) | |
9086 { | |
9087 if (tofree != NULL) | |
9088 name = tofree; | |
9089 n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK); | |
9090 if (n) | |
9091 { | |
9092 /* handle d.key, l[idx], f(expr) */ | |
9093 n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK); | |
9094 if (n) | |
9095 clear_tv(&tv); | |
9096 } | |
9097 } | |
9098 if (*p != NUL) | |
9099 n = FALSE; | |
9100 | |
9101 vim_free(tofree); | |
9102 } | |
9103 | |
9104 rettv->vval.v_number = n; | |
9105 } | |
9106 | |
9107 #ifdef FEAT_FLOAT | |
9108 /* | |
9109 * "exp()" function | |
9110 */ | |
9111 static void | |
9112 f_exp(typval_T *argvars, typval_T *rettv) | |
9113 { | |
9114 float_T f = 0.0; | |
9115 | |
9116 rettv->v_type = VAR_FLOAT; | |
9117 if (get_float_arg(argvars, &f) == OK) | |
9118 rettv->vval.v_float = exp(f); | |
9119 else | |
9120 rettv->vval.v_float = 0.0; | |
9121 } | |
9122 #endif | |
9123 | |
9124 /* | |
9125 * "expand()" function | |
9126 */ | |
9127 static void | |
9128 f_expand(typval_T *argvars, typval_T *rettv) | |
9129 { | |
9130 char_u *s; | |
9131 int len; | |
9132 char_u *errormsg; | |
9133 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND; | |
9134 expand_T xpc; | |
9135 int error = FALSE; | |
9136 char_u *result; | |
9137 | |
9138 rettv->v_type = VAR_STRING; | |
9139 if (argvars[1].v_type != VAR_UNKNOWN | |
9140 && argvars[2].v_type != VAR_UNKNOWN | |
9141 && get_tv_number_chk(&argvars[2], &error) | |
9142 && !error) | |
9143 { | |
9144 rettv->v_type = VAR_LIST; | |
9145 rettv->vval.v_list = NULL; | |
9146 } | |
9147 | |
9148 s = get_tv_string(&argvars[0]); | |
9149 if (*s == '%' || *s == '#' || *s == '<') | |
9150 { | |
9151 ++emsg_off; | |
9152 result = eval_vars(s, s, &len, NULL, &errormsg, NULL); | |
9153 --emsg_off; | |
9154 if (rettv->v_type == VAR_LIST) | |
9155 { | |
9156 if (rettv_list_alloc(rettv) != FAIL && result != NULL) | |
9157 list_append_string(rettv->vval.v_list, result, -1); | |
9158 else | |
9159 vim_free(result); | |
9160 } | |
9161 else | |
9162 rettv->vval.v_string = result; | |
9163 } | |
9164 else | |
9165 { | |
9166 /* When the optional second argument is non-zero, don't remove matches | |
9167 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ | |
9168 if (argvars[1].v_type != VAR_UNKNOWN | |
9169 && get_tv_number_chk(&argvars[1], &error)) | |
9170 options |= WILD_KEEP_ALL; | |
9171 if (!error) | |
9172 { | |
9173 ExpandInit(&xpc); | |
9174 xpc.xp_context = EXPAND_FILES; | |
9175 if (p_wic) | |
9176 options += WILD_ICASE; | |
9177 if (rettv->v_type == VAR_STRING) | |
9178 rettv->vval.v_string = ExpandOne(&xpc, s, NULL, | |
9179 options, WILD_ALL); | |
9180 else if (rettv_list_alloc(rettv) != FAIL) | |
9181 { | |
9182 int i; | |
9183 | |
9184 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP); | |
9185 for (i = 0; i < xpc.xp_numfiles; i++) | |
9186 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); | |
9187 ExpandCleanup(&xpc); | |
9188 } | |
9189 } | |
9190 else | |
9191 rettv->vval.v_string = NULL; | |
9192 } | |
9193 } | |
9194 | |
9195 /* | |
9196 * "extend(list, list [, idx])" function | |
9197 * "extend(dict, dict [, action])" function | |
9198 */ | |
9199 static void | |
9200 f_extend(typval_T *argvars, typval_T *rettv) | |
9201 { | |
9202 char_u *arg_errmsg = (char_u *)N_("extend() argument"); | |
9203 | |
9204 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) | |
9205 { | |
9206 list_T *l1, *l2; | |
9207 listitem_T *item; | |
9208 long before; | |
9209 int error = FALSE; | |
9210 | |
9211 l1 = argvars[0].vval.v_list; | |
9212 l2 = argvars[1].vval.v_list; | |
9213 if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, TRUE) | |
9214 && l2 != NULL) | |
9215 { | |
9216 if (argvars[2].v_type != VAR_UNKNOWN) | |
9217 { | |
9218 before = (long)get_tv_number_chk(&argvars[2], &error); | |
9219 if (error) | |
9220 return; /* type error; errmsg already given */ | |
9221 | |
9222 if (before == l1->lv_len) | |
9223 item = NULL; | |
9224 else | |
9225 { | |
9226 item = list_find(l1, before); | |
9227 if (item == NULL) | |
9228 { | |
9229 EMSGN(_(e_listidx), before); | |
9230 return; | |
9231 } | |
9232 } | |
9233 } | |
9234 else | |
9235 item = NULL; | |
9236 list_extend(l1, l2, item); | |
9237 | |
9238 copy_tv(&argvars[0], rettv); | |
9239 } | |
9240 } | |
9241 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) | |
9242 { | |
9243 dict_T *d1, *d2; | |
9244 char_u *action; | |
9245 int i; | |
9246 | |
9247 d1 = argvars[0].vval.v_dict; | |
9248 d2 = argvars[1].vval.v_dict; | |
9249 if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE) | |
9250 && d2 != NULL) | |
9251 { | |
9252 /* Check the third argument. */ | |
9253 if (argvars[2].v_type != VAR_UNKNOWN) | |
9254 { | |
9255 static char *(av[]) = {"keep", "force", "error"}; | |
9256 | |
9257 action = get_tv_string_chk(&argvars[2]); | |
9258 if (action == NULL) | |
9259 return; /* type error; errmsg already given */ | |
9260 for (i = 0; i < 3; ++i) | |
9261 if (STRCMP(action, av[i]) == 0) | |
9262 break; | |
9263 if (i == 3) | |
9264 { | |
9265 EMSG2(_(e_invarg2), action); | |
9266 return; | |
9267 } | |
9268 } | |
9269 else | |
9270 action = (char_u *)"force"; | |
9271 | |
9272 dict_extend(d1, d2, action); | |
9273 | |
9274 copy_tv(&argvars[0], rettv); | |
9275 } | |
9276 } | |
9277 else | |
9278 EMSG2(_(e_listdictarg), "extend()"); | |
9279 } | |
9280 | |
9281 /* | |
9282 * "feedkeys()" function | |
9283 */ | |
9284 static void | |
9285 f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) | |
9286 { | |
9287 int remap = TRUE; | |
9288 int insert = FALSE; | |
9289 char_u *keys, *flags; | |
9290 char_u nbuf[NUMBUFLEN]; | |
9291 int typed = FALSE; | |
9292 int execute = FALSE; | |
9293 int dangerous = FALSE; | |
9294 char_u *keys_esc; | |
9295 | |
9296 /* This is not allowed in the sandbox. If the commands would still be | |
9297 * executed in the sandbox it would be OK, but it probably happens later, | |
9298 * when "sandbox" is no longer set. */ | |
9299 if (check_secure()) | |
9300 return; | |
9301 | |
9302 keys = get_tv_string(&argvars[0]); | |
9303 | |
9304 if (argvars[1].v_type != VAR_UNKNOWN) | |
9305 { | |
9306 flags = get_tv_string_buf(&argvars[1], nbuf); | |
9307 for ( ; *flags != NUL; ++flags) | |
9308 { | |
9309 switch (*flags) | |
9310 { | |
9311 case 'n': remap = FALSE; break; | |
9312 case 'm': remap = TRUE; break; | |
9313 case 't': typed = TRUE; break; | |
9314 case 'i': insert = TRUE; break; | |
9315 case 'x': execute = TRUE; break; | |
9316 case '!': dangerous = TRUE; break; | |
9317 } | |
9318 } | |
9319 } | |
9320 | |
9321 if (*keys != NUL || execute) | |
9322 { | |
9323 /* Need to escape K_SPECIAL and CSI before putting the string in the | |
9324 * typeahead buffer. */ | |
9325 keys_esc = vim_strsave_escape_csi(keys); | |
9326 if (keys_esc != NULL) | |
9327 { | |
9328 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), | |
9329 insert ? 0 : typebuf.tb_len, !typed, FALSE); | |
9330 vim_free(keys_esc); | |
9331 if (vgetc_busy) | |
9332 typebuf_was_filled = TRUE; | |
9333 if (execute) | |
9334 { | |
9335 int save_msg_scroll = msg_scroll; | |
9336 | |
9337 /* Avoid a 1 second delay when the keys start Insert mode. */ | |
9338 msg_scroll = FALSE; | |
9339 | |
9340 if (!dangerous) | |
9341 ++ex_normal_busy; | |
9342 exec_normal(TRUE); | |
9343 if (!dangerous) | |
9344 --ex_normal_busy; | |
9345 msg_scroll |= save_msg_scroll; | |
9346 } | |
9347 } | |
9348 } | |
9349 } | |
9350 | |
9351 /* | |
9352 * "filereadable()" function | |
9353 */ | |
9354 static void | |
9355 f_filereadable(typval_T *argvars, typval_T *rettv) | |
9356 { | |
9357 int fd; | |
9358 char_u *p; | |
9359 int n; | |
9360 | |
9361 #ifndef O_NONBLOCK | |
9362 # define O_NONBLOCK 0 | |
9363 #endif | |
9364 p = get_tv_string(&argvars[0]); | |
9365 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p, | |
9366 O_RDONLY | O_NONBLOCK, 0)) >= 0) | |
9367 { | |
9368 n = TRUE; | |
9369 close(fd); | |
9370 } | |
9371 else | |
9372 n = FALSE; | |
9373 | |
9374 rettv->vval.v_number = n; | |
9375 } | |
9376 | |
9377 /* | |
9378 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have | |
9379 * rights to write into. | |
9380 */ | |
9381 static void | |
9382 f_filewritable(typval_T *argvars, typval_T *rettv) | |
9383 { | |
9384 rettv->vval.v_number = filewritable(get_tv_string(&argvars[0])); | |
9385 } | |
9386 | |
9387 static void | |
9388 findfilendir( | |
9389 typval_T *argvars UNUSED, | |
9390 typval_T *rettv, | |
9391 int find_what UNUSED) | |
9392 { | |
9393 #ifdef FEAT_SEARCHPATH | |
9394 char_u *fname; | |
9395 char_u *fresult = NULL; | |
9396 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; | |
9397 char_u *p; | |
9398 char_u pathbuf[NUMBUFLEN]; | |
9399 int count = 1; | |
9400 int first = TRUE; | |
9401 int error = FALSE; | |
9402 #endif | |
9403 | |
9404 rettv->vval.v_string = NULL; | |
9405 rettv->v_type = VAR_STRING; | |
9406 | |
9407 #ifdef FEAT_SEARCHPATH | |
9408 fname = get_tv_string(&argvars[0]); | |
9409 | |
9410 if (argvars[1].v_type != VAR_UNKNOWN) | |
9411 { | |
9412 p = get_tv_string_buf_chk(&argvars[1], pathbuf); | |
9413 if (p == NULL) | |
9414 error = TRUE; | |
9415 else | |
9416 { | |
9417 if (*p != NUL) | |
9418 path = p; | |
9419 | |
9420 if (argvars[2].v_type != VAR_UNKNOWN) | |
9421 count = (int)get_tv_number_chk(&argvars[2], &error); | |
9422 } | |
9423 } | |
9424 | |
9425 if (count < 0 && rettv_list_alloc(rettv) == FAIL) | |
9426 error = TRUE; | |
9427 | |
9428 if (*fname != NUL && !error) | |
9429 { | |
9430 do | |
9431 { | |
9432 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) | |
9433 vim_free(fresult); | |
9434 fresult = find_file_in_path_option(first ? fname : NULL, | |
9435 first ? (int)STRLEN(fname) : 0, | |
9436 0, first, path, | |
9437 find_what, | |
9438 curbuf->b_ffname, | |
9439 find_what == FINDFILE_DIR | |
9440 ? (char_u *)"" : curbuf->b_p_sua); | |
9441 first = FALSE; | |
9442 | |
9443 if (fresult != NULL && rettv->v_type == VAR_LIST) | |
9444 list_append_string(rettv->vval.v_list, fresult, -1); | |
9445 | |
9446 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL); | |
9447 } | |
9448 | |
9449 if (rettv->v_type == VAR_STRING) | |
9450 rettv->vval.v_string = fresult; | |
9451 #endif | |
9452 } | |
9453 | |
9454 static void filter_map(typval_T *argvars, typval_T *rettv, int map); | |
9455 static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp); | |
9456 | |
9457 /* | |
9458 * Implementation of map() and filter(). | |
9459 */ | |
9460 static void | |
9461 filter_map(typval_T *argvars, typval_T *rettv, int map) | |
9462 { | |
9463 typval_T *expr; | |
9464 listitem_T *li, *nli; | |
9465 list_T *l = NULL; | |
9466 dictitem_T *di; | |
9467 hashtab_T *ht; | |
9468 hashitem_T *hi; | |
9469 dict_T *d = NULL; | |
9470 typval_T save_val; | |
9471 typval_T save_key; | |
9472 int rem; | |
9473 int todo; | |
9474 char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); | |
9475 char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") | |
9476 : N_("filter() argument")); | |
9477 int save_did_emsg; | |
9478 int idx = 0; | |
9479 | |
9480 if (argvars[0].v_type == VAR_LIST) | |
9481 { | |
9482 if ((l = argvars[0].vval.v_list) == NULL | |
9483 || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE))) | |
9484 return; | |
9485 } | |
9486 else if (argvars[0].v_type == VAR_DICT) | |
9487 { | |
9488 if ((d = argvars[0].vval.v_dict) == NULL | |
9489 || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE))) | |
9490 return; | |
9491 } | |
9492 else | |
9493 { | |
9494 EMSG2(_(e_listdictarg), ermsg); | |
9495 return; | |
9496 } | |
9497 | |
9498 expr = &argvars[1]; | |
9499 /* On type errors, the preceding call has already displayed an error | |
9500 * message. Avoid a misleading error message for an empty string that | |
9501 * was not passed as argument. */ | |
9502 if (expr->v_type != VAR_UNKNOWN) | |
9503 { | |
9504 prepare_vimvar(VV_VAL, &save_val); | |
9505 | |
9506 /* We reset "did_emsg" to be able to detect whether an error | |
9507 * occurred during evaluation of the expression. */ | |
9508 save_did_emsg = did_emsg; | |
9509 did_emsg = FALSE; | |
9510 | |
9511 prepare_vimvar(VV_KEY, &save_key); | |
9512 if (argvars[0].v_type == VAR_DICT) | |
9513 { | |
9514 vimvars[VV_KEY].vv_type = VAR_STRING; | |
9515 | |
9516 ht = &d->dv_hashtab; | |
9517 hash_lock(ht); | |
9518 todo = (int)ht->ht_used; | |
9519 for (hi = ht->ht_array; todo > 0; ++hi) | |
9520 { | |
9521 if (!HASHITEM_EMPTY(hi)) | |
9522 { | |
9523 int r; | |
9524 | |
9525 --todo; | |
9526 di = HI2DI(hi); | |
9527 if (map && | |
9528 (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE) | |
9529 || var_check_ro(di->di_flags, arg_errmsg, TRUE))) | |
9530 break; | |
9531 vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); | |
9532 r = filter_map_one(&di->di_tv, expr, map, &rem); | |
9533 clear_tv(&vimvars[VV_KEY].vv_tv); | |
9534 if (r == FAIL || did_emsg) | |
9535 break; | |
9536 if (!map && rem) | |
9537 { | |
9538 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) | |
9539 || var_check_ro(di->di_flags, arg_errmsg, TRUE)) | |
9540 break; | |
9541 dictitem_remove(d, di); | |
9542 } | |
9543 } | |
9544 } | |
9545 hash_unlock(ht); | |
9546 } | |
9547 else | |
9548 { | |
9549 vimvars[VV_KEY].vv_type = VAR_NUMBER; | |
9550 | |
9551 for (li = l->lv_first; li != NULL; li = nli) | |
9552 { | |
9553 if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) | |
9554 break; | |
9555 nli = li->li_next; | |
9556 vimvars[VV_KEY].vv_nr = idx; | |
9557 if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL | |
9558 || did_emsg) | |
9559 break; | |
9560 if (!map && rem) | |
9561 listitem_remove(l, li); | |
9562 ++idx; | |
9563 } | |
9564 } | |
9565 | |
9566 restore_vimvar(VV_KEY, &save_key); | |
9567 restore_vimvar(VV_VAL, &save_val); | |
9568 | |
9569 did_emsg |= save_did_emsg; | |
9570 } | |
9571 | |
9572 copy_tv(&argvars[0], rettv); | |
9573 } | |
9574 | |
9575 static int | |
9576 filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) | |
9577 { | |
9578 typval_T rettv; | |
9579 typval_T argv[3]; | |
9580 char_u buf[NUMBUFLEN]; | |
9581 char_u *s; | |
9582 int retval = FAIL; | |
9583 int dummy; | |
9584 | |
9585 copy_tv(tv, &vimvars[VV_VAL].vv_tv); | |
9586 argv[0] = vimvars[VV_KEY].vv_tv; | |
9587 argv[1] = vimvars[VV_VAL].vv_tv; | |
9588 if (expr->v_type == VAR_FUNC) | |
9589 { | |
9590 s = expr->vval.v_string; | |
9591 if (call_func(s, (int)STRLEN(s), | |
9592 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL) | |
9593 goto theend; | |
9594 } | |
9595 else if (expr->v_type == VAR_PARTIAL) | |
9596 { | |
9597 partial_T *partial = expr->vval.v_partial; | |
9598 | |
9599 s = partial->pt_name; | |
9600 if (call_func(s, (int)STRLEN(s), | |
9601 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL) | |
9602 == FAIL) | |
9603 goto theend; | |
9604 } | |
9605 else | |
9606 { | |
9607 s = get_tv_string_buf_chk(expr, buf); | |
9608 if (s == NULL) | |
9609 goto theend; | |
9610 s = skipwhite(s); | |
9611 if (eval1(&s, &rettv, TRUE) == FAIL) | |
9612 goto theend; | |
9613 if (*s != NUL) /* check for trailing chars after expr */ | |
9614 { | |
9615 EMSG2(_(e_invexpr2), s); | |
9616 goto theend; | |
9617 } | |
9618 } | |
9619 if (map) | |
9620 { | |
9621 /* map(): replace the list item value */ | |
9622 clear_tv(tv); | |
9623 rettv.v_lock = 0; | |
9624 *tv = rettv; | |
9625 } | |
9626 else | |
9627 { | |
9628 int error = FALSE; | |
9629 | |
9630 /* filter(): when expr is zero remove the item */ | |
9631 *remp = (get_tv_number_chk(&rettv, &error) == 0); | |
9632 clear_tv(&rettv); | |
9633 /* On type error, nothing has been removed; return FAIL to stop the | |
9634 * loop. The error message was given by get_tv_number_chk(). */ | |
9635 if (error) | |
9636 goto theend; | |
9637 } | |
9638 retval = OK; | |
9639 theend: | |
9640 clear_tv(&vimvars[VV_VAL].vv_tv); | |
9641 return retval; | |
9642 } | |
9643 | |
9644 /* | |
9645 * "filter()" function | |
9646 */ | |
9647 static void | |
9648 f_filter(typval_T *argvars, typval_T *rettv) | |
9649 { | |
9650 filter_map(argvars, rettv, FALSE); | |
9651 } | |
9652 | |
9653 /* | |
9654 * "finddir({fname}[, {path}[, {count}]])" function | |
9655 */ | |
9656 static void | |
9657 f_finddir(typval_T *argvars, typval_T *rettv) | |
9658 { | |
9659 findfilendir(argvars, rettv, FINDFILE_DIR); | |
9660 } | |
9661 | |
9662 /* | |
9663 * "findfile({fname}[, {path}[, {count}]])" function | |
9664 */ | |
9665 static void | |
9666 f_findfile(typval_T *argvars, typval_T *rettv) | |
9667 { | |
9668 findfilendir(argvars, rettv, FINDFILE_FILE); | |
9669 } | |
9670 | |
9671 #ifdef FEAT_FLOAT | |
9672 /* | |
9673 * "float2nr({float})" function | |
9674 */ | |
9675 static void | |
9676 f_float2nr(typval_T *argvars, typval_T *rettv) | |
9677 { | |
9678 float_T f = 0.0; | |
9679 | |
9680 if (get_float_arg(argvars, &f) == OK) | |
9681 { | |
9682 # ifdef FEAT_NUM64 | |
9683 if (f < -0x7fffffffffffffff) | |
9684 rettv->vval.v_number = -0x7fffffffffffffff; | |
9685 else if (f > 0x7fffffffffffffff) | |
9686 rettv->vval.v_number = 0x7fffffffffffffff; | |
9687 else | |
9688 rettv->vval.v_number = (varnumber_T)f; | |
9689 # else | |
9690 if (f < -0x7fffffff) | |
9691 rettv->vval.v_number = -0x7fffffff; | |
9692 else if (f > 0x7fffffff) | |
9693 rettv->vval.v_number = 0x7fffffff; | |
9694 else | |
9695 rettv->vval.v_number = (varnumber_T)f; | |
9696 # endif | |
9697 } | |
9698 } | |
9699 | |
9700 /* | |
9701 * "floor({float})" function | |
9702 */ | |
9703 static void | |
9704 f_floor(typval_T *argvars, typval_T *rettv) | |
9705 { | |
9706 float_T f = 0.0; | |
9707 | |
9708 rettv->v_type = VAR_FLOAT; | |
9709 if (get_float_arg(argvars, &f) == OK) | |
9710 rettv->vval.v_float = floor(f); | |
9711 else | |
9712 rettv->vval.v_float = 0.0; | |
9713 } | |
9714 | |
9715 /* | |
9716 * "fmod()" function | |
9717 */ | |
9718 static void | |
9719 f_fmod(typval_T *argvars, typval_T *rettv) | |
9720 { | |
9721 float_T fx = 0.0, fy = 0.0; | |
9722 | |
9723 rettv->v_type = VAR_FLOAT; | |
9724 if (get_float_arg(argvars, &fx) == OK | |
9725 && get_float_arg(&argvars[1], &fy) == OK) | |
9726 rettv->vval.v_float = fmod(fx, fy); | |
9727 else | |
9728 rettv->vval.v_float = 0.0; | |
9729 } | |
9730 #endif | |
9731 | |
9732 /* | |
9733 * "fnameescape({string})" function | |
9734 */ | |
9735 static void | |
9736 f_fnameescape(typval_T *argvars, typval_T *rettv) | |
9737 { | |
9738 rettv->vval.v_string = vim_strsave_fnameescape( | |
9739 get_tv_string(&argvars[0]), FALSE); | |
9740 rettv->v_type = VAR_STRING; | |
9741 } | |
9742 | |
9743 /* | |
9744 * "fnamemodify({fname}, {mods})" function | |
9745 */ | |
9746 static void | |
9747 f_fnamemodify(typval_T *argvars, typval_T *rettv) | |
9748 { | |
9749 char_u *fname; | |
9750 char_u *mods; | |
9751 int usedlen = 0; | |
9752 int len; | |
9753 char_u *fbuf = NULL; | |
9754 char_u buf[NUMBUFLEN]; | |
9755 | |
9756 fname = get_tv_string_chk(&argvars[0]); | |
9757 mods = get_tv_string_buf_chk(&argvars[1], buf); | |
9758 if (fname == NULL || mods == NULL) | |
9759 fname = NULL; | |
9760 else | |
9761 { | |
9762 len = (int)STRLEN(fname); | |
9763 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len); | |
9764 } | |
9765 | |
9766 rettv->v_type = VAR_STRING; | |
9767 if (fname == NULL) | |
9768 rettv->vval.v_string = NULL; | |
9769 else | |
9770 rettv->vval.v_string = vim_strnsave(fname, len); | |
9771 vim_free(fbuf); | |
9772 } | |
9773 | |
9774 static void foldclosed_both(typval_T *argvars, typval_T *rettv, int end); | |
9775 | |
9776 /* | |
9777 * "foldclosed()" function | |
9778 */ | |
9779 static void | |
9780 foldclosed_both( | |
9781 typval_T *argvars UNUSED, | |
9782 typval_T *rettv, | |
9783 int end UNUSED) | |
9784 { | |
9785 #ifdef FEAT_FOLDING | |
9786 linenr_T lnum; | |
9787 linenr_T first, last; | |
9788 | |
9789 lnum = get_tv_lnum(argvars); | |
9790 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
9791 { | |
9792 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL)) | |
9793 { | |
9794 if (end) | |
9795 rettv->vval.v_number = (varnumber_T)last; | |
9796 else | |
9797 rettv->vval.v_number = (varnumber_T)first; | |
9798 return; | |
9799 } | |
9800 } | |
9801 #endif | |
9802 rettv->vval.v_number = -1; | |
9803 } | |
9804 | |
9805 /* | |
9806 * "foldclosed()" function | |
9807 */ | |
9808 static void | |
9809 f_foldclosed(typval_T *argvars, typval_T *rettv) | |
9810 { | |
9811 foldclosed_both(argvars, rettv, FALSE); | |
9812 } | |
9813 | |
9814 /* | |
9815 * "foldclosedend()" function | |
9816 */ | |
9817 static void | |
9818 f_foldclosedend(typval_T *argvars, typval_T *rettv) | |
9819 { | |
9820 foldclosed_both(argvars, rettv, TRUE); | |
9821 } | |
9822 | |
9823 /* | |
9824 * "foldlevel()" function | |
9825 */ | |
9826 static void | |
9827 f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
9828 { | |
9829 #ifdef FEAT_FOLDING | |
9830 linenr_T lnum; | |
9831 | |
9832 lnum = get_tv_lnum(argvars); | |
9833 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
9834 rettv->vval.v_number = foldLevel(lnum); | |
9835 #endif | |
9836 } | |
9837 | |
9838 /* | |
9839 * "foldtext()" function | |
9840 */ | |
9841 static void | |
9842 f_foldtext(typval_T *argvars UNUSED, typval_T *rettv) | |
9843 { | |
9844 #ifdef FEAT_FOLDING | |
9845 linenr_T lnum; | |
9846 char_u *s; | |
9847 char_u *r; | |
9848 int len; | |
9849 char *txt; | |
9850 #endif | |
9851 | |
9852 rettv->v_type = VAR_STRING; | |
9853 rettv->vval.v_string = NULL; | |
9854 #ifdef FEAT_FOLDING | |
9855 if ((linenr_T)vimvars[VV_FOLDSTART].vv_nr > 0 | |
9856 && (linenr_T)vimvars[VV_FOLDEND].vv_nr | |
9857 <= curbuf->b_ml.ml_line_count | |
9858 && vimvars[VV_FOLDDASHES].vv_str != NULL) | |
9859 { | |
9860 /* Find first non-empty line in the fold. */ | |
9861 lnum = (linenr_T)vimvars[VV_FOLDSTART].vv_nr; | |
9862 while (lnum < (linenr_T)vimvars[VV_FOLDEND].vv_nr) | |
9863 { | |
9864 if (!linewhite(lnum)) | |
9865 break; | |
9866 ++lnum; | |
9867 } | |
9868 | |
9869 /* Find interesting text in this line. */ | |
9870 s = skipwhite(ml_get(lnum)); | |
9871 /* skip C comment-start */ | |
9872 if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) | |
9873 { | |
9874 s = skipwhite(s + 2); | |
9875 if (*skipwhite(s) == NUL | |
9876 && lnum + 1 < (linenr_T)vimvars[VV_FOLDEND].vv_nr) | |
9877 { | |
9878 s = skipwhite(ml_get(lnum + 1)); | |
9879 if (*s == '*') | |
9880 s = skipwhite(s + 1); | |
9881 } | |
9882 } | |
9883 txt = _("+-%s%3ld lines: "); | |
9884 r = alloc((unsigned)(STRLEN(txt) | |
9885 + STRLEN(vimvars[VV_FOLDDASHES].vv_str) /* for %s */ | |
9886 + 20 /* for %3ld */ | |
9887 + STRLEN(s))); /* concatenated */ | |
9888 if (r != NULL) | |
9889 { | |
9890 sprintf((char *)r, txt, vimvars[VV_FOLDDASHES].vv_str, | |
9891 (long)((linenr_T)vimvars[VV_FOLDEND].vv_nr | |
9892 - (linenr_T)vimvars[VV_FOLDSTART].vv_nr + 1)); | |
9893 len = (int)STRLEN(r); | |
9894 STRCAT(r, s); | |
9895 /* remove 'foldmarker' and 'commentstring' */ | |
9896 foldtext_cleanup(r + len); | |
9897 rettv->vval.v_string = r; | |
9898 } | |
9899 } | |
9900 #endif | |
9901 } | |
9902 | |
9903 /* | |
9904 * "foldtextresult(lnum)" function | |
9905 */ | |
9906 static void | |
9907 f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv) | |
9908 { | |
9909 #ifdef FEAT_FOLDING | |
9910 linenr_T lnum; | |
9911 char_u *text; | |
9912 char_u buf[51]; | |
9913 foldinfo_T foldinfo; | |
9914 int fold_count; | |
9915 #endif | |
9916 | |
9917 rettv->v_type = VAR_STRING; | |
9918 rettv->vval.v_string = NULL; | |
9919 #ifdef FEAT_FOLDING | |
9920 lnum = get_tv_lnum(argvars); | |
9921 /* treat illegal types and illegal string values for {lnum} the same */ | |
9922 if (lnum < 0) | |
9923 lnum = 0; | |
9924 fold_count = foldedCount(curwin, lnum, &foldinfo); | |
9925 if (fold_count > 0) | |
9926 { | |
9927 text = get_foldtext(curwin, lnum, lnum + fold_count - 1, | |
9928 &foldinfo, buf); | |
9929 if (text == buf) | |
9930 text = vim_strsave(text); | |
9931 rettv->vval.v_string = text; | |
9932 } | |
9933 #endif | |
9934 } | |
9935 | |
9936 /* | |
9937 * "foreground()" function | |
9938 */ | |
9939 static void | |
9940 f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
9941 { | |
9942 #ifdef FEAT_GUI | |
9943 if (gui.in_use) | |
9944 gui_mch_set_foreground(); | |
9945 #else | |
9946 # ifdef WIN32 | |
9947 win32_set_foreground(); | |
9948 # endif | |
9949 #endif | |
9950 } | |
9951 | |
9952 /* | |
9953 * "function()" function | |
9954 */ | |
9955 static void | |
9956 f_function(typval_T *argvars, typval_T *rettv) | |
9957 { | |
9958 char_u *s; | |
9959 char_u *name; | |
9960 int use_string = FALSE; | |
9961 partial_T *arg_pt = NULL; | |
9962 | |
9963 if (argvars[0].v_type == VAR_FUNC) | |
9964 { | |
9965 /* function(MyFunc, [arg], dict) */ | |
9966 s = argvars[0].vval.v_string; | |
9967 } | |
9968 else if (argvars[0].v_type == VAR_PARTIAL | |
9969 && argvars[0].vval.v_partial != NULL) | |
9970 { | |
9971 /* function(dict.MyFunc, [arg]) */ | |
9972 arg_pt = argvars[0].vval.v_partial; | |
9973 s = arg_pt->pt_name; | |
9974 } | |
9975 else | |
9976 { | |
9977 /* function('MyFunc', [arg], dict) */ | |
9978 s = get_tv_string(&argvars[0]); | |
9979 use_string = TRUE; | |
9980 } | |
9981 | |
9982 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))) | |
9983 EMSG2(_(e_invarg2), s); | |
9984 /* Don't check an autoload name for existence here. */ | |
9985 else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL | |
9986 && !function_exists(s)) | |
9987 EMSG2(_("E700: Unknown function: %s"), s); | |
9988 else | |
9989 { | |
9990 int dict_idx = 0; | |
9991 int arg_idx = 0; | |
9992 list_T *list = NULL; | |
9993 | |
9994 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) | |
9995 { | |
9996 char sid_buf[25]; | |
9997 int off = *s == 's' ? 2 : 5; | |
9998 | |
9999 /* Expand s: and <SID> into <SNR>nr_, so that the function can | |
10000 * also be called from another script. Using trans_function_name() | |
10001 * would also work, but some plugins depend on the name being | |
10002 * printable text. */ | |
10003 sprintf(sid_buf, "<SNR>%ld_", (long)current_SID); | |
10004 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); | |
10005 if (name != NULL) | |
10006 { | |
10007 STRCPY(name, sid_buf); | |
10008 STRCAT(name, s + off); | |
10009 } | |
10010 } | |
10011 else | |
10012 name = vim_strsave(s); | |
10013 | |
10014 if (argvars[1].v_type != VAR_UNKNOWN) | |
10015 { | |
10016 if (argvars[2].v_type != VAR_UNKNOWN) | |
10017 { | |
10018 /* function(name, [args], dict) */ | |
10019 arg_idx = 1; | |
10020 dict_idx = 2; | |
10021 } | |
10022 else if (argvars[1].v_type == VAR_DICT) | |
10023 /* function(name, dict) */ | |
10024 dict_idx = 1; | |
10025 else | |
10026 /* function(name, [args]) */ | |
10027 arg_idx = 1; | |
10028 if (dict_idx > 0) | |
10029 { | |
10030 if (argvars[dict_idx].v_type != VAR_DICT) | |
10031 { | |
10032 EMSG(_("E922: expected a dict")); | |
10033 vim_free(name); | |
10034 return; | |
10035 } | |
10036 if (argvars[dict_idx].vval.v_dict == NULL) | |
10037 dict_idx = 0; | |
10038 } | |
10039 if (arg_idx > 0) | |
10040 { | |
10041 if (argvars[arg_idx].v_type != VAR_LIST) | |
10042 { | |
10043 EMSG(_("E923: Second argument of function() must be a list or a dict")); | |
10044 vim_free(name); | |
10045 return; | |
10046 } | |
10047 list = argvars[arg_idx].vval.v_list; | |
10048 if (list == NULL || list->lv_len == 0) | |
10049 arg_idx = 0; | |
10050 } | |
10051 } | |
10052 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL) | |
10053 { | |
10054 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T)); | |
10055 | |
10056 /* result is a VAR_PARTIAL */ | |
10057 if (pt == NULL) | |
10058 vim_free(name); | |
10059 else | |
10060 { | |
10061 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0)) | |
10062 { | |
10063 listitem_T *li; | |
10064 int i = 0; | |
10065 int arg_len = 0; | |
10066 int lv_len = 0; | |
10067 | |
10068 if (arg_pt != NULL) | |
10069 arg_len = arg_pt->pt_argc; | |
10070 if (list != NULL) | |
10071 lv_len = list->lv_len; | |
10072 pt->pt_argc = arg_len + lv_len; | |
10073 pt->pt_argv = (typval_T *)alloc( | |
10074 sizeof(typval_T) * pt->pt_argc); | |
10075 if (pt->pt_argv == NULL) | |
10076 { | |
10077 vim_free(pt); | |
10078 vim_free(name); | |
10079 return; | |
10080 } | |
10081 else | |
10082 { | |
10083 for (i = 0; i < arg_len; i++) | |
10084 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); | |
10085 if (lv_len > 0) | |
10086 for (li = list->lv_first; li != NULL; | |
10087 li = li->li_next) | |
10088 copy_tv(&li->li_tv, &pt->pt_argv[i++]); | |
10089 } | |
10090 } | |
10091 | |
10092 /* For "function(dict.func, [], dict)" and "func" is a partial | |
10093 * use "dict". That is backwards compatible. */ | |
10094 if (dict_idx > 0) | |
10095 { | |
10096 /* The dict is bound explicitly, pt_auto is FALSE. */ | |
10097 pt->pt_dict = argvars[dict_idx].vval.v_dict; | |
10098 ++pt->pt_dict->dv_refcount; | |
10099 } | |
10100 else if (arg_pt != NULL) | |
10101 { | |
10102 /* If the dict was bound automatically the result is also | |
10103 * bound automatically. */ | |
10104 pt->pt_dict = arg_pt->pt_dict; | |
10105 pt->pt_auto = arg_pt->pt_auto; | |
10106 if (pt->pt_dict != NULL) | |
10107 ++pt->pt_dict->dv_refcount; | |
10108 } | |
10109 | |
10110 pt->pt_refcount = 1; | |
10111 pt->pt_name = name; | |
10112 func_ref(pt->pt_name); | |
10113 } | |
10114 rettv->v_type = VAR_PARTIAL; | |
10115 rettv->vval.v_partial = pt; | |
10116 } | |
10117 else | |
10118 { | |
10119 /* result is a VAR_FUNC */ | |
10120 rettv->v_type = VAR_FUNC; | |
10121 rettv->vval.v_string = name; | |
10122 func_ref(name); | |
10123 } | |
10124 } | |
10125 } | |
10126 | |
10127 /* | |
10128 * "garbagecollect()" function | |
10129 */ | |
10130 static void | |
10131 f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED) | |
10132 { | |
10133 /* This is postponed until we are back at the toplevel, because we may be | |
10134 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ | |
10135 want_garbage_collect = TRUE; | |
10136 | |
10137 if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1) | |
10138 garbage_collect_at_exit = TRUE; | |
10139 } | |
10140 | |
10141 /* | |
10142 * "get()" function | |
10143 */ | |
10144 static void | |
10145 f_get(typval_T *argvars, typval_T *rettv) | |
10146 { | |
10147 listitem_T *li; | |
10148 list_T *l; | |
10149 dictitem_T *di; | |
10150 dict_T *d; | |
10151 typval_T *tv = NULL; | |
10152 | |
10153 if (argvars[0].v_type == VAR_LIST) | |
10154 { | |
10155 if ((l = argvars[0].vval.v_list) != NULL) | |
10156 { | |
10157 int error = FALSE; | |
10158 | |
10159 li = list_find(l, (long)get_tv_number_chk(&argvars[1], &error)); | |
10160 if (!error && li != NULL) | |
10161 tv = &li->li_tv; | |
10162 } | |
10163 } | |
10164 else if (argvars[0].v_type == VAR_DICT) | |
10165 { | |
10166 if ((d = argvars[0].vval.v_dict) != NULL) | |
10167 { | |
10168 di = dict_find(d, get_tv_string(&argvars[1]), -1); | |
10169 if (di != NULL) | |
10170 tv = &di->di_tv; | |
10171 } | |
10172 } | |
10173 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC) | |
10174 { | |
10175 partial_T *pt; | |
10176 partial_T fref_pt; | |
10177 | |
10178 if (argvars[0].v_type == VAR_PARTIAL) | |
10179 pt = argvars[0].vval.v_partial; | |
10180 else | |
10181 { | |
10182 vim_memset(&fref_pt, 0, sizeof(fref_pt)); | |
10183 fref_pt.pt_name = argvars[0].vval.v_string; | |
10184 pt = &fref_pt; | |
10185 } | |
10186 | |
10187 if (pt != NULL) | |
10188 { | |
10189 char_u *what = get_tv_string(&argvars[1]); | |
10190 | |
10191 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0) | |
10192 { | |
10193 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING); | |
10194 if (pt->pt_name == NULL) | |
10195 rettv->vval.v_string = NULL; | |
10196 else | |
10197 rettv->vval.v_string = vim_strsave(pt->pt_name); | |
10198 } | |
10199 else if (STRCMP(what, "dict") == 0) | |
10200 { | |
10201 rettv->v_type = VAR_DICT; | |
10202 rettv->vval.v_dict = pt->pt_dict; | |
10203 if (pt->pt_dict != NULL) | |
10204 ++pt->pt_dict->dv_refcount; | |
10205 } | |
10206 else if (STRCMP(what, "args") == 0) | |
10207 { | |
10208 rettv->v_type = VAR_LIST; | |
10209 if (rettv_list_alloc(rettv) == OK) | |
10210 { | |
10211 int i; | |
10212 | |
10213 for (i = 0; i < pt->pt_argc; ++i) | |
10214 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); | |
10215 } | |
10216 } | |
10217 else | |
10218 EMSG2(_(e_invarg2), what); | |
10219 return; | |
10220 } | |
10221 } | |
10222 else | |
10223 EMSG2(_(e_listdictarg), "get()"); | |
10224 | |
10225 if (tv == NULL) | |
10226 { | |
10227 if (argvars[2].v_type != VAR_UNKNOWN) | |
10228 copy_tv(&argvars[2], rettv); | |
10229 } | |
10230 else | |
10231 copy_tv(tv, rettv); | |
10232 } | |
10233 | |
10234 static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv); | |
10235 | |
10236 /* | |
10237 * Get line or list of lines from buffer "buf" into "rettv". | |
10238 * Return a range (from start to end) of lines in rettv from the specified | |
10239 * buffer. | |
10240 * If 'retlist' is TRUE, then the lines are returned as a Vim List. | |
10241 */ | |
10242 static void | |
10243 get_buffer_lines( | |
10244 buf_T *buf, | |
10245 linenr_T start, | |
10246 linenr_T end, | |
10247 int retlist, | |
10248 typval_T *rettv) | |
10249 { | |
10250 char_u *p; | |
10251 | |
10252 rettv->v_type = VAR_STRING; | |
10253 rettv->vval.v_string = NULL; | |
10254 if (retlist && rettv_list_alloc(rettv) == FAIL) | |
10255 return; | |
10256 | |
10257 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0) | |
10258 return; | |
10259 | |
10260 if (!retlist) | |
10261 { | |
10262 if (start >= 1 && start <= buf->b_ml.ml_line_count) | |
10263 p = ml_get_buf(buf, start, FALSE); | |
10264 else | |
10265 p = (char_u *)""; | |
10266 rettv->vval.v_string = vim_strsave(p); | |
10267 } | |
10268 else | |
10269 { | |
10270 if (end < start) | |
10271 return; | |
10272 | |
10273 if (start < 1) | |
10274 start = 1; | |
10275 if (end > buf->b_ml.ml_line_count) | |
10276 end = buf->b_ml.ml_line_count; | |
10277 while (start <= end) | |
10278 if (list_append_string(rettv->vval.v_list, | |
10279 ml_get_buf(buf, start++, FALSE), -1) == FAIL) | |
10280 break; | |
10281 } | |
10282 } | |
10283 | |
10284 /* | |
10285 * "getbufline()" function | |
10286 */ | |
10287 static void | |
10288 f_getbufline(typval_T *argvars, typval_T *rettv) | |
10289 { | |
10290 linenr_T lnum; | |
10291 linenr_T end; | |
10292 buf_T *buf; | |
10293 | |
10294 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
10295 ++emsg_off; | |
10296 buf = get_buf_tv(&argvars[0], FALSE); | |
10297 --emsg_off; | |
10298 | |
10299 lnum = get_tv_lnum_buf(&argvars[1], buf); | |
10300 if (argvars[2].v_type == VAR_UNKNOWN) | |
10301 end = lnum; | |
10302 else | |
10303 end = get_tv_lnum_buf(&argvars[2], buf); | |
10304 | |
10305 get_buffer_lines(buf, lnum, end, TRUE, rettv); | |
10306 } | |
10307 | |
10308 /* | |
10309 * "getbufvar()" function | |
10310 */ | |
10311 static void | |
10312 f_getbufvar(typval_T *argvars, typval_T *rettv) | |
10313 { | |
10314 buf_T *buf; | |
10315 buf_T *save_curbuf; | |
10316 char_u *varname; | |
10317 dictitem_T *v; | |
10318 int done = FALSE; | |
10319 | |
10320 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
10321 varname = get_tv_string_chk(&argvars[1]); | |
10322 ++emsg_off; | |
10323 buf = get_buf_tv(&argvars[0], FALSE); | |
10324 | |
10325 rettv->v_type = VAR_STRING; | |
10326 rettv->vval.v_string = NULL; | |
10327 | |
10328 if (buf != NULL && varname != NULL) | |
10329 { | |
10330 /* set curbuf to be our buf, temporarily */ | |
10331 save_curbuf = curbuf; | |
10332 curbuf = buf; | |
10333 | |
10334 if (*varname == '&') /* buffer-local-option */ | |
10335 { | |
10336 if (get_option_tv(&varname, rettv, TRUE) == OK) | |
10337 done = TRUE; | |
10338 } | |
10339 else if (STRCMP(varname, "changedtick") == 0) | |
10340 { | |
10341 rettv->v_type = VAR_NUMBER; | |
10342 rettv->vval.v_number = curbuf->b_changedtick; | |
10343 done = TRUE; | |
10344 } | |
10345 else | |
10346 { | |
10347 /* Look up the variable. */ | |
10348 /* Let getbufvar({nr}, "") return the "b:" dictionary. */ | |
10349 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, | |
10350 'b', varname, FALSE); | |
10351 if (v != NULL) | |
10352 { | |
10353 copy_tv(&v->di_tv, rettv); | |
10354 done = TRUE; | |
10355 } | |
10356 } | |
10357 | |
10358 /* restore previous notion of curbuf */ | |
10359 curbuf = save_curbuf; | |
10360 } | |
10361 | |
10362 if (!done && argvars[2].v_type != VAR_UNKNOWN) | |
10363 /* use the default value */ | |
10364 copy_tv(&argvars[2], rettv); | |
10365 | |
10366 --emsg_off; | |
10367 } | |
10368 | |
10369 /* | |
10370 * "getchar()" function | |
10371 */ | |
10372 static void | |
10373 f_getchar(typval_T *argvars, typval_T *rettv) | |
10374 { | |
10375 varnumber_T n; | |
10376 int error = FALSE; | |
10377 | |
10378 /* Position the cursor. Needed after a message that ends in a space. */ | |
10379 windgoto(msg_row, msg_col); | |
10380 | |
10381 ++no_mapping; | |
10382 ++allow_keys; | |
10383 for (;;) | |
10384 { | |
10385 if (argvars[0].v_type == VAR_UNKNOWN) | |
10386 /* getchar(): blocking wait. */ | |
10387 n = safe_vgetc(); | |
10388 else if (get_tv_number_chk(&argvars[0], &error) == 1) | |
10389 /* getchar(1): only check if char avail */ | |
10390 n = vpeekc_any(); | |
10391 else if (error || vpeekc_any() == NUL) | |
10392 /* illegal argument or getchar(0) and no char avail: return zero */ | |
10393 n = 0; | |
10394 else | |
10395 /* getchar(0) and char avail: return char */ | |
10396 n = safe_vgetc(); | |
10397 | |
10398 if (n == K_IGNORE) | |
10399 continue; | |
10400 break; | |
10401 } | |
10402 --no_mapping; | |
10403 --allow_keys; | |
10404 | |
10405 vimvars[VV_MOUSE_WIN].vv_nr = 0; | |
10406 vimvars[VV_MOUSE_WINID].vv_nr = 0; | |
10407 vimvars[VV_MOUSE_LNUM].vv_nr = 0; | |
10408 vimvars[VV_MOUSE_COL].vv_nr = 0; | |
10409 | |
10410 rettv->vval.v_number = n; | |
10411 if (IS_SPECIAL(n) || mod_mask != 0) | |
10412 { | |
10413 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */ | |
10414 int i = 0; | |
10415 | |
10416 /* Turn a special key into three bytes, plus modifier. */ | |
10417 if (mod_mask != 0) | |
10418 { | |
10419 temp[i++] = K_SPECIAL; | |
10420 temp[i++] = KS_MODIFIER; | |
10421 temp[i++] = mod_mask; | |
10422 } | |
10423 if (IS_SPECIAL(n)) | |
10424 { | |
10425 temp[i++] = K_SPECIAL; | |
10426 temp[i++] = K_SECOND(n); | |
10427 temp[i++] = K_THIRD(n); | |
10428 } | |
10429 #ifdef FEAT_MBYTE | |
10430 else if (has_mbyte) | |
10431 i += (*mb_char2bytes)(n, temp + i); | |
10432 #endif | |
10433 else | |
10434 temp[i++] = n; | |
10435 temp[i++] = NUL; | |
10436 rettv->v_type = VAR_STRING; | |
10437 rettv->vval.v_string = vim_strsave(temp); | |
10438 | |
10439 #ifdef FEAT_MOUSE | |
10440 if (is_mouse_key(n)) | |
10441 { | |
10442 int row = mouse_row; | |
10443 int col = mouse_col; | |
10444 win_T *win; | |
10445 linenr_T lnum; | |
10446 # ifdef FEAT_WINDOWS | |
10447 win_T *wp; | |
10448 # endif | |
10449 int winnr = 1; | |
10450 | |
10451 if (row >= 0 && col >= 0) | |
10452 { | |
10453 /* Find the window at the mouse coordinates and compute the | |
10454 * text position. */ | |
10455 win = mouse_find_win(&row, &col); | |
10456 (void)mouse_comp_pos(win, &row, &col, &lnum); | |
10457 # ifdef FEAT_WINDOWS | |
10458 for (wp = firstwin; wp != win; wp = wp->w_next) | |
10459 ++winnr; | |
10460 # endif | |
10461 vimvars[VV_MOUSE_WIN].vv_nr = winnr; | |
10462 vimvars[VV_MOUSE_WINID].vv_nr = win->w_id; | |
10463 vimvars[VV_MOUSE_LNUM].vv_nr = lnum; | |
10464 vimvars[VV_MOUSE_COL].vv_nr = col + 1; | |
10465 } | |
10466 } | |
10467 #endif | |
10468 } | |
10469 } | |
10470 | |
10471 /* | |
10472 * "getcharmod()" function | |
10473 */ | |
10474 static void | |
10475 f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv) | |
10476 { | |
10477 rettv->vval.v_number = mod_mask; | |
10478 } | |
10479 | |
10480 /* | |
10481 * "getcharsearch()" function | |
10482 */ | |
10483 static void | |
10484 f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) | |
10485 { | |
10486 if (rettv_dict_alloc(rettv) != FAIL) | |
10487 { | |
10488 dict_T *dict = rettv->vval.v_dict; | |
10489 | |
10490 dict_add_nr_str(dict, "char", 0L, last_csearch()); | |
10491 dict_add_nr_str(dict, "forward", last_csearch_forward(), NULL); | |
10492 dict_add_nr_str(dict, "until", last_csearch_until(), NULL); | |
10493 } | |
10494 } | |
10495 | |
10496 /* | |
10497 * "getcmdline()" function | |
10498 */ | |
10499 static void | |
10500 f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv) | |
10501 { | |
10502 rettv->v_type = VAR_STRING; | |
10503 rettv->vval.v_string = get_cmdline_str(); | |
10504 } | |
10505 | |
10506 /* | |
10507 * "getcmdpos()" function | |
10508 */ | |
10509 static void | |
10510 f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv) | |
10511 { | |
10512 rettv->vval.v_number = get_cmdline_pos() + 1; | |
10513 } | |
10514 | |
10515 /* | |
10516 * "getcmdtype()" function | |
10517 */ | |
10518 static void | |
10519 f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv) | |
10520 { | |
10521 rettv->v_type = VAR_STRING; | |
10522 rettv->vval.v_string = alloc(2); | |
10523 if (rettv->vval.v_string != NULL) | |
10524 { | |
10525 rettv->vval.v_string[0] = get_cmdline_type(); | |
10526 rettv->vval.v_string[1] = NUL; | |
10527 } | |
10528 } | |
10529 | |
10530 /* | |
10531 * "getcmdwintype()" function | |
10532 */ | |
10533 static void | |
10534 f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) | |
10535 { | |
10536 rettv->v_type = VAR_STRING; | |
10537 rettv->vval.v_string = NULL; | |
10538 #ifdef FEAT_CMDWIN | |
10539 rettv->vval.v_string = alloc(2); | |
10540 if (rettv->vval.v_string != NULL) | |
10541 { | |
10542 rettv->vval.v_string[0] = cmdwin_type; | |
10543 rettv->vval.v_string[1] = NUL; | |
10544 } | |
10545 #endif | |
10546 } | |
10547 | |
10548 #if defined(FEAT_CMDL_COMPL) | |
10549 /* | |
10550 * "getcompletion()" function | |
10551 */ | |
10552 static void | |
10553 f_getcompletion(typval_T *argvars, typval_T *rettv) | |
10554 { | |
10555 char_u *pat; | |
10556 expand_T xpc; | |
10557 int options = WILD_KEEP_ALL | WILD_SILENT | WILD_USE_NL | |
10558 | WILD_LIST_NOTFOUND | WILD_NO_BEEP; | |
10559 | |
10560 if (p_wic) | |
10561 options |= WILD_ICASE; | |
10562 | |
10563 ExpandInit(&xpc); | |
10564 xpc.xp_pattern = get_tv_string(&argvars[0]); | |
10565 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); | |
10566 xpc.xp_context = cmdcomplete_str_to_type(get_tv_string(&argvars[1])); | |
10567 if (xpc.xp_context == EXPAND_NOTHING) | |
10568 { | |
10569 if (argvars[1].v_type == VAR_STRING) | |
10570 EMSG2(_(e_invarg2), argvars[1].vval.v_string); | |
10571 else | |
10572 EMSG(_(e_invarg)); | |
10573 return; | |
10574 } | |
10575 | |
10576 # if defined(FEAT_MENU) | |
10577 if (xpc.xp_context == EXPAND_MENUS) | |
10578 { | |
10579 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE); | |
10580 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern); | |
10581 } | |
10582 # endif | |
10583 | |
10584 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context); | |
10585 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL)) | |
10586 { | |
10587 int i; | |
10588 | |
10589 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP); | |
10590 | |
10591 for (i = 0; i < xpc.xp_numfiles; i++) | |
10592 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); | |
10593 } | |
10594 vim_free(pat); | |
10595 ExpandCleanup(&xpc); | |
10596 } | |
10597 #endif | |
10598 | |
10599 /* | |
10600 * "getcwd()" function | |
10601 */ | |
10602 static void | |
10603 f_getcwd(typval_T *argvars, typval_T *rettv) | |
10604 { | |
10605 win_T *wp = NULL; | |
10606 char_u *cwd; | |
10607 | |
10608 rettv->v_type = VAR_STRING; | |
10609 rettv->vval.v_string = NULL; | |
10610 | |
10611 wp = find_tabwin(&argvars[0], &argvars[1]); | |
10612 if (wp != NULL) | |
10613 { | |
10614 if (wp->w_localdir != NULL) | |
10615 rettv->vval.v_string = vim_strsave(wp->w_localdir); | |
10616 else if (globaldir != NULL) | |
10617 rettv->vval.v_string = vim_strsave(globaldir); | |
10618 else | |
10619 { | |
10620 cwd = alloc(MAXPATHL); | |
10621 if (cwd != NULL) | |
10622 { | |
10623 if (mch_dirname(cwd, MAXPATHL) != FAIL) | |
10624 rettv->vval.v_string = vim_strsave(cwd); | |
10625 vim_free(cwd); | |
10626 } | |
10627 } | |
10628 #ifdef BACKSLASH_IN_FILENAME | |
10629 if (rettv->vval.v_string != NULL) | |
10630 slash_adjust(rettv->vval.v_string); | |
10631 #endif | |
10632 } | |
10633 } | |
10634 | |
10635 /* | |
10636 * "getfontname()" function | |
10637 */ | |
10638 static void | |
10639 f_getfontname(typval_T *argvars UNUSED, typval_T *rettv) | |
10640 { | |
10641 rettv->v_type = VAR_STRING; | |
10642 rettv->vval.v_string = NULL; | |
10643 #ifdef FEAT_GUI | |
10644 if (gui.in_use) | |
10645 { | |
10646 GuiFont font; | |
10647 char_u *name = NULL; | |
10648 | |
10649 if (argvars[0].v_type == VAR_UNKNOWN) | |
10650 { | |
10651 /* Get the "Normal" font. Either the name saved by | |
10652 * hl_set_font_name() or from the font ID. */ | |
10653 font = gui.norm_font; | |
10654 name = hl_get_font_name(); | |
10655 } | |
10656 else | |
10657 { | |
10658 name = get_tv_string(&argvars[0]); | |
10659 if (STRCMP(name, "*") == 0) /* don't use font dialog */ | |
10660 return; | |
10661 font = gui_mch_get_font(name, FALSE); | |
10662 if (font == NOFONT) | |
10663 return; /* Invalid font name, return empty string. */ | |
10664 } | |
10665 rettv->vval.v_string = gui_mch_get_fontname(font, name); | |
10666 if (argvars[0].v_type != VAR_UNKNOWN) | |
10667 gui_mch_free_font(font); | |
10668 } | |
10669 #endif | |
10670 } | |
10671 | |
10672 /* | |
10673 * "getfperm({fname})" function | |
10674 */ | |
10675 static void | |
10676 f_getfperm(typval_T *argvars, typval_T *rettv) | |
10677 { | |
10678 char_u *fname; | |
10679 stat_T st; | |
10680 char_u *perm = NULL; | |
10681 char_u flags[] = "rwx"; | |
10682 int i; | |
10683 | |
10684 fname = get_tv_string(&argvars[0]); | |
10685 | |
10686 rettv->v_type = VAR_STRING; | |
10687 if (mch_stat((char *)fname, &st) >= 0) | |
10688 { | |
10689 perm = vim_strsave((char_u *)"---------"); | |
10690 if (perm != NULL) | |
10691 { | |
10692 for (i = 0; i < 9; i++) | |
10693 { | |
10694 if (st.st_mode & (1 << (8 - i))) | |
10695 perm[i] = flags[i % 3]; | |
10696 } | |
10697 } | |
10698 } | |
10699 rettv->vval.v_string = perm; | |
10700 } | |
10701 | |
10702 /* | |
10703 * "getfsize({fname})" function | |
10704 */ | |
10705 static void | |
10706 f_getfsize(typval_T *argvars, typval_T *rettv) | |
10707 { | |
10708 char_u *fname; | |
10709 stat_T st; | |
10710 | |
10711 fname = get_tv_string(&argvars[0]); | |
10712 | |
10713 rettv->v_type = VAR_NUMBER; | |
10714 | |
10715 if (mch_stat((char *)fname, &st) >= 0) | |
10716 { | |
10717 if (mch_isdir(fname)) | |
10718 rettv->vval.v_number = 0; | |
10719 else | |
10720 { | |
10721 rettv->vval.v_number = (varnumber_T)st.st_size; | |
10722 | |
10723 /* non-perfect check for overflow */ | |
10724 if ((off_T)rettv->vval.v_number != (off_T)st.st_size) | |
10725 rettv->vval.v_number = -2; | |
10726 } | |
10727 } | |
10728 else | |
10729 rettv->vval.v_number = -1; | |
10730 } | |
10731 | |
10732 /* | |
10733 * "getftime({fname})" function | |
10734 */ | |
10735 static void | |
10736 f_getftime(typval_T *argvars, typval_T *rettv) | |
10737 { | |
10738 char_u *fname; | |
10739 stat_T st; | |
10740 | |
10741 fname = get_tv_string(&argvars[0]); | |
10742 | |
10743 if (mch_stat((char *)fname, &st) >= 0) | |
10744 rettv->vval.v_number = (varnumber_T)st.st_mtime; | |
10745 else | |
10746 rettv->vval.v_number = -1; | |
10747 } | |
10748 | |
10749 /* | |
10750 * "getftype({fname})" function | |
10751 */ | |
10752 static void | |
10753 f_getftype(typval_T *argvars, typval_T *rettv) | |
10754 { | |
10755 char_u *fname; | |
10756 stat_T st; | |
10757 char_u *type = NULL; | |
10758 char *t; | |
10759 | |
10760 fname = get_tv_string(&argvars[0]); | |
10761 | |
10762 rettv->v_type = VAR_STRING; | |
10763 if (mch_lstat((char *)fname, &st) >= 0) | |
10764 { | |
10765 #ifdef S_ISREG | |
10766 if (S_ISREG(st.st_mode)) | |
10767 t = "file"; | |
10768 else if (S_ISDIR(st.st_mode)) | |
10769 t = "dir"; | |
10770 # ifdef S_ISLNK | |
10771 else if (S_ISLNK(st.st_mode)) | |
10772 t = "link"; | |
10773 # endif | |
10774 # ifdef S_ISBLK | |
10775 else if (S_ISBLK(st.st_mode)) | |
10776 t = "bdev"; | |
10777 # endif | |
10778 # ifdef S_ISCHR | |
10779 else if (S_ISCHR(st.st_mode)) | |
10780 t = "cdev"; | |
10781 # endif | |
10782 # ifdef S_ISFIFO | |
10783 else if (S_ISFIFO(st.st_mode)) | |
10784 t = "fifo"; | |
10785 # endif | |
10786 # ifdef S_ISSOCK | |
10787 else if (S_ISSOCK(st.st_mode)) | |
10788 t = "fifo"; | |
10789 # endif | |
10790 else | |
10791 t = "other"; | |
10792 #else | |
10793 # ifdef S_IFMT | |
10794 switch (st.st_mode & S_IFMT) | |
10795 { | |
10796 case S_IFREG: t = "file"; break; | |
10797 case S_IFDIR: t = "dir"; break; | |
10798 # ifdef S_IFLNK | |
10799 case S_IFLNK: t = "link"; break; | |
10800 # endif | |
10801 # ifdef S_IFBLK | |
10802 case S_IFBLK: t = "bdev"; break; | |
10803 # endif | |
10804 # ifdef S_IFCHR | |
10805 case S_IFCHR: t = "cdev"; break; | |
10806 # endif | |
10807 # ifdef S_IFIFO | |
10808 case S_IFIFO: t = "fifo"; break; | |
10809 # endif | |
10810 # ifdef S_IFSOCK | |
10811 case S_IFSOCK: t = "socket"; break; | |
10812 # endif | |
10813 default: t = "other"; | |
10814 } | |
10815 # else | |
10816 if (mch_isdir(fname)) | |
10817 t = "dir"; | |
10818 else | |
10819 t = "file"; | |
10820 # endif | |
10821 #endif | |
10822 type = vim_strsave((char_u *)t); | |
10823 } | |
10824 rettv->vval.v_string = type; | |
10825 } | |
10826 | |
10827 /* | |
10828 * "getline(lnum, [end])" function | |
10829 */ | |
10830 static void | |
10831 f_getline(typval_T *argvars, typval_T *rettv) | |
10832 { | |
10833 linenr_T lnum; | |
10834 linenr_T end; | |
10835 int retlist; | |
10836 | |
10837 lnum = get_tv_lnum(argvars); | |
10838 if (argvars[1].v_type == VAR_UNKNOWN) | |
10839 { | |
10840 end = 0; | |
10841 retlist = FALSE; | |
10842 } | |
10843 else | |
10844 { | |
10845 end = get_tv_lnum(&argvars[1]); | |
10846 retlist = TRUE; | |
10847 } | |
10848 | |
10849 get_buffer_lines(curbuf, lnum, end, retlist, rettv); | |
10850 } | |
10851 | |
10852 /* | |
10853 * "getmatches()" function | |
10854 */ | |
10855 static void | |
10856 f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
10857 { | |
10858 #ifdef FEAT_SEARCH_EXTRA | |
10859 dict_T *dict; | |
10860 matchitem_T *cur = curwin->w_match_head; | |
10861 int i; | |
10862 | |
10863 if (rettv_list_alloc(rettv) == OK) | |
10864 { | |
10865 while (cur != NULL) | |
10866 { | |
10867 dict = dict_alloc(); | |
10868 if (dict == NULL) | |
10869 return; | |
10870 if (cur->match.regprog == NULL) | |
10871 { | |
10872 /* match added with matchaddpos() */ | |
10873 for (i = 0; i < MAXPOSMATCH; ++i) | |
10874 { | |
10875 llpos_T *llpos; | |
10876 char buf[6]; | |
10877 list_T *l; | |
10878 | |
10879 llpos = &cur->pos.pos[i]; | |
10880 if (llpos->lnum == 0) | |
10881 break; | |
10882 l = list_alloc(); | |
10883 if (l == NULL) | |
10884 break; | |
10885 list_append_number(l, (varnumber_T)llpos->lnum); | |
10886 if (llpos->col > 0) | |
10887 { | |
10888 list_append_number(l, (varnumber_T)llpos->col); | |
10889 list_append_number(l, (varnumber_T)llpos->len); | |
10890 } | |
10891 sprintf(buf, "pos%d", i + 1); | |
10892 dict_add_list(dict, buf, l); | |
10893 } | |
10894 } | |
10895 else | |
10896 { | |
10897 dict_add_nr_str(dict, "pattern", 0L, cur->pattern); | |
10898 } | |
10899 dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); | |
10900 dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); | |
10901 dict_add_nr_str(dict, "id", (long)cur->id, NULL); | |
10902 # if defined(FEAT_CONCEAL) && defined(FEAT_MBYTE) | |
10903 if (cur->conceal_char) | |
10904 { | |
10905 char_u buf[MB_MAXBYTES + 1]; | |
10906 | |
10907 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; | |
10908 dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf); | |
10909 } | |
10910 # endif | |
10911 list_append_dict(rettv->vval.v_list, dict); | |
10912 cur = cur->next; | |
10913 } | |
10914 } | |
10915 #endif | |
10916 } | |
10917 | |
10918 /* | |
10919 * "getpid()" function | |
10920 */ | |
10921 static void | |
10922 f_getpid(typval_T *argvars UNUSED, typval_T *rettv) | |
10923 { | |
10924 rettv->vval.v_number = mch_get_pid(); | |
10925 } | |
10926 | |
10927 static void | |
10928 getpos_both( | |
10929 typval_T *argvars, | |
10930 typval_T *rettv, | |
10931 int getcurpos) | |
10932 { | |
10933 pos_T *fp; | |
10934 list_T *l; | |
10935 int fnum = -1; | |
10936 | |
10937 if (rettv_list_alloc(rettv) == OK) | |
10938 { | |
10939 l = rettv->vval.v_list; | |
10940 if (getcurpos) | |
10941 fp = &curwin->w_cursor; | |
10942 else | |
10943 fp = var2fpos(&argvars[0], TRUE, &fnum); | |
10944 if (fnum != -1) | |
10945 list_append_number(l, (varnumber_T)fnum); | |
10946 else | |
10947 list_append_number(l, (varnumber_T)0); | |
10948 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum | |
10949 : (varnumber_T)0); | |
10950 list_append_number(l, (fp != NULL) | |
10951 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) | |
10952 : (varnumber_T)0); | |
10953 list_append_number(l, | |
10954 #ifdef FEAT_VIRTUALEDIT | |
10955 (fp != NULL) ? (varnumber_T)fp->coladd : | |
10956 #endif | |
10957 (varnumber_T)0); | |
10958 if (getcurpos) | |
10959 { | |
10960 update_curswant(); | |
10961 list_append_number(l, curwin->w_curswant == MAXCOL ? | |
10962 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1); | |
10963 } | |
10964 } | |
10965 else | |
10966 rettv->vval.v_number = FALSE; | |
10967 } | |
10968 | |
10969 | |
10970 /* | |
10971 * "getcurpos()" function | |
10972 */ | |
10973 static void | |
10974 f_getcurpos(typval_T *argvars, typval_T *rettv) | |
10975 { | |
10976 getpos_both(argvars, rettv, TRUE); | |
10977 } | |
10978 | |
10979 /* | |
10980 * "getpos(string)" function | |
10981 */ | |
10982 static void | |
10983 f_getpos(typval_T *argvars, typval_T *rettv) | |
10984 { | |
10985 getpos_both(argvars, rettv, FALSE); | |
10986 } | |
10987 | |
10988 /* | |
10989 * "getqflist()" and "getloclist()" functions | |
10990 */ | |
10991 static void | |
10992 f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
10993 { | |
10994 #ifdef FEAT_QUICKFIX | |
10995 win_T *wp; | |
10996 #endif | |
10997 | |
10998 #ifdef FEAT_QUICKFIX | |
10999 if (rettv_list_alloc(rettv) == OK) | |
11000 { | |
11001 wp = NULL; | |
11002 if (argvars[0].v_type != VAR_UNKNOWN) /* getloclist() */ | |
11003 { | |
11004 wp = find_win_by_nr(&argvars[0], NULL); | |
11005 if (wp == NULL) | |
11006 return; | |
11007 } | |
11008 | |
11009 (void)get_errorlist(wp, rettv->vval.v_list); | |
11010 } | |
11011 #endif | |
11012 } | |
11013 | |
11014 /* | |
11015 * "getreg()" function | |
11016 */ | |
11017 static void | |
11018 f_getreg(typval_T *argvars, typval_T *rettv) | |
11019 { | |
11020 char_u *strregname; | |
11021 int regname; | |
11022 int arg2 = FALSE; | |
11023 int return_list = FALSE; | |
11024 int error = FALSE; | |
11025 | |
11026 if (argvars[0].v_type != VAR_UNKNOWN) | |
11027 { | |
11028 strregname = get_tv_string_chk(&argvars[0]); | |
11029 error = strregname == NULL; | |
11030 if (argvars[1].v_type != VAR_UNKNOWN) | |
11031 { | |
11032 arg2 = (int)get_tv_number_chk(&argvars[1], &error); | |
11033 if (!error && argvars[2].v_type != VAR_UNKNOWN) | |
11034 return_list = (int)get_tv_number_chk(&argvars[2], &error); | |
11035 } | |
11036 } | |
11037 else | |
11038 strregname = vimvars[VV_REG].vv_str; | |
11039 | |
11040 if (error) | |
11041 return; | |
11042 | |
11043 regname = (strregname == NULL ? '"' : *strregname); | |
11044 if (regname == 0) | |
11045 regname = '"'; | |
11046 | |
11047 if (return_list) | |
11048 { | |
11049 rettv->v_type = VAR_LIST; | |
11050 rettv->vval.v_list = (list_T *)get_reg_contents(regname, | |
11051 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST); | |
11052 if (rettv->vval.v_list == NULL) | |
11053 (void)rettv_list_alloc(rettv); | |
11054 else | |
11055 ++rettv->vval.v_list->lv_refcount; | |
11056 } | |
11057 else | |
11058 { | |
11059 rettv->v_type = VAR_STRING; | |
11060 rettv->vval.v_string = get_reg_contents(regname, | |
11061 arg2 ? GREG_EXPR_SRC : 0); | |
11062 } | |
11063 } | |
11064 | |
11065 /* | |
11066 * "getregtype()" function | |
11067 */ | |
11068 static void | |
11069 f_getregtype(typval_T *argvars, typval_T *rettv) | |
11070 { | |
11071 char_u *strregname; | |
11072 int regname; | |
11073 char_u buf[NUMBUFLEN + 2]; | |
11074 long reglen = 0; | |
11075 | |
11076 if (argvars[0].v_type != VAR_UNKNOWN) | |
11077 { | |
11078 strregname = get_tv_string_chk(&argvars[0]); | |
11079 if (strregname == NULL) /* type error; errmsg already given */ | |
11080 { | |
11081 rettv->v_type = VAR_STRING; | |
11082 rettv->vval.v_string = NULL; | |
11083 return; | |
11084 } | |
11085 } | |
11086 else | |
11087 /* Default to v:register */ | |
11088 strregname = vimvars[VV_REG].vv_str; | |
11089 | |
11090 regname = (strregname == NULL ? '"' : *strregname); | |
11091 if (regname == 0) | |
11092 regname = '"'; | |
11093 | |
11094 buf[0] = NUL; | |
11095 buf[1] = NUL; | |
11096 switch (get_reg_type(regname, ®len)) | |
11097 { | |
11098 case MLINE: buf[0] = 'V'; break; | |
11099 case MCHAR: buf[0] = 'v'; break; | |
11100 case MBLOCK: | |
11101 buf[0] = Ctrl_V; | |
11102 sprintf((char *)buf + 1, "%ld", reglen + 1); | |
11103 break; | |
11104 } | |
11105 rettv->v_type = VAR_STRING; | |
11106 rettv->vval.v_string = vim_strsave(buf); | |
11107 } | |
11108 | |
11109 /* | |
11110 * "gettabvar()" function | |
11111 */ | |
11112 static void | |
11113 f_gettabvar(typval_T *argvars, typval_T *rettv) | |
11114 { | |
11115 win_T *oldcurwin; | |
11116 tabpage_T *tp, *oldtabpage; | |
11117 dictitem_T *v; | |
11118 char_u *varname; | |
11119 int done = FALSE; | |
11120 | |
11121 rettv->v_type = VAR_STRING; | |
11122 rettv->vval.v_string = NULL; | |
11123 | |
11124 varname = get_tv_string_chk(&argvars[1]); | |
11125 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
11126 if (tp != NULL && varname != NULL) | |
11127 { | |
11128 /* Set tp to be our tabpage, temporarily. Also set the window to the | |
11129 * first window in the tabpage, otherwise the window is not valid. */ | |
11130 if (switch_win(&oldcurwin, &oldtabpage, | |
11131 tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE) | |
11132 == OK) | |
11133 { | |
11134 /* look up the variable */ | |
11135 /* Let gettabvar({nr}, "") return the "t:" dictionary. */ | |
11136 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); | |
11137 if (v != NULL) | |
11138 { | |
11139 copy_tv(&v->di_tv, rettv); | |
11140 done = TRUE; | |
11141 } | |
11142 } | |
11143 | |
11144 /* restore previous notion of curwin */ | |
11145 restore_win(oldcurwin, oldtabpage, TRUE); | |
11146 } | |
11147 | |
11148 if (!done && argvars[2].v_type != VAR_UNKNOWN) | |
11149 copy_tv(&argvars[2], rettv); | |
11150 } | |
11151 | |
11152 /* | |
11153 * "gettabwinvar()" function | |
11154 */ | |
11155 static void | |
11156 f_gettabwinvar(typval_T *argvars, typval_T *rettv) | |
11157 { | |
11158 getwinvar(argvars, rettv, 1); | |
11159 } | |
11160 | |
11161 /* | |
11162 * "getwinposx()" function | |
11163 */ | |
11164 static void | |
11165 f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv) | |
11166 { | |
11167 rettv->vval.v_number = -1; | |
11168 #ifdef FEAT_GUI | |
11169 if (gui.in_use) | |
11170 { | |
11171 int x, y; | |
11172 | |
11173 if (gui_mch_get_winpos(&x, &y) == OK) | |
11174 rettv->vval.v_number = x; | |
11175 } | |
11176 #endif | |
11177 } | |
11178 | |
11179 /* | |
11180 * "win_findbuf()" function | |
11181 */ | |
11182 static void | |
11183 f_win_findbuf(typval_T *argvars, typval_T *rettv) | |
11184 { | |
11185 if (rettv_list_alloc(rettv) != FAIL) | |
11186 win_findbuf(argvars, rettv->vval.v_list); | |
11187 } | |
11188 | |
11189 /* | |
11190 * "win_getid()" function | |
11191 */ | |
11192 static void | |
11193 f_win_getid(typval_T *argvars, typval_T *rettv) | |
11194 { | |
11195 rettv->vval.v_number = win_getid(argvars); | |
11196 } | |
11197 | |
11198 /* | |
11199 * "win_gotoid()" function | |
11200 */ | |
11201 static void | |
11202 f_win_gotoid(typval_T *argvars, typval_T *rettv) | |
11203 { | |
11204 rettv->vval.v_number = win_gotoid(argvars); | |
11205 } | |
11206 | |
11207 /* | |
11208 * "win_id2tabwin()" function | |
11209 */ | |
11210 static void | |
11211 f_win_id2tabwin(typval_T *argvars, typval_T *rettv) | |
11212 { | |
11213 if (rettv_list_alloc(rettv) != FAIL) | |
11214 win_id2tabwin(argvars, rettv->vval.v_list); | |
11215 } | |
11216 | |
11217 /* | |
11218 * "win_id2win()" function | |
11219 */ | |
11220 static void | |
11221 f_win_id2win(typval_T *argvars, typval_T *rettv) | |
11222 { | |
11223 rettv->vval.v_number = win_id2win(argvars); | |
11224 } | |
11225 | |
11226 /* | |
11227 * "getwinposy()" function | |
11228 */ | |
11229 static void | |
11230 f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv) | |
11231 { | |
11232 rettv->vval.v_number = -1; | |
11233 #ifdef FEAT_GUI | |
11234 if (gui.in_use) | |
11235 { | |
11236 int x, y; | |
11237 | |
11238 if (gui_mch_get_winpos(&x, &y) == OK) | |
11239 rettv->vval.v_number = y; | |
11240 } | |
11241 #endif | |
11242 } | |
11243 | |
11244 /* | |
11245 * Find window specified by "vp" in tabpage "tp". | |
11246 */ | |
11247 static win_T * | |
11248 find_win_by_nr( | |
11249 typval_T *vp, | |
11250 tabpage_T *tp UNUSED) /* NULL for current tab page */ | |
11251 { | |
11252 #ifdef FEAT_WINDOWS | |
11253 win_T *wp; | |
11254 #endif | |
11255 int nr; | |
11256 | |
11257 nr = (int)get_tv_number_chk(vp, NULL); | |
11258 | |
11259 #ifdef FEAT_WINDOWS | |
11260 if (nr < 0) | |
11261 return NULL; | |
11262 if (nr == 0) | |
11263 return curwin; | |
11264 | |
11265 for (wp = (tp == NULL || tp == curtab) ? firstwin : tp->tp_firstwin; | |
11266 wp != NULL; wp = wp->w_next) | |
11267 if (nr >= LOWEST_WIN_ID) | |
11268 { | |
11269 if (wp->w_id == nr) | |
11270 return wp; | |
11271 } | |
11272 else if (--nr <= 0) | |
11273 break; | |
11274 if (nr >= LOWEST_WIN_ID) | |
11275 return NULL; | |
11276 return wp; | |
11277 #else | |
11278 if (nr == 0 || nr == 1 || nr == curwin->w_id) | |
11279 return curwin; | |
11280 return NULL; | |
11281 #endif | |
11282 } | |
11283 | |
11284 /* | |
11285 * Find window specified by "wvp" in tabpage "tvp". | |
11286 */ | |
11287 static win_T * | |
11288 find_tabwin( | |
11289 typval_T *wvp, /* VAR_UNKNOWN for current window */ | |
11290 typval_T *tvp) /* VAR_UNKNOWN for current tab page */ | |
11291 { | |
11292 win_T *wp = NULL; | |
11293 tabpage_T *tp = NULL; | |
11294 long n; | |
11295 | |
11296 if (wvp->v_type != VAR_UNKNOWN) | |
11297 { | |
11298 if (tvp->v_type != VAR_UNKNOWN) | |
11299 { | |
11300 n = (long)get_tv_number(tvp); | |
11301 if (n >= 0) | |
11302 tp = find_tabpage(n); | |
11303 } | |
11304 else | |
11305 tp = curtab; | |
11306 | |
11307 if (tp != NULL) | |
11308 wp = find_win_by_nr(wvp, tp); | |
11309 } | |
11310 else | |
11311 wp = curwin; | |
11312 | |
11313 return wp; | |
11314 } | |
11315 | |
11316 /* | |
11317 * "getwinvar()" function | |
11318 */ | |
11319 static void | |
11320 f_getwinvar(typval_T *argvars, typval_T *rettv) | |
11321 { | |
11322 getwinvar(argvars, rettv, 0); | |
11323 } | |
11324 | |
11325 /* | |
11326 * getwinvar() and gettabwinvar() | |
11327 */ | |
11328 static void | |
11329 getwinvar( | |
11330 typval_T *argvars, | |
11331 typval_T *rettv, | |
11332 int off) /* 1 for gettabwinvar() */ | |
11333 { | |
11334 win_T *win; | |
11335 char_u *varname; | |
11336 dictitem_T *v; | |
11337 tabpage_T *tp = NULL; | |
11338 int done = FALSE; | |
11339 #ifdef FEAT_WINDOWS | |
11340 win_T *oldcurwin; | |
11341 tabpage_T *oldtabpage; | |
11342 int need_switch_win; | |
11343 #endif | |
11344 | |
11345 #ifdef FEAT_WINDOWS | |
11346 if (off == 1) | |
11347 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
11348 else | |
11349 tp = curtab; | |
11350 #endif | |
11351 win = find_win_by_nr(&argvars[off], tp); | |
11352 varname = get_tv_string_chk(&argvars[off + 1]); | |
11353 ++emsg_off; | |
11354 | |
11355 rettv->v_type = VAR_STRING; | |
11356 rettv->vval.v_string = NULL; | |
11357 | |
11358 if (win != NULL && varname != NULL) | |
11359 { | |
11360 #ifdef FEAT_WINDOWS | |
11361 /* Set curwin to be our win, temporarily. Also set the tabpage, | |
11362 * otherwise the window is not valid. Only do this when needed, | |
11363 * autocommands get blocked. */ | |
11364 need_switch_win = !(tp == curtab && win == curwin); | |
11365 if (!need_switch_win | |
11366 || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) | |
11367 #endif | |
11368 { | |
11369 if (*varname == '&') /* window-local-option */ | |
11370 { | |
11371 if (get_option_tv(&varname, rettv, 1) == OK) | |
11372 done = TRUE; | |
11373 } | |
11374 else | |
11375 { | |
11376 /* Look up the variable. */ | |
11377 /* Let getwinvar({nr}, "") return the "w:" dictionary. */ | |
11378 v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', | |
11379 varname, FALSE); | |
11380 if (v != NULL) | |
11381 { | |
11382 copy_tv(&v->di_tv, rettv); | |
11383 done = TRUE; | |
11384 } | |
11385 } | |
11386 } | |
11387 | |
11388 #ifdef FEAT_WINDOWS | |
11389 if (need_switch_win) | |
11390 /* restore previous notion of curwin */ | |
11391 restore_win(oldcurwin, oldtabpage, TRUE); | |
11392 #endif | |
11393 } | |
11394 | |
11395 if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) | |
11396 /* use the default return value */ | |
11397 copy_tv(&argvars[off + 2], rettv); | |
11398 | |
11399 --emsg_off; | |
11400 } | |
11401 | |
11402 /* | |
11403 * "glob()" function | |
11404 */ | |
11405 static void | |
11406 f_glob(typval_T *argvars, typval_T *rettv) | |
11407 { | |
11408 int options = WILD_SILENT|WILD_USE_NL; | |
11409 expand_T xpc; | |
11410 int error = FALSE; | |
11411 | |
11412 /* When the optional second argument is non-zero, don't remove matches | |
11413 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ | |
11414 rettv->v_type = VAR_STRING; | |
11415 if (argvars[1].v_type != VAR_UNKNOWN) | |
11416 { | |
11417 if (get_tv_number_chk(&argvars[1], &error)) | |
11418 options |= WILD_KEEP_ALL; | |
11419 if (argvars[2].v_type != VAR_UNKNOWN) | |
11420 { | |
11421 if (get_tv_number_chk(&argvars[2], &error)) | |
11422 { | |
11423 rettv->v_type = VAR_LIST; | |
11424 rettv->vval.v_list = NULL; | |
11425 } | |
11426 if (argvars[3].v_type != VAR_UNKNOWN | |
11427 && get_tv_number_chk(&argvars[3], &error)) | |
11428 options |= WILD_ALLLINKS; | |
11429 } | |
11430 } | |
11431 if (!error) | |
11432 { | |
11433 ExpandInit(&xpc); | |
11434 xpc.xp_context = EXPAND_FILES; | |
11435 if (p_wic) | |
11436 options += WILD_ICASE; | |
11437 if (rettv->v_type == VAR_STRING) | |
11438 rettv->vval.v_string = ExpandOne(&xpc, get_tv_string(&argvars[0]), | |
11439 NULL, options, WILD_ALL); | |
11440 else if (rettv_list_alloc(rettv) != FAIL) | |
11441 { | |
11442 int i; | |
11443 | |
11444 ExpandOne(&xpc, get_tv_string(&argvars[0]), | |
11445 NULL, options, WILD_ALL_KEEP); | |
11446 for (i = 0; i < xpc.xp_numfiles; i++) | |
11447 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1); | |
11448 | |
11449 ExpandCleanup(&xpc); | |
11450 } | |
11451 } | |
11452 else | |
11453 rettv->vval.v_string = NULL; | |
11454 } | |
11455 | |
11456 /* | |
11457 * "globpath()" function | |
11458 */ | |
11459 static void | |
11460 f_globpath(typval_T *argvars, typval_T *rettv) | |
11461 { | |
11462 int flags = 0; | |
11463 char_u buf1[NUMBUFLEN]; | |
11464 char_u *file = get_tv_string_buf_chk(&argvars[1], buf1); | |
11465 int error = FALSE; | |
11466 garray_T ga; | |
11467 int i; | |
11468 | |
11469 /* When the optional second argument is non-zero, don't remove matches | |
11470 * for 'wildignore' and don't put matches for 'suffixes' at the end. */ | |
11471 rettv->v_type = VAR_STRING; | |
11472 if (argvars[2].v_type != VAR_UNKNOWN) | |
11473 { | |
11474 if (get_tv_number_chk(&argvars[2], &error)) | |
11475 flags |= WILD_KEEP_ALL; | |
11476 if (argvars[3].v_type != VAR_UNKNOWN) | |
11477 { | |
11478 if (get_tv_number_chk(&argvars[3], &error)) | |
11479 { | |
11480 rettv->v_type = VAR_LIST; | |
11481 rettv->vval.v_list = NULL; | |
11482 } | |
11483 if (argvars[4].v_type != VAR_UNKNOWN | |
11484 && get_tv_number_chk(&argvars[4], &error)) | |
11485 flags |= WILD_ALLLINKS; | |
11486 } | |
11487 } | |
11488 if (file != NULL && !error) | |
11489 { | |
11490 ga_init2(&ga, (int)sizeof(char_u *), 10); | |
11491 globpath(get_tv_string(&argvars[0]), file, &ga, flags); | |
11492 if (rettv->v_type == VAR_STRING) | |
11493 rettv->vval.v_string = ga_concat_strings(&ga, "\n"); | |
11494 else if (rettv_list_alloc(rettv) != FAIL) | |
11495 for (i = 0; i < ga.ga_len; ++i) | |
11496 list_append_string(rettv->vval.v_list, | |
11497 ((char_u **)(ga.ga_data))[i], -1); | |
11498 ga_clear_strings(&ga); | |
11499 } | |
11500 else | |
11501 rettv->vval.v_string = NULL; | |
11502 } | |
11503 | |
11504 /* | |
11505 * "glob2regpat()" function | |
11506 */ | |
11507 static void | |
11508 f_glob2regpat(typval_T *argvars, typval_T *rettv) | |
11509 { | |
11510 char_u *pat = get_tv_string_chk(&argvars[0]); | |
11511 | |
11512 rettv->v_type = VAR_STRING; | |
11513 rettv->vval.v_string = (pat == NULL) | |
11514 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE); | |
11515 } | |
11516 | |
11517 /* | |
11518 * "has()" function | |
11519 */ | |
11520 static void | |
11521 f_has(typval_T *argvars, typval_T *rettv) | |
11522 { | |
11523 int i; | |
11524 char_u *name; | |
11525 int n = FALSE; | |
11526 static char *(has_list[]) = | |
11527 { | |
11528 #ifdef AMIGA | |
11529 "amiga", | |
11530 # ifdef FEAT_ARP | |
11531 "arp", | |
11532 # endif | |
11533 #endif | |
11534 #ifdef __BEOS__ | |
11535 "beos", | |
11536 #endif | |
11537 #ifdef MACOS | |
11538 "mac", | |
11539 #endif | |
11540 #if defined(MACOS_X_UNIX) | |
11541 "macunix", /* built with 'darwin' enabled */ | |
11542 #endif | |
11543 #if defined(__APPLE__) && __APPLE__ == 1 | |
11544 "osx", /* built with or without 'darwin' enabled */ | |
11545 #endif | |
11546 #ifdef __QNX__ | |
11547 "qnx", | |
11548 #endif | |
11549 #ifdef UNIX | |
11550 "unix", | |
11551 #endif | |
11552 #ifdef VMS | |
11553 "vms", | |
11554 #endif | |
11555 #ifdef WIN32 | |
11556 "win32", | |
11557 #endif | |
11558 #if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__)) | |
11559 "win32unix", | |
11560 #endif | |
11561 #if defined(WIN64) || defined(_WIN64) | |
11562 "win64", | |
11563 #endif | |
11564 #ifdef EBCDIC | |
11565 "ebcdic", | |
11566 #endif | |
11567 #ifndef CASE_INSENSITIVE_FILENAME | |
11568 "fname_case", | |
11569 #endif | |
11570 #ifdef HAVE_ACL | |
11571 "acl", | |
11572 #endif | |
11573 #ifdef FEAT_ARABIC | |
11574 "arabic", | |
11575 #endif | |
11576 #ifdef FEAT_AUTOCMD | |
11577 "autocmd", | |
11578 #endif | |
11579 #ifdef FEAT_BEVAL | |
11580 "balloon_eval", | |
11581 # ifndef FEAT_GUI_W32 /* other GUIs always have multiline balloons */ | |
11582 "balloon_multiline", | |
11583 # endif | |
11584 #endif | |
11585 #if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS) | |
11586 "builtin_terms", | |
11587 # ifdef ALL_BUILTIN_TCAPS | |
11588 "all_builtin_terms", | |
11589 # endif | |
11590 #endif | |
11591 #if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \ | |
11592 || defined(FEAT_GUI_W32) \ | |
11593 || defined(FEAT_GUI_MOTIF)) | |
11594 "browsefilter", | |
11595 #endif | |
11596 #ifdef FEAT_BYTEOFF | |
11597 "byte_offset", | |
11598 #endif | |
11599 #ifdef FEAT_JOB_CHANNEL | |
11600 "channel", | |
11601 #endif | |
11602 #ifdef FEAT_CINDENT | |
11603 "cindent", | |
11604 #endif | |
11605 #ifdef FEAT_CLIENTSERVER | |
11606 "clientserver", | |
11607 #endif | |
11608 #ifdef FEAT_CLIPBOARD | |
11609 "clipboard", | |
11610 #endif | |
11611 #ifdef FEAT_CMDL_COMPL | |
11612 "cmdline_compl", | |
11613 #endif | |
11614 #ifdef FEAT_CMDHIST | |
11615 "cmdline_hist", | |
11616 #endif | |
11617 #ifdef FEAT_COMMENTS | |
11618 "comments", | |
11619 #endif | |
11620 #ifdef FEAT_CONCEAL | |
11621 "conceal", | |
11622 #endif | |
11623 #ifdef FEAT_CRYPT | |
11624 "cryptv", | |
11625 "crypt-blowfish", | |
11626 "crypt-blowfish2", | |
11627 #endif | |
11628 #ifdef FEAT_CSCOPE | |
11629 "cscope", | |
11630 #endif | |
11631 #ifdef FEAT_CURSORBIND | |
11632 "cursorbind", | |
11633 #endif | |
11634 #ifdef CURSOR_SHAPE | |
11635 "cursorshape", | |
11636 #endif | |
11637 #ifdef DEBUG | |
11638 "debug", | |
11639 #endif | |
11640 #ifdef FEAT_CON_DIALOG | |
11641 "dialog_con", | |
11642 #endif | |
11643 #ifdef FEAT_GUI_DIALOG | |
11644 "dialog_gui", | |
11645 #endif | |
11646 #ifdef FEAT_DIFF | |
11647 "diff", | |
11648 #endif | |
11649 #ifdef FEAT_DIGRAPHS | |
11650 "digraphs", | |
11651 #endif | |
11652 #ifdef FEAT_DIRECTX | |
11653 "directx", | |
11654 #endif | |
11655 #ifdef FEAT_DND | |
11656 "dnd", | |
11657 #endif | |
11658 #ifdef FEAT_EMACS_TAGS | |
11659 "emacs_tags", | |
11660 #endif | |
11661 "eval", /* always present, of course! */ | |
11662 "ex_extra", /* graduated feature */ | |
11663 #ifdef FEAT_SEARCH_EXTRA | |
11664 "extra_search", | |
11665 #endif | |
11666 #ifdef FEAT_FKMAP | |
11667 "farsi", | |
11668 #endif | |
11669 #ifdef FEAT_SEARCHPATH | |
11670 "file_in_path", | |
11671 #endif | |
11672 #ifdef FEAT_FILTERPIPE | |
11673 "filterpipe", | |
11674 #endif | |
11675 #ifdef FEAT_FIND_ID | |
11676 "find_in_path", | |
11677 #endif | |
11678 #ifdef FEAT_FLOAT | |
11679 "float", | |
11680 #endif | |
11681 #ifdef FEAT_FOLDING | |
11682 "folding", | |
11683 #endif | |
11684 #ifdef FEAT_FOOTER | |
11685 "footer", | |
11686 #endif | |
11687 #if !defined(USE_SYSTEM) && defined(UNIX) | |
11688 "fork", | |
11689 #endif | |
11690 #ifdef FEAT_GETTEXT | |
11691 "gettext", | |
11692 #endif | |
11693 #ifdef FEAT_GUI | |
11694 "gui", | |
11695 #endif | |
11696 #ifdef FEAT_GUI_ATHENA | |
11697 # ifdef FEAT_GUI_NEXTAW | |
11698 "gui_neXtaw", | |
11699 # else | |
11700 "gui_athena", | |
11701 # endif | |
11702 #endif | |
11703 #ifdef FEAT_GUI_GTK | |
11704 "gui_gtk", | |
11705 # ifdef USE_GTK3 | |
11706 "gui_gtk3", | |
11707 # else | |
11708 "gui_gtk2", | |
11709 # endif | |
11710 #endif | |
11711 #ifdef FEAT_GUI_GNOME | |
11712 "gui_gnome", | |
11713 #endif | |
11714 #ifdef FEAT_GUI_MAC | |
11715 "gui_mac", | |
11716 #endif | |
11717 #ifdef FEAT_GUI_MOTIF | |
11718 "gui_motif", | |
11719 #endif | |
11720 #ifdef FEAT_GUI_PHOTON | |
11721 "gui_photon", | |
11722 #endif | |
11723 #ifdef FEAT_GUI_W32 | |
11724 "gui_win32", | |
11725 #endif | |
11726 #ifdef FEAT_HANGULIN | |
11727 "hangul_input", | |
11728 #endif | |
11729 #if defined(HAVE_ICONV_H) && defined(USE_ICONV) | |
11730 "iconv", | |
11731 #endif | |
11732 #ifdef FEAT_INS_EXPAND | |
11733 "insert_expand", | |
11734 #endif | |
11735 #ifdef FEAT_JOB_CHANNEL | |
11736 "job", | |
11737 #endif | |
11738 #ifdef FEAT_JUMPLIST | |
11739 "jumplist", | |
11740 #endif | |
11741 #ifdef FEAT_KEYMAP | |
11742 "keymap", | |
11743 #endif | |
11744 #ifdef FEAT_LANGMAP | |
11745 "langmap", | |
11746 #endif | |
11747 #ifdef FEAT_LIBCALL | |
11748 "libcall", | |
11749 #endif | |
11750 #ifdef FEAT_LINEBREAK | |
11751 "linebreak", | |
11752 #endif | |
11753 #ifdef FEAT_LISP | |
11754 "lispindent", | |
11755 #endif | |
11756 #ifdef FEAT_LISTCMDS | |
11757 "listcmds", | |
11758 #endif | |
11759 #ifdef FEAT_LOCALMAP | |
11760 "localmap", | |
11761 #endif | |
11762 #ifdef FEAT_LUA | |
11763 # ifndef DYNAMIC_LUA | |
11764 "lua", | |
11765 # endif | |
11766 #endif | |
11767 #ifdef FEAT_MENU | |
11768 "menu", | |
11769 #endif | |
11770 #ifdef FEAT_SESSION | |
11771 "mksession", | |
11772 #endif | |
11773 #ifdef FEAT_MODIFY_FNAME | |
11774 "modify_fname", | |
11775 #endif | |
11776 #ifdef FEAT_MOUSE | |
11777 "mouse", | |
11778 #endif | |
11779 #ifdef FEAT_MOUSESHAPE | |
11780 "mouseshape", | |
11781 #endif | |
11782 #if defined(UNIX) || defined(VMS) | |
11783 # ifdef FEAT_MOUSE_DEC | |
11784 "mouse_dec", | |
11785 # endif | |
11786 # ifdef FEAT_MOUSE_GPM | |
11787 "mouse_gpm", | |
11788 # endif | |
11789 # ifdef FEAT_MOUSE_JSB | |
11790 "mouse_jsbterm", | |
11791 # endif | |
11792 # ifdef FEAT_MOUSE_NET | |
11793 "mouse_netterm", | |
11794 # endif | |
11795 # ifdef FEAT_MOUSE_PTERM | |
11796 "mouse_pterm", | |
11797 # endif | |
11798 # ifdef FEAT_MOUSE_SGR | |
11799 "mouse_sgr", | |
11800 # endif | |
11801 # ifdef FEAT_SYSMOUSE | |
11802 "mouse_sysmouse", | |
11803 # endif | |
11804 # ifdef FEAT_MOUSE_URXVT | |
11805 "mouse_urxvt", | |
11806 # endif | |
11807 # ifdef FEAT_MOUSE_XTERM | |
11808 "mouse_xterm", | |
11809 # endif | |
11810 #endif | |
11811 #ifdef FEAT_MBYTE | |
11812 "multi_byte", | |
11813 #endif | |
11814 #ifdef FEAT_MBYTE_IME | |
11815 "multi_byte_ime", | |
11816 #endif | |
11817 #ifdef FEAT_MULTI_LANG | |
11818 "multi_lang", | |
11819 #endif | |
11820 #ifdef FEAT_MZSCHEME | |
11821 #ifndef DYNAMIC_MZSCHEME | |
11822 "mzscheme", | |
11823 #endif | |
11824 #endif | |
11825 #ifdef FEAT_NUM64 | |
11826 "num64", | |
11827 #endif | |
11828 #ifdef FEAT_OLE | |
11829 "ole", | |
11830 #endif | |
11831 "packages", | |
11832 #ifdef FEAT_PATH_EXTRA | |
11833 "path_extra", | |
11834 #endif | |
11835 #ifdef FEAT_PERL | |
11836 #ifndef DYNAMIC_PERL | |
11837 "perl", | |
11838 #endif | |
11839 #endif | |
11840 #ifdef FEAT_PERSISTENT_UNDO | |
11841 "persistent_undo", | |
11842 #endif | |
11843 #ifdef FEAT_PYTHON | |
11844 #ifndef DYNAMIC_PYTHON | |
11845 "python", | |
11846 #endif | |
11847 #endif | |
11848 #ifdef FEAT_PYTHON3 | |
11849 #ifndef DYNAMIC_PYTHON3 | |
11850 "python3", | |
11851 #endif | |
11852 #endif | |
11853 #ifdef FEAT_POSTSCRIPT | |
11854 "postscript", | |
11855 #endif | |
11856 #ifdef FEAT_PRINTER | |
11857 "printer", | |
11858 #endif | |
11859 #ifdef FEAT_PROFILE | |
11860 "profile", | |
11861 #endif | |
11862 #ifdef FEAT_RELTIME | |
11863 "reltime", | |
11864 #endif | |
11865 #ifdef FEAT_QUICKFIX | |
11866 "quickfix", | |
11867 #endif | |
11868 #ifdef FEAT_RIGHTLEFT | |
11869 "rightleft", | |
11870 #endif | |
11871 #if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY) | |
11872 "ruby", | |
11873 #endif | |
11874 #ifdef FEAT_SCROLLBIND | |
11875 "scrollbind", | |
11876 #endif | |
11877 #ifdef FEAT_CMDL_INFO | |
11878 "showcmd", | |
11879 "cmdline_info", | |
11880 #endif | |
11881 #ifdef FEAT_SIGNS | |
11882 "signs", | |
11883 #endif | |
11884 #ifdef FEAT_SMARTINDENT | |
11885 "smartindent", | |
11886 #endif | |
11887 #ifdef STARTUPTIME | |
11888 "startuptime", | |
11889 #endif | |
11890 #ifdef FEAT_STL_OPT | |
11891 "statusline", | |
11892 #endif | |
11893 #ifdef FEAT_SUN_WORKSHOP | |
11894 "sun_workshop", | |
11895 #endif | |
11896 #ifdef FEAT_NETBEANS_INTG | |
11897 "netbeans_intg", | |
11898 #endif | |
11899 #ifdef FEAT_SPELL | |
11900 "spell", | |
11901 #endif | |
11902 #ifdef FEAT_SYN_HL | |
11903 "syntax", | |
11904 #endif | |
11905 #if defined(USE_SYSTEM) || !defined(UNIX) | |
11906 "system", | |
11907 #endif | |
11908 #ifdef FEAT_TAG_BINS | |
11909 "tag_binary", | |
11910 #endif | |
11911 #ifdef FEAT_TAG_OLDSTATIC | |
11912 "tag_old_static", | |
11913 #endif | |
11914 #ifdef FEAT_TAG_ANYWHITE | |
11915 "tag_any_white", | |
11916 #endif | |
11917 #ifdef FEAT_TCL | |
11918 # ifndef DYNAMIC_TCL | |
11919 "tcl", | |
11920 # endif | |
11921 #endif | |
11922 #ifdef FEAT_TERMGUICOLORS | |
11923 "termguicolors", | |
11924 #endif | |
11925 #ifdef TERMINFO | |
11926 "terminfo", | |
11927 #endif | |
11928 #ifdef FEAT_TERMRESPONSE | |
11929 "termresponse", | |
11930 #endif | |
11931 #ifdef FEAT_TEXTOBJ | |
11932 "textobjects", | |
11933 #endif | |
11934 #ifdef HAVE_TGETENT | |
11935 "tgetent", | |
11936 #endif | |
11937 #ifdef FEAT_TIMERS | |
11938 "timers", | |
11939 #endif | |
11940 #ifdef FEAT_TITLE | |
11941 "title", | |
11942 #endif | |
11943 #ifdef FEAT_TOOLBAR | |
11944 "toolbar", | |
11945 #endif | |
11946 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11) | |
11947 "unnamedplus", | |
11948 #endif | |
11949 #ifdef FEAT_USR_CMDS | |
11950 "user-commands", /* was accidentally included in 5.4 */ | |
11951 "user_commands", | |
11952 #endif | |
11953 #ifdef FEAT_VIMINFO | |
11954 "viminfo", | |
11955 #endif | |
11956 #ifdef FEAT_WINDOWS | |
11957 "vertsplit", | |
11958 #endif | |
11959 #ifdef FEAT_VIRTUALEDIT | |
11960 "virtualedit", | |
11961 #endif | |
11962 "visual", | |
11963 #ifdef FEAT_VISUALEXTRA | |
11964 "visualextra", | |
11965 #endif | |
11966 #ifdef FEAT_VREPLACE | |
11967 "vreplace", | |
11968 #endif | |
11969 #ifdef FEAT_WILDIGN | |
11970 "wildignore", | |
11971 #endif | |
11972 #ifdef FEAT_WILDMENU | |
11973 "wildmenu", | |
11974 #endif | |
11975 #ifdef FEAT_WINDOWS | |
11976 "windows", | |
11977 #endif | |
11978 #ifdef FEAT_WAK | |
11979 "winaltkeys", | |
11980 #endif | |
11981 #ifdef FEAT_WRITEBACKUP | |
11982 "writebackup", | |
11983 #endif | |
11984 #ifdef FEAT_XIM | |
11985 "xim", | |
11986 #endif | |
11987 #ifdef FEAT_XFONTSET | |
11988 "xfontset", | |
11989 #endif | |
11990 #ifdef FEAT_XPM_W32 | |
11991 "xpm", | |
11992 "xpm_w32", /* for backward compatibility */ | |
11993 #else | |
11994 # if defined(HAVE_XPM) | |
11995 "xpm", | |
11996 # endif | |
11997 #endif | |
11998 #ifdef USE_XSMP | |
11999 "xsmp", | |
12000 #endif | |
12001 #ifdef USE_XSMP_INTERACT | |
12002 "xsmp_interact", | |
12003 #endif | |
12004 #ifdef FEAT_XCLIPBOARD | |
12005 "xterm_clipboard", | |
12006 #endif | |
12007 #ifdef FEAT_XTERM_SAVE | |
12008 "xterm_save", | |
12009 #endif | |
12010 #if defined(UNIX) && defined(FEAT_X11) | |
12011 "X11", | |
12012 #endif | |
12013 NULL | |
12014 }; | |
12015 | |
12016 name = get_tv_string(&argvars[0]); | |
12017 for (i = 0; has_list[i] != NULL; ++i) | |
12018 if (STRICMP(name, has_list[i]) == 0) | |
12019 { | |
12020 n = TRUE; | |
12021 break; | |
12022 } | |
12023 | |
12024 if (n == FALSE) | |
12025 { | |
12026 if (STRNICMP(name, "patch", 5) == 0) | |
12027 { | |
12028 if (name[5] == '-' | |
12029 && STRLEN(name) >= 11 | |
12030 && vim_isdigit(name[6]) | |
12031 && vim_isdigit(name[8]) | |
12032 && vim_isdigit(name[10])) | |
12033 { | |
12034 int major = atoi((char *)name + 6); | |
12035 int minor = atoi((char *)name + 8); | |
12036 | |
12037 /* Expect "patch-9.9.01234". */ | |
12038 n = (major < VIM_VERSION_MAJOR | |
12039 || (major == VIM_VERSION_MAJOR | |
12040 && (minor < VIM_VERSION_MINOR | |
12041 || (minor == VIM_VERSION_MINOR | |
12042 && has_patch(atoi((char *)name + 10)))))); | |
12043 } | |
12044 else | |
12045 n = has_patch(atoi((char *)name + 5)); | |
12046 } | |
12047 else if (STRICMP(name, "vim_starting") == 0) | |
12048 n = (starting != 0); | |
12049 #ifdef FEAT_MBYTE | |
12050 else if (STRICMP(name, "multi_byte_encoding") == 0) | |
12051 n = has_mbyte; | |
12052 #endif | |
12053 #if defined(FEAT_BEVAL) && defined(FEAT_GUI_W32) | |
12054 else if (STRICMP(name, "balloon_multiline") == 0) | |
12055 n = multiline_balloon_available(); | |
12056 #endif | |
12057 #ifdef DYNAMIC_TCL | |
12058 else if (STRICMP(name, "tcl") == 0) | |
12059 n = tcl_enabled(FALSE); | |
12060 #endif | |
12061 #if defined(USE_ICONV) && defined(DYNAMIC_ICONV) | |
12062 else if (STRICMP(name, "iconv") == 0) | |
12063 n = iconv_enabled(FALSE); | |
12064 #endif | |
12065 #ifdef DYNAMIC_LUA | |
12066 else if (STRICMP(name, "lua") == 0) | |
12067 n = lua_enabled(FALSE); | |
12068 #endif | |
12069 #ifdef DYNAMIC_MZSCHEME | |
12070 else if (STRICMP(name, "mzscheme") == 0) | |
12071 n = mzscheme_enabled(FALSE); | |
12072 #endif | |
12073 #ifdef DYNAMIC_RUBY | |
12074 else if (STRICMP(name, "ruby") == 0) | |
12075 n = ruby_enabled(FALSE); | |
12076 #endif | |
12077 #ifdef FEAT_PYTHON | |
12078 #ifdef DYNAMIC_PYTHON | |
12079 else if (STRICMP(name, "python") == 0) | |
12080 n = python_enabled(FALSE); | |
12081 #endif | |
12082 #endif | |
12083 #ifdef FEAT_PYTHON3 | |
12084 #ifdef DYNAMIC_PYTHON3 | |
12085 else if (STRICMP(name, "python3") == 0) | |
12086 n = python3_enabled(FALSE); | |
12087 #endif | |
12088 #endif | |
12089 #ifdef DYNAMIC_PERL | |
12090 else if (STRICMP(name, "perl") == 0) | |
12091 n = perl_enabled(FALSE); | |
12092 #endif | |
12093 #ifdef FEAT_GUI | |
12094 else if (STRICMP(name, "gui_running") == 0) | |
12095 n = (gui.in_use || gui.starting); | |
12096 # ifdef FEAT_GUI_W32 | |
12097 else if (STRICMP(name, "gui_win32s") == 0) | |
12098 n = gui_is_win32s(); | |
12099 # endif | |
12100 # ifdef FEAT_BROWSE | |
12101 else if (STRICMP(name, "browse") == 0) | |
12102 n = gui.in_use; /* gui_mch_browse() works when GUI is running */ | |
12103 # endif | |
12104 #endif | |
12105 #ifdef FEAT_SYN_HL | |
12106 else if (STRICMP(name, "syntax_items") == 0) | |
12107 n = syntax_present(curwin); | |
12108 #endif | |
12109 #if defined(WIN3264) | |
12110 else if (STRICMP(name, "win95") == 0) | |
12111 n = mch_windows95(); | |
12112 #endif | |
12113 #ifdef FEAT_NETBEANS_INTG | |
12114 else if (STRICMP(name, "netbeans_enabled") == 0) | |
12115 n = netbeans_active(); | |
12116 #endif | |
12117 } | |
12118 | |
12119 rettv->vval.v_number = n; | |
12120 } | |
12121 | |
12122 /* | |
12123 * "has_key()" function | |
12124 */ | |
12125 static void | |
12126 f_has_key(typval_T *argvars, typval_T *rettv) | |
12127 { | |
12128 if (argvars[0].v_type != VAR_DICT) | |
12129 { | |
12130 EMSG(_(e_dictreq)); | |
12131 return; | |
12132 } | |
12133 if (argvars[0].vval.v_dict == NULL) | |
12134 return; | |
12135 | |
12136 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict, | |
12137 get_tv_string(&argvars[1]), -1) != NULL; | |
12138 } | |
12139 | |
12140 /* | |
12141 * "haslocaldir()" function | |
12142 */ | |
12143 static void | |
12144 f_haslocaldir(typval_T *argvars, typval_T *rettv) | |
12145 { | |
12146 win_T *wp = NULL; | |
12147 | |
12148 wp = find_tabwin(&argvars[0], &argvars[1]); | |
12149 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL); | |
12150 } | |
12151 | |
12152 /* | |
12153 * "hasmapto()" function | |
12154 */ | |
12155 static void | |
12156 f_hasmapto(typval_T *argvars, typval_T *rettv) | |
12157 { | |
12158 char_u *name; | |
12159 char_u *mode; | |
12160 char_u buf[NUMBUFLEN]; | |
12161 int abbr = FALSE; | |
12162 | |
12163 name = get_tv_string(&argvars[0]); | |
12164 if (argvars[1].v_type == VAR_UNKNOWN) | |
12165 mode = (char_u *)"nvo"; | |
12166 else | |
12167 { | |
12168 mode = get_tv_string_buf(&argvars[1], buf); | |
12169 if (argvars[2].v_type != VAR_UNKNOWN) | |
12170 abbr = (int)get_tv_number(&argvars[2]); | |
12171 } | |
12172 | |
12173 if (map_to_exists(name, mode, abbr)) | |
12174 rettv->vval.v_number = TRUE; | |
12175 else | |
12176 rettv->vval.v_number = FALSE; | |
12177 } | |
12178 | |
12179 /* | |
12180 * "histadd()" function | |
12181 */ | |
12182 static void | |
12183 f_histadd(typval_T *argvars UNUSED, typval_T *rettv) | |
12184 { | |
12185 #ifdef FEAT_CMDHIST | |
12186 int histype; | |
12187 char_u *str; | |
12188 char_u buf[NUMBUFLEN]; | |
12189 #endif | |
12190 | |
12191 rettv->vval.v_number = FALSE; | |
12192 if (check_restricted() || check_secure()) | |
12193 return; | |
12194 #ifdef FEAT_CMDHIST | |
12195 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ | |
12196 histype = str != NULL ? get_histtype(str) : -1; | |
12197 if (histype >= 0) | |
12198 { | |
12199 str = get_tv_string_buf(&argvars[1], buf); | |
12200 if (*str != NUL) | |
12201 { | |
12202 init_history(); | |
12203 add_to_history(histype, str, FALSE, NUL); | |
12204 rettv->vval.v_number = TRUE; | |
12205 return; | |
12206 } | |
12207 } | |
12208 #endif | |
12209 } | |
12210 | |
12211 /* | |
12212 * "histdel()" function | |
12213 */ | |
12214 static void | |
12215 f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
12216 { | |
12217 #ifdef FEAT_CMDHIST | |
12218 int n; | |
12219 char_u buf[NUMBUFLEN]; | |
12220 char_u *str; | |
12221 | |
12222 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ | |
12223 if (str == NULL) | |
12224 n = 0; | |
12225 else if (argvars[1].v_type == VAR_UNKNOWN) | |
12226 /* only one argument: clear entire history */ | |
12227 n = clr_history(get_histtype(str)); | |
12228 else if (argvars[1].v_type == VAR_NUMBER) | |
12229 /* index given: remove that entry */ | |
12230 n = del_history_idx(get_histtype(str), | |
12231 (int)get_tv_number(&argvars[1])); | |
12232 else | |
12233 /* string given: remove all matching entries */ | |
12234 n = del_history_entry(get_histtype(str), | |
12235 get_tv_string_buf(&argvars[1], buf)); | |
12236 rettv->vval.v_number = n; | |
12237 #endif | |
12238 } | |
12239 | |
12240 /* | |
12241 * "histget()" function | |
12242 */ | |
12243 static void | |
12244 f_histget(typval_T *argvars UNUSED, typval_T *rettv) | |
12245 { | |
12246 #ifdef FEAT_CMDHIST | |
12247 int type; | |
12248 int idx; | |
12249 char_u *str; | |
12250 | |
12251 str = get_tv_string_chk(&argvars[0]); /* NULL on type error */ | |
12252 if (str == NULL) | |
12253 rettv->vval.v_string = NULL; | |
12254 else | |
12255 { | |
12256 type = get_histtype(str); | |
12257 if (argvars[1].v_type == VAR_UNKNOWN) | |
12258 idx = get_history_idx(type); | |
12259 else | |
12260 idx = (int)get_tv_number_chk(&argvars[1], NULL); | |
12261 /* -1 on type error */ | |
12262 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); | |
12263 } | |
12264 #else | |
12265 rettv->vval.v_string = NULL; | |
12266 #endif | |
12267 rettv->v_type = VAR_STRING; | |
12268 } | |
12269 | |
12270 /* | |
12271 * "histnr()" function | |
12272 */ | |
12273 static void | |
12274 f_histnr(typval_T *argvars UNUSED, typval_T *rettv) | |
12275 { | |
12276 int i; | |
12277 | |
12278 #ifdef FEAT_CMDHIST | |
12279 char_u *history = get_tv_string_chk(&argvars[0]); | |
12280 | |
12281 i = history == NULL ? HIST_CMD - 1 : get_histtype(history); | |
12282 if (i >= HIST_CMD && i < HIST_COUNT) | |
12283 i = get_history_idx(i); | |
12284 else | |
12285 #endif | |
12286 i = -1; | |
12287 rettv->vval.v_number = i; | |
12288 } | |
12289 | |
12290 /* | |
12291 * "highlightID(name)" function | |
12292 */ | |
12293 static void | |
12294 f_hlID(typval_T *argvars, typval_T *rettv) | |
12295 { | |
12296 rettv->vval.v_number = syn_name2id(get_tv_string(&argvars[0])); | |
12297 } | |
12298 | |
12299 /* | |
12300 * "highlight_exists()" function | |
12301 */ | |
12302 static void | |
12303 f_hlexists(typval_T *argvars, typval_T *rettv) | |
12304 { | |
12305 rettv->vval.v_number = highlight_exists(get_tv_string(&argvars[0])); | |
12306 } | |
12307 | |
12308 /* | |
12309 * "hostname()" function | |
12310 */ | |
12311 static void | |
12312 f_hostname(typval_T *argvars UNUSED, typval_T *rettv) | |
12313 { | |
12314 char_u hostname[256]; | |
12315 | |
12316 mch_get_host_name(hostname, 256); | |
12317 rettv->v_type = VAR_STRING; | |
12318 rettv->vval.v_string = vim_strsave(hostname); | |
12319 } | |
12320 | |
12321 /* | |
12322 * iconv() function | |
12323 */ | |
12324 static void | |
12325 f_iconv(typval_T *argvars UNUSED, typval_T *rettv) | |
12326 { | |
12327 #ifdef FEAT_MBYTE | |
12328 char_u buf1[NUMBUFLEN]; | |
12329 char_u buf2[NUMBUFLEN]; | |
12330 char_u *from, *to, *str; | |
12331 vimconv_T vimconv; | |
12332 #endif | |
12333 | |
12334 rettv->v_type = VAR_STRING; | |
12335 rettv->vval.v_string = NULL; | |
12336 | |
12337 #ifdef FEAT_MBYTE | |
12338 str = get_tv_string(&argvars[0]); | |
12339 from = enc_canonize(enc_skip(get_tv_string_buf(&argvars[1], buf1))); | |
12340 to = enc_canonize(enc_skip(get_tv_string_buf(&argvars[2], buf2))); | |
12341 vimconv.vc_type = CONV_NONE; | |
12342 convert_setup(&vimconv, from, to); | |
12343 | |
12344 /* If the encodings are equal, no conversion needed. */ | |
12345 if (vimconv.vc_type == CONV_NONE) | |
12346 rettv->vval.v_string = vim_strsave(str); | |
12347 else | |
12348 rettv->vval.v_string = string_convert(&vimconv, str, NULL); | |
12349 | |
12350 convert_setup(&vimconv, NULL, NULL); | |
12351 vim_free(from); | |
12352 vim_free(to); | |
12353 #endif | |
12354 } | |
12355 | |
12356 /* | |
12357 * "indent()" function | |
12358 */ | |
12359 static void | |
12360 f_indent(typval_T *argvars, typval_T *rettv) | |
12361 { | |
12362 linenr_T lnum; | |
12363 | |
12364 lnum = get_tv_lnum(argvars); | |
12365 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
12366 rettv->vval.v_number = get_indent_lnum(lnum); | |
12367 else | |
12368 rettv->vval.v_number = -1; | |
12369 } | |
12370 | |
12371 /* | |
12372 * "index()" function | |
12373 */ | |
12374 static void | |
12375 f_index(typval_T *argvars, typval_T *rettv) | |
12376 { | |
12377 list_T *l; | |
12378 listitem_T *item; | |
12379 long idx = 0; | |
12380 int ic = FALSE; | |
12381 | |
12382 rettv->vval.v_number = -1; | |
12383 if (argvars[0].v_type != VAR_LIST) | |
12384 { | |
12385 EMSG(_(e_listreq)); | |
12386 return; | |
12387 } | |
12388 l = argvars[0].vval.v_list; | |
12389 if (l != NULL) | |
12390 { | |
12391 item = l->lv_first; | |
12392 if (argvars[2].v_type != VAR_UNKNOWN) | |
12393 { | |
12394 int error = FALSE; | |
12395 | |
12396 /* Start at specified item. Use the cached index that list_find() | |
12397 * sets, so that a negative number also works. */ | |
12398 item = list_find(l, (long)get_tv_number_chk(&argvars[2], &error)); | |
12399 idx = l->lv_idx; | |
12400 if (argvars[3].v_type != VAR_UNKNOWN) | |
12401 ic = (int)get_tv_number_chk(&argvars[3], &error); | |
12402 if (error) | |
12403 item = NULL; | |
12404 } | |
12405 | |
12406 for ( ; item != NULL; item = item->li_next, ++idx) | |
12407 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE)) | |
12408 { | |
12409 rettv->vval.v_number = idx; | |
12410 break; | |
12411 } | |
12412 } | |
12413 } | |
12414 | |
12415 static int inputsecret_flag = 0; | |
12416 | |
12417 static void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog); | |
12418 | |
12419 /* | |
12420 * This function is used by f_input() and f_inputdialog() functions. The third | |
12421 * argument to f_input() specifies the type of completion to use at the | |
12422 * prompt. The third argument to f_inputdialog() specifies the value to return | |
12423 * when the user cancels the prompt. | |
12424 */ | |
12425 static void | |
12426 get_user_input( | |
12427 typval_T *argvars, | |
12428 typval_T *rettv, | |
12429 int inputdialog) | |
12430 { | |
12431 char_u *prompt = get_tv_string_chk(&argvars[0]); | |
12432 char_u *p = NULL; | |
12433 int c; | |
12434 char_u buf[NUMBUFLEN]; | |
12435 int cmd_silent_save = cmd_silent; | |
12436 char_u *defstr = (char_u *)""; | |
12437 int xp_type = EXPAND_NOTHING; | |
12438 char_u *xp_arg = NULL; | |
12439 | |
12440 rettv->v_type = VAR_STRING; | |
12441 rettv->vval.v_string = NULL; | |
12442 | |
12443 #ifdef NO_CONSOLE_INPUT | |
12444 /* While starting up, there is no place to enter text. */ | |
12445 if (no_console_input()) | |
12446 return; | |
12447 #endif | |
12448 | |
12449 cmd_silent = FALSE; /* Want to see the prompt. */ | |
12450 if (prompt != NULL) | |
12451 { | |
12452 /* Only the part of the message after the last NL is considered as | |
12453 * prompt for the command line */ | |
12454 p = vim_strrchr(prompt, '\n'); | |
12455 if (p == NULL) | |
12456 p = prompt; | |
12457 else | |
12458 { | |
12459 ++p; | |
12460 c = *p; | |
12461 *p = NUL; | |
12462 msg_start(); | |
12463 msg_clr_eos(); | |
12464 msg_puts_attr(prompt, echo_attr); | |
12465 msg_didout = FALSE; | |
12466 msg_starthere(); | |
12467 *p = c; | |
12468 } | |
12469 cmdline_row = msg_row; | |
12470 | |
12471 if (argvars[1].v_type != VAR_UNKNOWN) | |
12472 { | |
12473 defstr = get_tv_string_buf_chk(&argvars[1], buf); | |
12474 if (defstr != NULL) | |
12475 stuffReadbuffSpec(defstr); | |
12476 | |
12477 if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) | |
12478 { | |
12479 char_u *xp_name; | |
12480 int xp_namelen; | |
12481 long argt; | |
12482 | |
12483 /* input() with a third argument: completion */ | |
12484 rettv->vval.v_string = NULL; | |
12485 | |
12486 xp_name = get_tv_string_buf_chk(&argvars[2], buf); | |
12487 if (xp_name == NULL) | |
12488 return; | |
12489 | |
12490 xp_namelen = (int)STRLEN(xp_name); | |
12491 | |
12492 if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt, | |
12493 &xp_arg) == FAIL) | |
12494 return; | |
12495 } | |
12496 } | |
12497 | |
12498 if (defstr != NULL) | |
12499 { | |
12500 int save_ex_normal_busy = ex_normal_busy; | |
12501 ex_normal_busy = 0; | |
12502 rettv->vval.v_string = | |
12503 getcmdline_prompt(inputsecret_flag ? NUL : '@', p, echo_attr, | |
12504 xp_type, xp_arg); | |
12505 ex_normal_busy = save_ex_normal_busy; | |
12506 } | |
12507 if (inputdialog && rettv->vval.v_string == NULL | |
12508 && argvars[1].v_type != VAR_UNKNOWN | |
12509 && argvars[2].v_type != VAR_UNKNOWN) | |
12510 rettv->vval.v_string = vim_strsave(get_tv_string_buf( | |
12511 &argvars[2], buf)); | |
12512 | |
12513 vim_free(xp_arg); | |
12514 | |
12515 /* since the user typed this, no need to wait for return */ | |
12516 need_wait_return = FALSE; | |
12517 msg_didout = FALSE; | |
12518 } | |
12519 cmd_silent = cmd_silent_save; | |
12520 } | |
12521 | |
12522 /* | |
12523 * "input()" function | |
12524 * Also handles inputsecret() when inputsecret is set. | |
12525 */ | |
12526 static void | |
12527 f_input(typval_T *argvars, typval_T *rettv) | |
12528 { | |
12529 get_user_input(argvars, rettv, FALSE); | |
12530 } | |
12531 | |
12532 /* | |
12533 * "inputdialog()" function | |
12534 */ | |
12535 static void | |
12536 f_inputdialog(typval_T *argvars, typval_T *rettv) | |
12537 { | |
12538 #if defined(FEAT_GUI_TEXTDIALOG) | |
12539 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */ | |
12540 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) | |
12541 { | |
12542 char_u *message; | |
12543 char_u buf[NUMBUFLEN]; | |
12544 char_u *defstr = (char_u *)""; | |
12545 | |
12546 message = get_tv_string_chk(&argvars[0]); | |
12547 if (argvars[1].v_type != VAR_UNKNOWN | |
12548 && (defstr = get_tv_string_buf_chk(&argvars[1], buf)) != NULL) | |
12549 vim_strncpy(IObuff, defstr, IOSIZE - 1); | |
12550 else | |
12551 IObuff[0] = NUL; | |
12552 if (message != NULL && defstr != NULL | |
12553 && do_dialog(VIM_QUESTION, NULL, message, | |
12554 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1) | |
12555 rettv->vval.v_string = vim_strsave(IObuff); | |
12556 else | |
12557 { | |
12558 if (message != NULL && defstr != NULL | |
12559 && argvars[1].v_type != VAR_UNKNOWN | |
12560 && argvars[2].v_type != VAR_UNKNOWN) | |
12561 rettv->vval.v_string = vim_strsave( | |
12562 get_tv_string_buf(&argvars[2], buf)); | |
12563 else | |
12564 rettv->vval.v_string = NULL; | |
12565 } | |
12566 rettv->v_type = VAR_STRING; | |
12567 } | |
12568 else | |
12569 #endif | |
12570 get_user_input(argvars, rettv, TRUE); | |
12571 } | |
12572 | |
12573 /* | |
12574 * "inputlist()" function | |
12575 */ | |
12576 static void | |
12577 f_inputlist(typval_T *argvars, typval_T *rettv) | |
12578 { | |
12579 listitem_T *li; | |
12580 int selected; | |
12581 int mouse_used; | |
12582 | |
12583 #ifdef NO_CONSOLE_INPUT | |
12584 /* While starting up, there is no place to enter text. */ | |
12585 if (no_console_input()) | |
12586 return; | |
12587 #endif | |
12588 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) | |
12589 { | |
12590 EMSG2(_(e_listarg), "inputlist()"); | |
12591 return; | |
12592 } | |
12593 | |
12594 msg_start(); | |
12595 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */ | |
12596 lines_left = Rows; /* avoid more prompt */ | |
12597 msg_scroll = TRUE; | |
12598 msg_clr_eos(); | |
12599 | |
12600 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) | |
12601 { | |
12602 msg_puts(get_tv_string(&li->li_tv)); | |
12603 msg_putchar('\n'); | |
12604 } | |
12605 | |
12606 /* Ask for choice. */ | |
12607 selected = prompt_for_number(&mouse_used); | |
12608 if (mouse_used) | |
12609 selected -= lines_left; | |
12610 | |
12611 rettv->vval.v_number = selected; | |
12612 } | |
12613 | |
12614 | |
12615 static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL}; | |
12616 | |
12617 /* | |
12618 * "inputrestore()" function | |
12619 */ | |
12620 static void | |
12621 f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv) | |
12622 { | |
12623 if (ga_userinput.ga_len > 0) | |
12624 { | |
12625 --ga_userinput.ga_len; | |
12626 restore_typeahead((tasave_T *)(ga_userinput.ga_data) | |
12627 + ga_userinput.ga_len); | |
12628 /* default return is zero == OK */ | |
12629 } | |
12630 else if (p_verbose > 1) | |
12631 { | |
12632 verb_msg((char_u *)_("called inputrestore() more often than inputsave()")); | |
12633 rettv->vval.v_number = 1; /* Failed */ | |
12634 } | |
12635 } | |
12636 | |
12637 /* | |
12638 * "inputsave()" function | |
12639 */ | |
12640 static void | |
12641 f_inputsave(typval_T *argvars UNUSED, typval_T *rettv) | |
12642 { | |
12643 /* Add an entry to the stack of typeahead storage. */ | |
12644 if (ga_grow(&ga_userinput, 1) == OK) | |
12645 { | |
12646 save_typeahead((tasave_T *)(ga_userinput.ga_data) | |
12647 + ga_userinput.ga_len); | |
12648 ++ga_userinput.ga_len; | |
12649 /* default return is zero == OK */ | |
12650 } | |
12651 else | |
12652 rettv->vval.v_number = 1; /* Failed */ | |
12653 } | |
12654 | |
12655 /* | |
12656 * "inputsecret()" function | |
12657 */ | |
12658 static void | |
12659 f_inputsecret(typval_T *argvars, typval_T *rettv) | |
12660 { | |
12661 ++cmdline_star; | |
12662 ++inputsecret_flag; | |
12663 f_input(argvars, rettv); | |
12664 --cmdline_star; | |
12665 --inputsecret_flag; | |
12666 } | |
12667 | |
12668 /* | |
12669 * "insert()" function | |
12670 */ | |
12671 static void | |
12672 f_insert(typval_T *argvars, typval_T *rettv) | |
12673 { | |
12674 long before = 0; | |
12675 listitem_T *item; | |
12676 list_T *l; | |
12677 int error = FALSE; | |
12678 | |
12679 if (argvars[0].v_type != VAR_LIST) | |
12680 EMSG2(_(e_listarg), "insert()"); | |
12681 else if ((l = argvars[0].vval.v_list) != NULL | |
12682 && !tv_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE)) | |
12683 { | |
12684 if (argvars[2].v_type != VAR_UNKNOWN) | |
12685 before = (long)get_tv_number_chk(&argvars[2], &error); | |
12686 if (error) | |
12687 return; /* type error; errmsg already given */ | |
12688 | |
12689 if (before == l->lv_len) | |
12690 item = NULL; | |
12691 else | |
12692 { | |
12693 item = list_find(l, before); | |
12694 if (item == NULL) | |
12695 { | |
12696 EMSGN(_(e_listidx), before); | |
12697 l = NULL; | |
12698 } | |
12699 } | |
12700 if (l != NULL) | |
12701 { | |
12702 list_insert_tv(l, &argvars[1], item); | |
12703 copy_tv(&argvars[0], rettv); | |
12704 } | |
12705 } | |
12706 } | |
12707 | |
12708 /* | |
12709 * "invert(expr)" function | |
12710 */ | |
12711 static void | |
12712 f_invert(typval_T *argvars, typval_T *rettv) | |
12713 { | |
12714 rettv->vval.v_number = ~get_tv_number_chk(&argvars[0], NULL); | |
12715 } | |
12716 | |
12717 /* | |
12718 * "isdirectory()" function | |
12719 */ | |
12720 static void | |
12721 f_isdirectory(typval_T *argvars, typval_T *rettv) | |
12722 { | |
12723 rettv->vval.v_number = mch_isdir(get_tv_string(&argvars[0])); | |
12724 } | |
12725 | |
12726 /* | |
12727 * "islocked()" function | |
12728 */ | |
12729 static void | |
12730 f_islocked(typval_T *argvars, typval_T *rettv) | |
12731 { | |
12732 lval_T lv; | |
12733 char_u *end; | |
12734 dictitem_T *di; | |
12735 | |
12736 rettv->vval.v_number = -1; | |
12737 end = get_lval(get_tv_string(&argvars[0]), NULL, &lv, FALSE, FALSE, | |
12738 GLV_NO_AUTOLOAD, FNE_CHECK_START); | |
12739 if (end != NULL && lv.ll_name != NULL) | |
12740 { | |
12741 if (*end != NUL) | |
12742 EMSG(_(e_trailing)); | |
12743 else | |
12744 { | |
12745 if (lv.ll_tv == NULL) | |
12746 { | |
12747 if (check_changedtick(lv.ll_name)) | |
12748 rettv->vval.v_number = 1; /* always locked */ | |
12749 else | |
12750 { | |
12751 di = find_var(lv.ll_name, NULL, TRUE); | |
12752 if (di != NULL) | |
12753 { | |
12754 /* Consider a variable locked when: | |
12755 * 1. the variable itself is locked | |
12756 * 2. the value of the variable is locked. | |
12757 * 3. the List or Dict value is locked. | |
12758 */ | |
12759 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK) | |
12760 || tv_islocked(&di->di_tv)); | |
12761 } | |
12762 } | |
12763 } | |
12764 else if (lv.ll_range) | |
12765 EMSG(_("E786: Range not allowed")); | |
12766 else if (lv.ll_newkey != NULL) | |
12767 EMSG2(_(e_dictkey), lv.ll_newkey); | |
12768 else if (lv.ll_list != NULL) | |
12769 /* List item. */ | |
12770 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv); | |
12771 else | |
12772 /* Dictionary item. */ | |
12773 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv); | |
12774 } | |
12775 } | |
12776 | |
12777 clear_lval(&lv); | |
12778 } | |
12779 | |
12780 #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) | |
12781 /* | |
12782 * "isnan()" function | |
12783 */ | |
12784 static void | |
12785 f_isnan(typval_T *argvars, typval_T *rettv) | |
12786 { | |
12787 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT | |
12788 && isnan(argvars[0].vval.v_float); | |
12789 } | |
12790 #endif | |
12791 | |
12792 /* | |
12793 * "items(dict)" function | |
12794 */ | |
12795 static void | |
12796 f_items(typval_T *argvars, typval_T *rettv) | |
12797 { | |
12798 dict_list(argvars, rettv, 2); | |
12799 } | |
12800 | |
12801 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) | |
12802 /* | |
12803 * Get the job from the argument. | |
12804 * Returns NULL if the job is invalid. | |
12805 */ | |
12806 static job_T * | |
12807 get_job_arg(typval_T *tv) | |
12808 { | |
12809 job_T *job; | |
12810 | |
12811 if (tv->v_type != VAR_JOB) | |
12812 { | |
12813 EMSG2(_(e_invarg2), get_tv_string(tv)); | |
12814 return NULL; | |
12815 } | |
12816 job = tv->vval.v_job; | |
12817 | |
12818 if (job == NULL) | |
12819 EMSG(_("E916: not a valid job")); | |
12820 return job; | |
12821 } | |
12822 | |
12823 /* | |
12824 * "job_getchannel()" function | |
12825 */ | |
12826 static void | |
12827 f_job_getchannel(typval_T *argvars, typval_T *rettv) | |
12828 { | |
12829 job_T *job = get_job_arg(&argvars[0]); | |
12830 | |
12831 if (job != NULL) | |
12832 { | |
12833 rettv->v_type = VAR_CHANNEL; | |
12834 rettv->vval.v_channel = job->jv_channel; | |
12835 if (job->jv_channel != NULL) | |
12836 ++job->jv_channel->ch_refcount; | |
12837 } | |
12838 } | |
12839 | |
12840 /* | |
12841 * "job_info()" function | |
12842 */ | |
12843 static void | |
12844 f_job_info(typval_T *argvars, typval_T *rettv) | |
12845 { | |
12846 job_T *job = get_job_arg(&argvars[0]); | |
12847 | |
12848 if (job != NULL && rettv_dict_alloc(rettv) != FAIL) | |
12849 job_info(job, rettv->vval.v_dict); | |
12850 } | |
12851 | |
12852 /* | |
12853 * "job_setoptions()" function | |
12854 */ | |
12855 static void | |
12856 f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED) | |
12857 { | |
12858 job_T *job = get_job_arg(&argvars[0]); | |
12859 jobopt_T opt; | |
12860 | |
12861 if (job == NULL) | |
12862 return; | |
12863 clear_job_options(&opt); | |
12864 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB) == OK) | |
12865 job_set_options(job, &opt); | |
12866 free_job_options(&opt); | |
12867 } | |
12868 | |
12869 /* | |
12870 * "job_start()" function | |
12871 */ | |
12872 static void | |
12873 f_job_start(typval_T *argvars, typval_T *rettv) | |
12874 { | |
12875 rettv->v_type = VAR_JOB; | |
12876 if (check_restricted() || check_secure()) | |
12877 return; | |
12878 rettv->vval.v_job = job_start(argvars); | |
12879 } | |
12880 | |
12881 /* | |
12882 * "job_status()" function | |
12883 */ | |
12884 static void | |
12885 f_job_status(typval_T *argvars, typval_T *rettv) | |
12886 { | |
12887 job_T *job = get_job_arg(&argvars[0]); | |
12888 | |
12889 if (job != NULL) | |
12890 { | |
12891 rettv->v_type = VAR_STRING; | |
12892 rettv->vval.v_string = vim_strsave((char_u *)job_status(job)); | |
12893 } | |
12894 } | |
12895 | |
12896 /* | |
12897 * "job_stop()" function | |
12898 */ | |
12899 static void | |
12900 f_job_stop(typval_T *argvars, typval_T *rettv) | |
12901 { | |
12902 job_T *job = get_job_arg(&argvars[0]); | |
12903 | |
12904 if (job != NULL) | |
12905 rettv->vval.v_number = job_stop(job, argvars); | |
12906 } | |
12907 #endif | |
12908 | |
12909 /* | |
12910 * "join()" function | |
12911 */ | |
12912 static void | |
12913 f_join(typval_T *argvars, typval_T *rettv) | |
12914 { | |
12915 garray_T ga; | |
12916 char_u *sep; | |
12917 | |
12918 if (argvars[0].v_type != VAR_LIST) | |
12919 { | |
12920 EMSG(_(e_listreq)); | |
12921 return; | |
12922 } | |
12923 if (argvars[0].vval.v_list == NULL) | |
12924 return; | |
12925 if (argvars[1].v_type == VAR_UNKNOWN) | |
12926 sep = (char_u *)" "; | |
12927 else | |
12928 sep = get_tv_string_chk(&argvars[1]); | |
12929 | |
12930 rettv->v_type = VAR_STRING; | |
12931 | |
12932 if (sep != NULL) | |
12933 { | |
12934 ga_init2(&ga, (int)sizeof(char), 80); | |
12935 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0); | |
12936 ga_append(&ga, NUL); | |
12937 rettv->vval.v_string = (char_u *)ga.ga_data; | |
12938 } | |
12939 else | |
12940 rettv->vval.v_string = NULL; | |
12941 } | |
12942 | |
12943 /* | |
12944 * "js_decode()" function | |
12945 */ | |
12946 static void | |
12947 f_js_decode(typval_T *argvars, typval_T *rettv) | |
12948 { | |
12949 js_read_T reader; | |
12950 | |
12951 reader.js_buf = get_tv_string(&argvars[0]); | |
12952 reader.js_fill = NULL; | |
12953 reader.js_used = 0; | |
12954 if (json_decode_all(&reader, rettv, JSON_JS) != OK) | |
12955 EMSG(_(e_invarg)); | |
12956 } | |
12957 | |
12958 /* | |
12959 * "js_encode()" function | |
12960 */ | |
12961 static void | |
12962 f_js_encode(typval_T *argvars, typval_T *rettv) | |
12963 { | |
12964 rettv->v_type = VAR_STRING; | |
12965 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS); | |
12966 } | |
12967 | |
12968 /* | |
12969 * "json_decode()" function | |
12970 */ | |
12971 static void | |
12972 f_json_decode(typval_T *argvars, typval_T *rettv) | |
12973 { | |
12974 js_read_T reader; | |
12975 | |
12976 reader.js_buf = get_tv_string(&argvars[0]); | |
12977 reader.js_fill = NULL; | |
12978 reader.js_used = 0; | |
12979 if (json_decode_all(&reader, rettv, 0) != OK) | |
12980 EMSG(_(e_invarg)); | |
12981 } | |
12982 | |
12983 /* | |
12984 * "json_encode()" function | |
12985 */ | |
12986 static void | |
12987 f_json_encode(typval_T *argvars, typval_T *rettv) | |
12988 { | |
12989 rettv->v_type = VAR_STRING; | |
12990 rettv->vval.v_string = json_encode(&argvars[0], 0); | |
12991 } | |
12992 | |
12993 /* | |
12994 * "keys()" function | |
12995 */ | |
12996 static void | |
12997 f_keys(typval_T *argvars, typval_T *rettv) | |
12998 { | |
12999 dict_list(argvars, rettv, 0); | |
13000 } | |
13001 | |
13002 /* | |
13003 * "last_buffer_nr()" function. | |
13004 */ | |
13005 static void | |
13006 f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv) | |
13007 { | |
13008 int n = 0; | |
13009 buf_T *buf; | |
13010 | |
13011 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
13012 if (n < buf->b_fnum) | |
13013 n = buf->b_fnum; | |
13014 | |
13015 rettv->vval.v_number = n; | |
13016 } | |
13017 | |
13018 /* | |
13019 * "len()" function | |
13020 */ | |
13021 static void | |
13022 f_len(typval_T *argvars, typval_T *rettv) | |
13023 { | |
13024 switch (argvars[0].v_type) | |
13025 { | |
13026 case VAR_STRING: | |
13027 case VAR_NUMBER: | |
13028 rettv->vval.v_number = (varnumber_T)STRLEN( | |
13029 get_tv_string(&argvars[0])); | |
13030 break; | |
13031 case VAR_LIST: | |
13032 rettv->vval.v_number = list_len(argvars[0].vval.v_list); | |
13033 break; | |
13034 case VAR_DICT: | |
13035 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict); | |
13036 break; | |
13037 case VAR_UNKNOWN: | |
13038 case VAR_SPECIAL: | |
13039 case VAR_FLOAT: | |
13040 case VAR_FUNC: | |
13041 case VAR_PARTIAL: | |
13042 case VAR_JOB: | |
13043 case VAR_CHANNEL: | |
13044 EMSG(_("E701: Invalid type for len()")); | |
13045 break; | |
13046 } | |
13047 } | |
13048 | |
13049 static void libcall_common(typval_T *argvars, typval_T *rettv, int type); | |
13050 | |
13051 static void | |
13052 libcall_common(typval_T *argvars, typval_T *rettv, int type) | |
13053 { | |
13054 #ifdef FEAT_LIBCALL | |
13055 char_u *string_in; | |
13056 char_u **string_result; | |
13057 int nr_result; | |
13058 #endif | |
13059 | |
13060 rettv->v_type = type; | |
13061 if (type != VAR_NUMBER) | |
13062 rettv->vval.v_string = NULL; | |
13063 | |
13064 if (check_restricted() || check_secure()) | |
13065 return; | |
13066 | |
13067 #ifdef FEAT_LIBCALL | |
13068 /* The first two args must be strings, otherwise its meaningless */ | |
13069 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING) | |
13070 { | |
13071 string_in = NULL; | |
13072 if (argvars[2].v_type == VAR_STRING) | |
13073 string_in = argvars[2].vval.v_string; | |
13074 if (type == VAR_NUMBER) | |
13075 string_result = NULL; | |
13076 else | |
13077 string_result = &rettv->vval.v_string; | |
13078 if (mch_libcall(argvars[0].vval.v_string, | |
13079 argvars[1].vval.v_string, | |
13080 string_in, | |
13081 argvars[2].vval.v_number, | |
13082 string_result, | |
13083 &nr_result) == OK | |
13084 && type == VAR_NUMBER) | |
13085 rettv->vval.v_number = nr_result; | |
13086 } | |
13087 #endif | |
13088 } | |
13089 | |
13090 /* | |
13091 * "libcall()" function | |
13092 */ | |
13093 static void | |
13094 f_libcall(typval_T *argvars, typval_T *rettv) | |
13095 { | |
13096 libcall_common(argvars, rettv, VAR_STRING); | |
13097 } | |
13098 | |
13099 /* | |
13100 * "libcallnr()" function | |
13101 */ | |
13102 static void | |
13103 f_libcallnr(typval_T *argvars, typval_T *rettv) | |
13104 { | |
13105 libcall_common(argvars, rettv, VAR_NUMBER); | |
13106 } | |
13107 | |
13108 /* | |
13109 * "line(string)" function | |
13110 */ | |
13111 static void | |
13112 f_line(typval_T *argvars, typval_T *rettv) | |
13113 { | |
13114 linenr_T lnum = 0; | |
13115 pos_T *fp; | |
13116 int fnum; | |
13117 | |
13118 fp = var2fpos(&argvars[0], TRUE, &fnum); | |
13119 if (fp != NULL) | |
13120 lnum = fp->lnum; | |
13121 rettv->vval.v_number = lnum; | |
13122 } | |
13123 | |
13124 /* | |
13125 * "line2byte(lnum)" function | |
13126 */ | |
13127 static void | |
13128 f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) | |
13129 { | |
13130 #ifndef FEAT_BYTEOFF | |
13131 rettv->vval.v_number = -1; | |
13132 #else | |
13133 linenr_T lnum; | |
13134 | |
13135 lnum = get_tv_lnum(argvars); | |
13136 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) | |
13137 rettv->vval.v_number = -1; | |
13138 else | |
13139 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL); | |
13140 if (rettv->vval.v_number >= 0) | |
13141 ++rettv->vval.v_number; | |
13142 #endif | |
13143 } | |
13144 | |
13145 /* | |
13146 * "lispindent(lnum)" function | |
13147 */ | |
13148 static void | |
13149 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv) | |
13150 { | |
13151 #ifdef FEAT_LISP | |
13152 pos_T pos; | |
13153 linenr_T lnum; | |
13154 | |
13155 pos = curwin->w_cursor; | |
13156 lnum = get_tv_lnum(argvars); | |
13157 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count) | |
13158 { | |
13159 curwin->w_cursor.lnum = lnum; | |
13160 rettv->vval.v_number = get_lisp_indent(); | |
13161 curwin->w_cursor = pos; | |
13162 } | |
13163 else | |
13164 #endif | |
13165 rettv->vval.v_number = -1; | |
13166 } | |
13167 | |
13168 /* | |
13169 * "localtime()" function | |
13170 */ | |
13171 static void | |
13172 f_localtime(typval_T *argvars UNUSED, typval_T *rettv) | |
13173 { | |
13174 rettv->vval.v_number = (varnumber_T)time(NULL); | |
13175 } | |
13176 | |
13177 static void get_maparg(typval_T *argvars, typval_T *rettv, int exact); | |
13178 | |
13179 static void | |
13180 get_maparg(typval_T *argvars, typval_T *rettv, int exact) | |
13181 { | |
13182 char_u *keys; | |
13183 char_u *which; | |
13184 char_u buf[NUMBUFLEN]; | |
13185 char_u *keys_buf = NULL; | |
13186 char_u *rhs; | |
13187 int mode; | |
13188 int abbr = FALSE; | |
13189 int get_dict = FALSE; | |
13190 mapblock_T *mp; | |
13191 int buffer_local; | |
13192 | |
13193 /* return empty string for failure */ | |
13194 rettv->v_type = VAR_STRING; | |
13195 rettv->vval.v_string = NULL; | |
13196 | |
13197 keys = get_tv_string(&argvars[0]); | |
13198 if (*keys == NUL) | |
13199 return; | |
13200 | |
13201 if (argvars[1].v_type != VAR_UNKNOWN) | |
13202 { | |
13203 which = get_tv_string_buf_chk(&argvars[1], buf); | |
13204 if (argvars[2].v_type != VAR_UNKNOWN) | |
13205 { | |
13206 abbr = (int)get_tv_number(&argvars[2]); | |
13207 if (argvars[3].v_type != VAR_UNKNOWN) | |
13208 get_dict = (int)get_tv_number(&argvars[3]); | |
13209 } | |
13210 } | |
13211 else | |
13212 which = (char_u *)""; | |
13213 if (which == NULL) | |
13214 return; | |
13215 | |
13216 mode = get_map_mode(&which, 0); | |
13217 | |
13218 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); | |
13219 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); | |
13220 vim_free(keys_buf); | |
13221 | |
13222 if (!get_dict) | |
13223 { | |
13224 /* Return a string. */ | |
13225 if (rhs != NULL) | |
13226 rettv->vval.v_string = str2special_save(rhs, FALSE); | |
13227 | |
13228 } | |
13229 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL) | |
13230 { | |
13231 /* Return a dictionary. */ | |
13232 char_u *lhs = str2special_save(mp->m_keys, TRUE); | |
13233 char_u *mapmode = map_mode_to_chars(mp->m_mode); | |
13234 dict_T *dict = rettv->vval.v_dict; | |
13235 | |
13236 dict_add_nr_str(dict, "lhs", 0L, lhs); | |
13237 dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); | |
13238 dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L , NULL); | |
13239 dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL); | |
13240 dict_add_nr_str(dict, "silent", mp->m_silent ? 1L : 0L, NULL); | |
13241 dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL); | |
13242 dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL); | |
13243 dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL); | |
13244 dict_add_nr_str(dict, "mode", 0L, mapmode); | |
13245 | |
13246 vim_free(lhs); | |
13247 vim_free(mapmode); | |
13248 } | |
13249 } | |
13250 | |
13251 #ifdef FEAT_FLOAT | |
13252 /* | |
13253 * "log()" function | |
13254 */ | |
13255 static void | |
13256 f_log(typval_T *argvars, typval_T *rettv) | |
13257 { | |
13258 float_T f = 0.0; | |
13259 | |
13260 rettv->v_type = VAR_FLOAT; | |
13261 if (get_float_arg(argvars, &f) == OK) | |
13262 rettv->vval.v_float = log(f); | |
13263 else | |
13264 rettv->vval.v_float = 0.0; | |
13265 } | |
13266 | |
13267 /* | |
13268 * "log10()" function | |
13269 */ | |
13270 static void | |
13271 f_log10(typval_T *argvars, typval_T *rettv) | |
13272 { | |
13273 float_T f = 0.0; | |
13274 | |
13275 rettv->v_type = VAR_FLOAT; | |
13276 if (get_float_arg(argvars, &f) == OK) | |
13277 rettv->vval.v_float = log10(f); | |
13278 else | |
13279 rettv->vval.v_float = 0.0; | |
13280 } | |
13281 #endif | |
13282 | |
13283 #ifdef FEAT_LUA | |
13284 /* | |
13285 * "luaeval()" function | |
13286 */ | |
13287 static void | |
13288 f_luaeval(typval_T *argvars, typval_T *rettv) | |
13289 { | |
13290 char_u *str; | |
13291 char_u buf[NUMBUFLEN]; | |
13292 | |
13293 str = get_tv_string_buf(&argvars[0], buf); | |
13294 do_luaeval(str, argvars + 1, rettv); | |
13295 } | |
13296 #endif | |
13297 | |
13298 /* | |
13299 * "map()" function | |
13300 */ | |
13301 static void | |
13302 f_map(typval_T *argvars, typval_T *rettv) | |
13303 { | |
13304 filter_map(argvars, rettv, TRUE); | |
13305 } | |
13306 | |
13307 /* | |
13308 * "maparg()" function | |
13309 */ | |
13310 static void | |
13311 f_maparg(typval_T *argvars, typval_T *rettv) | |
13312 { | |
13313 get_maparg(argvars, rettv, TRUE); | |
13314 } | |
13315 | |
13316 /* | |
13317 * "mapcheck()" function | |
13318 */ | |
13319 static void | |
13320 f_mapcheck(typval_T *argvars, typval_T *rettv) | |
13321 { | |
13322 get_maparg(argvars, rettv, FALSE); | |
13323 } | |
13324 | |
13325 static void find_some_match(typval_T *argvars, typval_T *rettv, int start); | |
13326 | |
13327 static void | |
13328 find_some_match(typval_T *argvars, typval_T *rettv, int type) | |
13329 { | |
13330 char_u *str = NULL; | |
13331 long len = 0; | |
13332 char_u *expr = NULL; | |
13333 char_u *pat; | |
13334 regmatch_T regmatch; | |
13335 char_u patbuf[NUMBUFLEN]; | |
13336 char_u strbuf[NUMBUFLEN]; | |
13337 char_u *save_cpo; | |
13338 long start = 0; | |
13339 long nth = 1; | |
13340 colnr_T startcol = 0; | |
13341 int match = 0; | |
13342 list_T *l = NULL; | |
13343 listitem_T *li = NULL; | |
13344 long idx = 0; | |
13345 char_u *tofree = NULL; | |
13346 | |
13347 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
13348 save_cpo = p_cpo; | |
13349 p_cpo = (char_u *)""; | |
13350 | |
13351 rettv->vval.v_number = -1; | |
13352 if (type == 3 || type == 4) | |
13353 { | |
13354 /* type 3: return empty list when there are no matches. | |
13355 * type 4: return ["", -1, -1, -1] */ | |
13356 if (rettv_list_alloc(rettv) == FAIL) | |
13357 goto theend; | |
13358 if (type == 4 | |
13359 && (list_append_string(rettv->vval.v_list, | |
13360 (char_u *)"", 0) == FAIL | |
13361 || list_append_number(rettv->vval.v_list, | |
13362 (varnumber_T)-1) == FAIL | |
13363 || list_append_number(rettv->vval.v_list, | |
13364 (varnumber_T)-1) == FAIL | |
13365 || list_append_number(rettv->vval.v_list, | |
13366 (varnumber_T)-1) == FAIL)) | |
13367 { | |
13368 list_free(rettv->vval.v_list); | |
13369 rettv->vval.v_list = NULL; | |
13370 goto theend; | |
13371 } | |
13372 } | |
13373 else if (type == 2) | |
13374 { | |
13375 rettv->v_type = VAR_STRING; | |
13376 rettv->vval.v_string = NULL; | |
13377 } | |
13378 | |
13379 if (argvars[0].v_type == VAR_LIST) | |
13380 { | |
13381 if ((l = argvars[0].vval.v_list) == NULL) | |
13382 goto theend; | |
13383 li = l->lv_first; | |
13384 } | |
13385 else | |
13386 { | |
13387 expr = str = get_tv_string(&argvars[0]); | |
13388 len = (long)STRLEN(str); | |
13389 } | |
13390 | |
13391 pat = get_tv_string_buf_chk(&argvars[1], patbuf); | |
13392 if (pat == NULL) | |
13393 goto theend; | |
13394 | |
13395 if (argvars[2].v_type != VAR_UNKNOWN) | |
13396 { | |
13397 int error = FALSE; | |
13398 | |
13399 start = (long)get_tv_number_chk(&argvars[2], &error); | |
13400 if (error) | |
13401 goto theend; | |
13402 if (l != NULL) | |
13403 { | |
13404 li = list_find(l, start); | |
13405 if (li == NULL) | |
13406 goto theend; | |
13407 idx = l->lv_idx; /* use the cached index */ | |
13408 } | |
13409 else | |
13410 { | |
13411 if (start < 0) | |
13412 start = 0; | |
13413 if (start > len) | |
13414 goto theend; | |
13415 /* When "count" argument is there ignore matches before "start", | |
13416 * otherwise skip part of the string. Differs when pattern is "^" | |
13417 * or "\<". */ | |
13418 if (argvars[3].v_type != VAR_UNKNOWN) | |
13419 startcol = start; | |
13420 else | |
13421 { | |
13422 str += start; | |
13423 len -= start; | |
13424 } | |
13425 } | |
13426 | |
13427 if (argvars[3].v_type != VAR_UNKNOWN) | |
13428 nth = (long)get_tv_number_chk(&argvars[3], &error); | |
13429 if (error) | |
13430 goto theend; | |
13431 } | |
13432 | |
13433 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); | |
13434 if (regmatch.regprog != NULL) | |
13435 { | |
13436 regmatch.rm_ic = p_ic; | |
13437 | |
13438 for (;;) | |
13439 { | |
13440 if (l != NULL) | |
13441 { | |
13442 if (li == NULL) | |
13443 { | |
13444 match = FALSE; | |
13445 break; | |
13446 } | |
13447 vim_free(tofree); | |
13448 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0); | |
13449 if (str == NULL) | |
13450 break; | |
13451 } | |
13452 | |
13453 match = vim_regexec_nl(®match, str, (colnr_T)startcol); | |
13454 | |
13455 if (match && --nth <= 0) | |
13456 break; | |
13457 if (l == NULL && !match) | |
13458 break; | |
13459 | |
13460 /* Advance to just after the match. */ | |
13461 if (l != NULL) | |
13462 { | |
13463 li = li->li_next; | |
13464 ++idx; | |
13465 } | |
13466 else | |
13467 { | |
13468 #ifdef FEAT_MBYTE | |
13469 startcol = (colnr_T)(regmatch.startp[0] | |
13470 + (*mb_ptr2len)(regmatch.startp[0]) - str); | |
13471 #else | |
13472 startcol = (colnr_T)(regmatch.startp[0] + 1 - str); | |
13473 #endif | |
13474 if (startcol > (colnr_T)len | |
13475 || str + startcol <= regmatch.startp[0]) | |
13476 { | |
13477 match = FALSE; | |
13478 break; | |
13479 } | |
13480 } | |
13481 } | |
13482 | |
13483 if (match) | |
13484 { | |
13485 if (type == 4) | |
13486 { | |
13487 listitem_T *li1 = rettv->vval.v_list->lv_first; | |
13488 listitem_T *li2 = li1->li_next; | |
13489 listitem_T *li3 = li2->li_next; | |
13490 listitem_T *li4 = li3->li_next; | |
13491 | |
13492 vim_free(li1->li_tv.vval.v_string); | |
13493 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0], | |
13494 (int)(regmatch.endp[0] - regmatch.startp[0])); | |
13495 li3->li_tv.vval.v_number = | |
13496 (varnumber_T)(regmatch.startp[0] - expr); | |
13497 li4->li_tv.vval.v_number = | |
13498 (varnumber_T)(regmatch.endp[0] - expr); | |
13499 if (l != NULL) | |
13500 li2->li_tv.vval.v_number = (varnumber_T)idx; | |
13501 } | |
13502 else if (type == 3) | |
13503 { | |
13504 int i; | |
13505 | |
13506 /* return list with matched string and submatches */ | |
13507 for (i = 0; i < NSUBEXP; ++i) | |
13508 { | |
13509 if (regmatch.endp[i] == NULL) | |
13510 { | |
13511 if (list_append_string(rettv->vval.v_list, | |
13512 (char_u *)"", 0) == FAIL) | |
13513 break; | |
13514 } | |
13515 else if (list_append_string(rettv->vval.v_list, | |
13516 regmatch.startp[i], | |
13517 (int)(regmatch.endp[i] - regmatch.startp[i])) | |
13518 == FAIL) | |
13519 break; | |
13520 } | |
13521 } | |
13522 else if (type == 2) | |
13523 { | |
13524 /* return matched string */ | |
13525 if (l != NULL) | |
13526 copy_tv(&li->li_tv, rettv); | |
13527 else | |
13528 rettv->vval.v_string = vim_strnsave(regmatch.startp[0], | |
13529 (int)(regmatch.endp[0] - regmatch.startp[0])); | |
13530 } | |
13531 else if (l != NULL) | |
13532 rettv->vval.v_number = idx; | |
13533 else | |
13534 { | |
13535 if (type != 0) | |
13536 rettv->vval.v_number = | |
13537 (varnumber_T)(regmatch.startp[0] - str); | |
13538 else | |
13539 rettv->vval.v_number = | |
13540 (varnumber_T)(regmatch.endp[0] - str); | |
13541 rettv->vval.v_number += (varnumber_T)(str - expr); | |
13542 } | |
13543 } | |
13544 vim_regfree(regmatch.regprog); | |
13545 } | |
13546 | |
13547 if (type == 4 && l == NULL) | |
13548 /* matchstrpos() without a list: drop the second item. */ | |
13549 listitem_remove(rettv->vval.v_list, | |
13550 rettv->vval.v_list->lv_first->li_next); | |
13551 | |
13552 theend: | |
13553 vim_free(tofree); | |
13554 p_cpo = save_cpo; | |
13555 } | |
13556 | |
13557 /* | |
13558 * "match()" function | |
13559 */ | |
13560 static void | |
13561 f_match(typval_T *argvars, typval_T *rettv) | |
13562 { | |
13563 find_some_match(argvars, rettv, 1); | |
13564 } | |
13565 | |
13566 /* | |
13567 * "matchadd()" function | |
13568 */ | |
13569 static void | |
13570 f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
13571 { | |
13572 #ifdef FEAT_SEARCH_EXTRA | |
13573 char_u buf[NUMBUFLEN]; | |
13574 char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */ | |
13575 char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ | |
13576 int prio = 10; /* default priority */ | |
13577 int id = -1; | |
13578 int error = FALSE; | |
13579 char_u *conceal_char = NULL; | |
13580 | |
13581 rettv->vval.v_number = -1; | |
13582 | |
13583 if (grp == NULL || pat == NULL) | |
13584 return; | |
13585 if (argvars[2].v_type != VAR_UNKNOWN) | |
13586 { | |
13587 prio = (int)get_tv_number_chk(&argvars[2], &error); | |
13588 if (argvars[3].v_type != VAR_UNKNOWN) | |
13589 { | |
13590 id = (int)get_tv_number_chk(&argvars[3], &error); | |
13591 if (argvars[4].v_type != VAR_UNKNOWN) | |
13592 { | |
13593 if (argvars[4].v_type != VAR_DICT) | |
13594 { | |
13595 EMSG(_(e_dictreq)); | |
13596 return; | |
13597 } | |
13598 if (dict_find(argvars[4].vval.v_dict, | |
13599 (char_u *)"conceal", -1) != NULL) | |
13600 conceal_char = get_dict_string(argvars[4].vval.v_dict, | |
13601 (char_u *)"conceal", FALSE); | |
13602 } | |
13603 } | |
13604 } | |
13605 if (error == TRUE) | |
13606 return; | |
13607 if (id >= 1 && id <= 3) | |
13608 { | |
13609 EMSGN("E798: ID is reserved for \":match\": %ld", id); | |
13610 return; | |
13611 } | |
13612 | |
13613 rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL, | |
13614 conceal_char); | |
13615 #endif | |
13616 } | |
13617 | |
13618 /* | |
13619 * "matchaddpos()" function | |
13620 */ | |
13621 static void | |
13622 f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
13623 { | |
13624 #ifdef FEAT_SEARCH_EXTRA | |
13625 char_u buf[NUMBUFLEN]; | |
13626 char_u *group; | |
13627 int prio = 10; | |
13628 int id = -1; | |
13629 int error = FALSE; | |
13630 list_T *l; | |
13631 char_u *conceal_char = NULL; | |
13632 | |
13633 rettv->vval.v_number = -1; | |
13634 | |
13635 group = get_tv_string_buf_chk(&argvars[0], buf); | |
13636 if (group == NULL) | |
13637 return; | |
13638 | |
13639 if (argvars[1].v_type != VAR_LIST) | |
13640 { | |
13641 EMSG2(_(e_listarg), "matchaddpos()"); | |
13642 return; | |
13643 } | |
13644 l = argvars[1].vval.v_list; | |
13645 if (l == NULL) | |
13646 return; | |
13647 | |
13648 if (argvars[2].v_type != VAR_UNKNOWN) | |
13649 { | |
13650 prio = (int)get_tv_number_chk(&argvars[2], &error); | |
13651 if (argvars[3].v_type != VAR_UNKNOWN) | |
13652 { | |
13653 id = (int)get_tv_number_chk(&argvars[3], &error); | |
13654 if (argvars[4].v_type != VAR_UNKNOWN) | |
13655 { | |
13656 if (argvars[4].v_type != VAR_DICT) | |
13657 { | |
13658 EMSG(_(e_dictreq)); | |
13659 return; | |
13660 } | |
13661 if (dict_find(argvars[4].vval.v_dict, | |
13662 (char_u *)"conceal", -1) != NULL) | |
13663 conceal_char = get_dict_string(argvars[4].vval.v_dict, | |
13664 (char_u *)"conceal", FALSE); | |
13665 } | |
13666 } | |
13667 } | |
13668 if (error == TRUE) | |
13669 return; | |
13670 | |
13671 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */ | |
13672 if (id == 1 || id == 2) | |
13673 { | |
13674 EMSGN("E798: ID is reserved for \":match\": %ld", id); | |
13675 return; | |
13676 } | |
13677 | |
13678 rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l, | |
13679 conceal_char); | |
13680 #endif | |
13681 } | |
13682 | |
13683 /* | |
13684 * "matcharg()" function | |
13685 */ | |
13686 static void | |
13687 f_matcharg(typval_T *argvars UNUSED, typval_T *rettv) | |
13688 { | |
13689 if (rettv_list_alloc(rettv) == OK) | |
13690 { | |
13691 #ifdef FEAT_SEARCH_EXTRA | |
13692 int id = (int)get_tv_number(&argvars[0]); | |
13693 matchitem_T *m; | |
13694 | |
13695 if (id >= 1 && id <= 3) | |
13696 { | |
13697 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) | |
13698 { | |
13699 list_append_string(rettv->vval.v_list, | |
13700 syn_id2name(m->hlg_id), -1); | |
13701 list_append_string(rettv->vval.v_list, m->pattern, -1); | |
13702 } | |
13703 else | |
13704 { | |
13705 list_append_string(rettv->vval.v_list, NULL, -1); | |
13706 list_append_string(rettv->vval.v_list, NULL, -1); | |
13707 } | |
13708 } | |
13709 #endif | |
13710 } | |
13711 } | |
13712 | |
13713 /* | |
13714 * "matchdelete()" function | |
13715 */ | |
13716 static void | |
13717 f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
13718 { | |
13719 #ifdef FEAT_SEARCH_EXTRA | |
13720 rettv->vval.v_number = match_delete(curwin, | |
13721 (int)get_tv_number(&argvars[0]), TRUE); | |
13722 #endif | |
13723 } | |
13724 | |
13725 /* | |
13726 * "matchend()" function | |
13727 */ | |
13728 static void | |
13729 f_matchend(typval_T *argvars, typval_T *rettv) | |
13730 { | |
13731 find_some_match(argvars, rettv, 0); | |
13732 } | |
13733 | |
13734 /* | |
13735 * "matchlist()" function | |
13736 */ | |
13737 static void | |
13738 f_matchlist(typval_T *argvars, typval_T *rettv) | |
13739 { | |
13740 find_some_match(argvars, rettv, 3); | |
13741 } | |
13742 | |
13743 /* | |
13744 * "matchstr()" function | |
13745 */ | |
13746 static void | |
13747 f_matchstr(typval_T *argvars, typval_T *rettv) | |
13748 { | |
13749 find_some_match(argvars, rettv, 2); | |
13750 } | |
13751 | |
13752 /* | |
13753 * "matchstrpos()" function | |
13754 */ | |
13755 static void | |
13756 f_matchstrpos(typval_T *argvars, typval_T *rettv) | |
13757 { | |
13758 find_some_match(argvars, rettv, 4); | |
13759 } | |
13760 | |
13761 static void max_min(typval_T *argvars, typval_T *rettv, int domax); | |
13762 | |
13763 static void | |
13764 max_min(typval_T *argvars, typval_T *rettv, int domax) | |
13765 { | |
13766 varnumber_T n = 0; | |
13767 varnumber_T i; | |
13768 int error = FALSE; | |
13769 | |
13770 if (argvars[0].v_type == VAR_LIST) | |
13771 { | |
13772 list_T *l; | |
13773 listitem_T *li; | |
13774 | |
13775 l = argvars[0].vval.v_list; | |
13776 if (l != NULL) | |
13777 { | |
13778 li = l->lv_first; | |
13779 if (li != NULL) | |
13780 { | |
13781 n = get_tv_number_chk(&li->li_tv, &error); | |
13782 for (;;) | |
13783 { | |
13784 li = li->li_next; | |
13785 if (li == NULL) | |
13786 break; | |
13787 i = get_tv_number_chk(&li->li_tv, &error); | |
13788 if (domax ? i > n : i < n) | |
13789 n = i; | |
13790 } | |
13791 } | |
13792 } | |
13793 } | |
13794 else if (argvars[0].v_type == VAR_DICT) | |
13795 { | |
13796 dict_T *d; | |
13797 int first = TRUE; | |
13798 hashitem_T *hi; | |
13799 int todo; | |
13800 | |
13801 d = argvars[0].vval.v_dict; | |
13802 if (d != NULL) | |
13803 { | |
13804 todo = (int)d->dv_hashtab.ht_used; | |
13805 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) | |
13806 { | |
13807 if (!HASHITEM_EMPTY(hi)) | |
13808 { | |
13809 --todo; | |
13810 i = get_tv_number_chk(&HI2DI(hi)->di_tv, &error); | |
13811 if (first) | |
13812 { | |
13813 n = i; | |
13814 first = FALSE; | |
13815 } | |
13816 else if (domax ? i > n : i < n) | |
13817 n = i; | |
13818 } | |
13819 } | |
13820 } | |
13821 } | |
13822 else | |
13823 EMSG(_(e_listdictarg)); | |
13824 rettv->vval.v_number = error ? 0 : n; | |
13825 } | |
13826 | |
13827 /* | |
13828 * "max()" function | |
13829 */ | |
13830 static void | |
13831 f_max(typval_T *argvars, typval_T *rettv) | |
13832 { | |
13833 max_min(argvars, rettv, TRUE); | |
13834 } | |
13835 | |
13836 /* | |
13837 * "min()" function | |
13838 */ | |
13839 static void | |
13840 f_min(typval_T *argvars, typval_T *rettv) | |
13841 { | |
13842 max_min(argvars, rettv, FALSE); | |
13843 } | |
13844 | |
13845 static int mkdir_recurse(char_u *dir, int prot); | |
13846 | |
13847 /* | |
13848 * Create the directory in which "dir" is located, and higher levels when | |
13849 * needed. | |
13850 */ | |
13851 static int | |
13852 mkdir_recurse(char_u *dir, int prot) | |
13853 { | |
13854 char_u *p; | |
13855 char_u *updir; | |
13856 int r = FAIL; | |
13857 | |
13858 /* Get end of directory name in "dir". | |
13859 * We're done when it's "/" or "c:/". */ | |
13860 p = gettail_sep(dir); | |
13861 if (p <= get_past_head(dir)) | |
13862 return OK; | |
13863 | |
13864 /* If the directory exists we're done. Otherwise: create it.*/ | |
13865 updir = vim_strnsave(dir, (int)(p - dir)); | |
13866 if (updir == NULL) | |
13867 return FAIL; | |
13868 if (mch_isdir(updir)) | |
13869 r = OK; | |
13870 else if (mkdir_recurse(updir, prot) == OK) | |
13871 r = vim_mkdir_emsg(updir, prot); | |
13872 vim_free(updir); | |
13873 return r; | |
13874 } | |
13875 | |
13876 #ifdef vim_mkdir | |
13877 /* | |
13878 * "mkdir()" function | |
13879 */ | |
13880 static void | |
13881 f_mkdir(typval_T *argvars, typval_T *rettv) | |
13882 { | |
13883 char_u *dir; | |
13884 char_u buf[NUMBUFLEN]; | |
13885 int prot = 0755; | |
13886 | |
13887 rettv->vval.v_number = FAIL; | |
13888 if (check_restricted() || check_secure()) | |
13889 return; | |
13890 | |
13891 dir = get_tv_string_buf(&argvars[0], buf); | |
13892 if (*dir == NUL) | |
13893 rettv->vval.v_number = FAIL; | |
13894 else | |
13895 { | |
13896 if (*gettail(dir) == NUL) | |
13897 /* remove trailing slashes */ | |
13898 *gettail_sep(dir) = NUL; | |
13899 | |
13900 if (argvars[1].v_type != VAR_UNKNOWN) | |
13901 { | |
13902 if (argvars[2].v_type != VAR_UNKNOWN) | |
13903 prot = (int)get_tv_number_chk(&argvars[2], NULL); | |
13904 if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) | |
13905 mkdir_recurse(dir, prot); | |
13906 } | |
13907 rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot); | |
13908 } | |
13909 } | |
13910 #endif | |
13911 | |
13912 /* | |
13913 * "mode()" function | |
13914 */ | |
13915 static void | |
13916 f_mode(typval_T *argvars, typval_T *rettv) | |
13917 { | |
13918 char_u buf[3]; | |
13919 | |
13920 buf[1] = NUL; | |
13921 buf[2] = NUL; | |
13922 | |
13923 if (time_for_testing == 93784) | |
13924 { | |
13925 /* Testing the two-character code. */ | |
13926 buf[0] = 'x'; | |
13927 buf[1] = '!'; | |
13928 } | |
13929 else if (VIsual_active) | |
13930 { | |
13931 if (VIsual_select) | |
13932 buf[0] = VIsual_mode + 's' - 'v'; | |
13933 else | |
13934 buf[0] = VIsual_mode; | |
13935 } | |
13936 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE | |
13937 || State == CONFIRM) | |
13938 { | |
13939 buf[0] = 'r'; | |
13940 if (State == ASKMORE) | |
13941 buf[1] = 'm'; | |
13942 else if (State == CONFIRM) | |
13943 buf[1] = '?'; | |
13944 } | |
13945 else if (State == EXTERNCMD) | |
13946 buf[0] = '!'; | |
13947 else if (State & INSERT) | |
13948 { | |
13949 #ifdef FEAT_VREPLACE | |
13950 if (State & VREPLACE_FLAG) | |
13951 { | |
13952 buf[0] = 'R'; | |
13953 buf[1] = 'v'; | |
13954 } | |
13955 else | |
13956 #endif | |
13957 if (State & REPLACE_FLAG) | |
13958 buf[0] = 'R'; | |
13959 else | |
13960 buf[0] = 'i'; | |
13961 } | |
13962 else if (State & CMDLINE) | |
13963 { | |
13964 buf[0] = 'c'; | |
13965 if (exmode_active) | |
13966 buf[1] = 'v'; | |
13967 } | |
13968 else if (exmode_active) | |
13969 { | |
13970 buf[0] = 'c'; | |
13971 buf[1] = 'e'; | |
13972 } | |
13973 else | |
13974 { | |
13975 buf[0] = 'n'; | |
13976 if (finish_op) | |
13977 buf[1] = 'o'; | |
13978 } | |
13979 | |
13980 /* Clear out the minor mode when the argument is not a non-zero number or | |
13981 * non-empty string. */ | |
13982 if (!non_zero_arg(&argvars[0])) | |
13983 buf[1] = NUL; | |
13984 | |
13985 rettv->vval.v_string = vim_strsave(buf); | |
13986 rettv->v_type = VAR_STRING; | |
13987 } | |
13988 | |
13989 #if defined(FEAT_MZSCHEME) || defined(PROTO) | |
13990 /* | |
13991 * "mzeval()" function | |
13992 */ | |
13993 static void | |
13994 f_mzeval(typval_T *argvars, typval_T *rettv) | |
13995 { | |
13996 char_u *str; | |
13997 char_u buf[NUMBUFLEN]; | |
13998 | |
13999 str = get_tv_string_buf(&argvars[0], buf); | |
14000 do_mzeval(str, rettv); | |
14001 } | |
14002 | |
14003 void | |
14004 mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv) | |
14005 { | |
14006 typval_T argvars[3]; | |
14007 | |
14008 argvars[0].v_type = VAR_STRING; | |
14009 argvars[0].vval.v_string = name; | |
14010 copy_tv(args, &argvars[1]); | |
14011 argvars[2].v_type = VAR_UNKNOWN; | |
14012 f_call(argvars, rettv); | |
14013 clear_tv(&argvars[1]); | |
14014 } | |
14015 #endif | |
14016 | |
14017 /* | |
14018 * "nextnonblank()" function | |
14019 */ | |
14020 static void | |
14021 f_nextnonblank(typval_T *argvars, typval_T *rettv) | |
14022 { | |
14023 linenr_T lnum; | |
14024 | |
14025 for (lnum = get_tv_lnum(argvars); ; ++lnum) | |
14026 { | |
14027 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count) | |
14028 { | |
14029 lnum = 0; | |
14030 break; | |
14031 } | |
14032 if (*skipwhite(ml_get(lnum)) != NUL) | |
14033 break; | |
14034 } | |
14035 rettv->vval.v_number = lnum; | |
14036 } | |
14037 | |
14038 /* | |
14039 * "nr2char()" function | |
14040 */ | |
14041 static void | |
14042 f_nr2char(typval_T *argvars, typval_T *rettv) | |
14043 { | |
14044 char_u buf[NUMBUFLEN]; | |
14045 | |
14046 #ifdef FEAT_MBYTE | |
14047 if (has_mbyte) | |
14048 { | |
14049 int utf8 = 0; | |
14050 | |
14051 if (argvars[1].v_type != VAR_UNKNOWN) | |
14052 utf8 = (int)get_tv_number_chk(&argvars[1], NULL); | |
14053 if (utf8) | |
14054 buf[(*utf_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; | |
14055 else | |
14056 buf[(*mb_char2bytes)((int)get_tv_number(&argvars[0]), buf)] = NUL; | |
14057 } | |
14058 else | |
14059 #endif | |
14060 { | |
14061 buf[0] = (char_u)get_tv_number(&argvars[0]); | |
14062 buf[1] = NUL; | |
14063 } | |
14064 rettv->v_type = VAR_STRING; | |
14065 rettv->vval.v_string = vim_strsave(buf); | |
14066 } | |
14067 | |
14068 /* | |
14069 * "or(expr, expr)" function | |
14070 */ | |
14071 static void | |
14072 f_or(typval_T *argvars, typval_T *rettv) | |
14073 { | |
14074 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | |
14075 | get_tv_number_chk(&argvars[1], NULL); | |
14076 } | |
14077 | |
14078 /* | |
14079 * "pathshorten()" function | |
14080 */ | |
14081 static void | |
14082 f_pathshorten(typval_T *argvars, typval_T *rettv) | |
14083 { | |
14084 char_u *p; | |
14085 | |
14086 rettv->v_type = VAR_STRING; | |
14087 p = get_tv_string_chk(&argvars[0]); | |
14088 if (p == NULL) | |
14089 rettv->vval.v_string = NULL; | |
14090 else | |
14091 { | |
14092 p = vim_strsave(p); | |
14093 rettv->vval.v_string = p; | |
14094 if (p != NULL) | |
14095 shorten_dir(p); | |
14096 } | |
14097 } | |
14098 | |
14099 #ifdef FEAT_PERL | |
14100 /* | |
14101 * "perleval()" function | |
14102 */ | |
14103 static void | |
14104 f_perleval(typval_T *argvars, typval_T *rettv) | |
14105 { | |
14106 char_u *str; | |
14107 char_u buf[NUMBUFLEN]; | |
14108 | |
14109 str = get_tv_string_buf(&argvars[0], buf); | |
14110 do_perleval(str, rettv); | |
14111 } | |
14112 #endif | |
14113 | |
14114 #ifdef FEAT_FLOAT | |
14115 /* | |
14116 * "pow()" function | |
14117 */ | |
14118 static void | |
14119 f_pow(typval_T *argvars, typval_T *rettv) | |
14120 { | |
14121 float_T fx = 0.0, fy = 0.0; | |
14122 | |
14123 rettv->v_type = VAR_FLOAT; | |
14124 if (get_float_arg(argvars, &fx) == OK | |
14125 && get_float_arg(&argvars[1], &fy) == OK) | |
14126 rettv->vval.v_float = pow(fx, fy); | |
14127 else | |
14128 rettv->vval.v_float = 0.0; | |
14129 } | |
14130 #endif | |
14131 | |
14132 /* | |
14133 * "prevnonblank()" function | |
14134 */ | |
14135 static void | |
14136 f_prevnonblank(typval_T *argvars, typval_T *rettv) | |
14137 { | |
14138 linenr_T lnum; | |
14139 | |
14140 lnum = get_tv_lnum(argvars); | |
14141 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) | |
14142 lnum = 0; | |
14143 else | |
14144 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL) | |
14145 --lnum; | |
14146 rettv->vval.v_number = lnum; | |
14147 } | |
14148 | |
14149 /* This dummy va_list is here because: | |
14150 * - passing a NULL pointer doesn't work when va_list isn't a pointer | |
14151 * - locally in the function results in a "used before set" warning | |
14152 * - using va_start() to initialize it gives "function with fixed args" error */ | |
14153 static va_list ap; | |
14154 | |
14155 /* | |
14156 * "printf()" function | |
14157 */ | |
14158 static void | |
14159 f_printf(typval_T *argvars, typval_T *rettv) | |
14160 { | |
14161 char_u buf[NUMBUFLEN]; | |
14162 int len; | |
14163 char_u *s; | |
14164 int saved_did_emsg = did_emsg; | |
14165 char *fmt; | |
14166 | |
14167 rettv->v_type = VAR_STRING; | |
14168 rettv->vval.v_string = NULL; | |
14169 | |
14170 /* Get the required length, allocate the buffer and do it for real. */ | |
14171 did_emsg = FALSE; | |
14172 fmt = (char *)get_tv_string_buf(&argvars[0], buf); | |
14173 len = vim_vsnprintf(NULL, 0, fmt, ap, argvars + 1); | |
14174 if (!did_emsg) | |
14175 { | |
14176 s = alloc(len + 1); | |
14177 if (s != NULL) | |
14178 { | |
14179 rettv->vval.v_string = s; | |
14180 (void)vim_vsnprintf((char *)s, len + 1, fmt, ap, argvars + 1); | |
14181 } | |
14182 } | |
14183 did_emsg |= saved_did_emsg; | |
14184 } | |
14185 | |
14186 /* | |
14187 * "pumvisible()" function | |
14188 */ | |
14189 static void | |
14190 f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
14191 { | |
14192 #ifdef FEAT_INS_EXPAND | |
14193 if (pum_visible()) | |
14194 rettv->vval.v_number = 1; | |
14195 #endif | |
14196 } | |
14197 | |
14198 #ifdef FEAT_PYTHON3 | |
14199 /* | |
14200 * "py3eval()" function | |
14201 */ | |
14202 static void | |
14203 f_py3eval(typval_T *argvars, typval_T *rettv) | |
14204 { | |
14205 char_u *str; | |
14206 char_u buf[NUMBUFLEN]; | |
14207 | |
14208 str = get_tv_string_buf(&argvars[0], buf); | |
14209 do_py3eval(str, rettv); | |
14210 } | |
14211 #endif | |
14212 | |
14213 #ifdef FEAT_PYTHON | |
14214 /* | |
14215 * "pyeval()" function | |
14216 */ | |
14217 static void | |
14218 f_pyeval(typval_T *argvars, typval_T *rettv) | |
14219 { | |
14220 char_u *str; | |
14221 char_u buf[NUMBUFLEN]; | |
14222 | |
14223 str = get_tv_string_buf(&argvars[0], buf); | |
14224 do_pyeval(str, rettv); | |
14225 } | |
14226 #endif | |
14227 | |
14228 /* | |
14229 * "range()" function | |
14230 */ | |
14231 static void | |
14232 f_range(typval_T *argvars, typval_T *rettv) | |
14233 { | |
14234 varnumber_T start; | |
14235 varnumber_T end; | |
14236 varnumber_T stride = 1; | |
14237 varnumber_T i; | |
14238 int error = FALSE; | |
14239 | |
14240 start = get_tv_number_chk(&argvars[0], &error); | |
14241 if (argvars[1].v_type == VAR_UNKNOWN) | |
14242 { | |
14243 end = start - 1; | |
14244 start = 0; | |
14245 } | |
14246 else | |
14247 { | |
14248 end = get_tv_number_chk(&argvars[1], &error); | |
14249 if (argvars[2].v_type != VAR_UNKNOWN) | |
14250 stride = get_tv_number_chk(&argvars[2], &error); | |
14251 } | |
14252 | |
14253 if (error) | |
14254 return; /* type error; errmsg already given */ | |
14255 if (stride == 0) | |
14256 EMSG(_("E726: Stride is zero")); | |
14257 else if (stride > 0 ? end + 1 < start : end - 1 > start) | |
14258 EMSG(_("E727: Start past end")); | |
14259 else | |
14260 { | |
14261 if (rettv_list_alloc(rettv) == OK) | |
14262 for (i = start; stride > 0 ? i <= end : i >= end; i += stride) | |
14263 if (list_append_number(rettv->vval.v_list, | |
14264 (varnumber_T)i) == FAIL) | |
14265 break; | |
14266 } | |
14267 } | |
14268 | |
14269 /* | |
14270 * "readfile()" function | |
14271 */ | |
14272 static void | |
14273 f_readfile(typval_T *argvars, typval_T *rettv) | |
14274 { | |
14275 int binary = FALSE; | |
14276 int failed = FALSE; | |
14277 char_u *fname; | |
14278 FILE *fd; | |
14279 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */ | |
14280 int io_size = sizeof(buf); | |
14281 int readlen; /* size of last fread() */ | |
14282 char_u *prev = NULL; /* previously read bytes, if any */ | |
14283 long prevlen = 0; /* length of data in prev */ | |
14284 long prevsize = 0; /* size of prev buffer */ | |
14285 long maxline = MAXLNUM; | |
14286 long cnt = 0; | |
14287 char_u *p; /* position in buf */ | |
14288 char_u *start; /* start of current line */ | |
14289 | |
14290 if (argvars[1].v_type != VAR_UNKNOWN) | |
14291 { | |
14292 if (STRCMP(get_tv_string(&argvars[1]), "b") == 0) | |
14293 binary = TRUE; | |
14294 if (argvars[2].v_type != VAR_UNKNOWN) | |
14295 maxline = (long)get_tv_number(&argvars[2]); | |
14296 } | |
14297 | |
14298 if (rettv_list_alloc(rettv) == FAIL) | |
14299 return; | |
14300 | |
14301 /* Always open the file in binary mode, library functions have a mind of | |
14302 * their own about CR-LF conversion. */ | |
14303 fname = get_tv_string(&argvars[0]); | |
14304 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL) | |
14305 { | |
14306 EMSG2(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname); | |
14307 return; | |
14308 } | |
14309 | |
14310 while (cnt < maxline || maxline < 0) | |
14311 { | |
14312 readlen = (int)fread(buf, 1, io_size, fd); | |
14313 | |
14314 /* This for loop processes what was read, but is also entered at end | |
14315 * of file so that either: | |
14316 * - an incomplete line gets written | |
14317 * - a "binary" file gets an empty line at the end if it ends in a | |
14318 * newline. */ | |
14319 for (p = buf, start = buf; | |
14320 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary)); | |
14321 ++p) | |
14322 { | |
14323 if (*p == '\n' || readlen <= 0) | |
14324 { | |
14325 listitem_T *li; | |
14326 char_u *s = NULL; | |
14327 long_u len = p - start; | |
14328 | |
14329 /* Finished a line. Remove CRs before NL. */ | |
14330 if (readlen > 0 && !binary) | |
14331 { | |
14332 while (len > 0 && start[len - 1] == '\r') | |
14333 --len; | |
14334 /* removal may cross back to the "prev" string */ | |
14335 if (len == 0) | |
14336 while (prevlen > 0 && prev[prevlen - 1] == '\r') | |
14337 --prevlen; | |
14338 } | |
14339 if (prevlen == 0) | |
14340 s = vim_strnsave(start, (int)len); | |
14341 else | |
14342 { | |
14343 /* Change "prev" buffer to be the right size. This way | |
14344 * the bytes are only copied once, and very long lines are | |
14345 * allocated only once. */ | |
14346 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL) | |
14347 { | |
14348 mch_memmove(s + prevlen, start, len); | |
14349 s[prevlen + len] = NUL; | |
14350 prev = NULL; /* the list will own the string */ | |
14351 prevlen = prevsize = 0; | |
14352 } | |
14353 } | |
14354 if (s == NULL) | |
14355 { | |
14356 do_outofmem_msg((long_u) prevlen + len + 1); | |
14357 failed = TRUE; | |
14358 break; | |
14359 } | |
14360 | |
14361 if ((li = listitem_alloc()) == NULL) | |
14362 { | |
14363 vim_free(s); | |
14364 failed = TRUE; | |
14365 break; | |
14366 } | |
14367 li->li_tv.v_type = VAR_STRING; | |
14368 li->li_tv.v_lock = 0; | |
14369 li->li_tv.vval.v_string = s; | |
14370 list_append(rettv->vval.v_list, li); | |
14371 | |
14372 start = p + 1; /* step over newline */ | |
14373 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0) | |
14374 break; | |
14375 } | |
14376 else if (*p == NUL) | |
14377 *p = '\n'; | |
14378 #ifdef FEAT_MBYTE | |
14379 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this | |
14380 * when finding the BF and check the previous two bytes. */ | |
14381 else if (*p == 0xbf && enc_utf8 && !binary) | |
14382 { | |
14383 /* Find the two bytes before the 0xbf. If p is at buf, or buf | |
14384 * + 1, these may be in the "prev" string. */ | |
14385 char_u back1 = p >= buf + 1 ? p[-1] | |
14386 : prevlen >= 1 ? prev[prevlen - 1] : NUL; | |
14387 char_u back2 = p >= buf + 2 ? p[-2] | |
14388 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1] | |
14389 : prevlen >= 2 ? prev[prevlen - 2] : NUL; | |
14390 | |
14391 if (back2 == 0xef && back1 == 0xbb) | |
14392 { | |
14393 char_u *dest = p - 2; | |
14394 | |
14395 /* Usually a BOM is at the beginning of a file, and so at | |
14396 * the beginning of a line; then we can just step over it. | |
14397 */ | |
14398 if (start == dest) | |
14399 start = p + 1; | |
14400 else | |
14401 { | |
14402 /* have to shuffle buf to close gap */ | |
14403 int adjust_prevlen = 0; | |
14404 | |
14405 if (dest < buf) | |
14406 { | |
14407 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */ | |
14408 dest = buf; | |
14409 } | |
14410 if (readlen > p - buf + 1) | |
14411 mch_memmove(dest, p + 1, readlen - (p - buf) - 1); | |
14412 readlen -= 3 - adjust_prevlen; | |
14413 prevlen -= adjust_prevlen; | |
14414 p = dest - 1; | |
14415 } | |
14416 } | |
14417 } | |
14418 #endif | |
14419 } /* for */ | |
14420 | |
14421 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0) | |
14422 break; | |
14423 if (start < p) | |
14424 { | |
14425 /* There's part of a line in buf, store it in "prev". */ | |
14426 if (p - start + prevlen >= prevsize) | |
14427 { | |
14428 /* need bigger "prev" buffer */ | |
14429 char_u *newprev; | |
14430 | |
14431 /* A common use case is ordinary text files and "prev" gets a | |
14432 * fragment of a line, so the first allocation is made | |
14433 * small, to avoid repeatedly 'allocing' large and | |
14434 * 'reallocing' small. */ | |
14435 if (prevsize == 0) | |
14436 prevsize = (long)(p - start); | |
14437 else | |
14438 { | |
14439 long grow50pc = (prevsize * 3) / 2; | |
14440 long growmin = (long)((p - start) * 2 + prevlen); | |
14441 prevsize = grow50pc > growmin ? grow50pc : growmin; | |
14442 } | |
14443 newprev = prev == NULL ? alloc(prevsize) | |
14444 : vim_realloc(prev, prevsize); | |
14445 if (newprev == NULL) | |
14446 { | |
14447 do_outofmem_msg((long_u)prevsize); | |
14448 failed = TRUE; | |
14449 break; | |
14450 } | |
14451 prev = newprev; | |
14452 } | |
14453 /* Add the line part to end of "prev". */ | |
14454 mch_memmove(prev + prevlen, start, p - start); | |
14455 prevlen += (long)(p - start); | |
14456 } | |
14457 } /* while */ | |
14458 | |
14459 /* | |
14460 * For a negative line count use only the lines at the end of the file, | |
14461 * free the rest. | |
14462 */ | |
14463 if (!failed && maxline < 0) | |
14464 while (cnt > -maxline) | |
14465 { | |
14466 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first); | |
14467 --cnt; | |
14468 } | |
14469 | |
14470 if (failed) | |
14471 { | |
14472 list_free(rettv->vval.v_list); | |
14473 /* readfile doc says an empty list is returned on error */ | |
14474 rettv->vval.v_list = list_alloc(); | |
14475 } | |
14476 | |
14477 vim_free(prev); | |
14478 fclose(fd); | |
14479 } | |
14480 | |
14481 #if defined(FEAT_RELTIME) | |
14482 static int list2proftime(typval_T *arg, proftime_T *tm); | |
14483 | |
14484 /* | |
14485 * Convert a List to proftime_T. | |
14486 * Return FAIL when there is something wrong. | |
14487 */ | |
14488 static int | |
14489 list2proftime(typval_T *arg, proftime_T *tm) | |
14490 { | |
14491 long n1, n2; | |
14492 int error = FALSE; | |
14493 | |
14494 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL | |
14495 || arg->vval.v_list->lv_len != 2) | |
14496 return FAIL; | |
14497 n1 = list_find_nr(arg->vval.v_list, 0L, &error); | |
14498 n2 = list_find_nr(arg->vval.v_list, 1L, &error); | |
14499 # ifdef WIN3264 | |
14500 tm->HighPart = n1; | |
14501 tm->LowPart = n2; | |
14502 # else | |
14503 tm->tv_sec = n1; | |
14504 tm->tv_usec = n2; | |
14505 # endif | |
14506 return error ? FAIL : OK; | |
14507 } | |
14508 #endif /* FEAT_RELTIME */ | |
14509 | |
14510 /* | |
14511 * "reltime()" function | |
14512 */ | |
14513 static void | |
14514 f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
14515 { | |
14516 #ifdef FEAT_RELTIME | |
14517 proftime_T res; | |
14518 proftime_T start; | |
14519 | |
14520 if (argvars[0].v_type == VAR_UNKNOWN) | |
14521 { | |
14522 /* No arguments: get current time. */ | |
14523 profile_start(&res); | |
14524 } | |
14525 else if (argvars[1].v_type == VAR_UNKNOWN) | |
14526 { | |
14527 if (list2proftime(&argvars[0], &res) == FAIL) | |
14528 return; | |
14529 profile_end(&res); | |
14530 } | |
14531 else | |
14532 { | |
14533 /* Two arguments: compute the difference. */ | |
14534 if (list2proftime(&argvars[0], &start) == FAIL | |
14535 || list2proftime(&argvars[1], &res) == FAIL) | |
14536 return; | |
14537 profile_sub(&res, &start); | |
14538 } | |
14539 | |
14540 if (rettv_list_alloc(rettv) == OK) | |
14541 { | |
14542 long n1, n2; | |
14543 | |
14544 # ifdef WIN3264 | |
14545 n1 = res.HighPart; | |
14546 n2 = res.LowPart; | |
14547 # else | |
14548 n1 = res.tv_sec; | |
14549 n2 = res.tv_usec; | |
14550 # endif | |
14551 list_append_number(rettv->vval.v_list, (varnumber_T)n1); | |
14552 list_append_number(rettv->vval.v_list, (varnumber_T)n2); | |
14553 } | |
14554 #endif | |
14555 } | |
14556 | |
14557 #ifdef FEAT_FLOAT | |
14558 /* | |
14559 * "reltimefloat()" function | |
14560 */ | |
14561 static void | |
14562 f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) | |
14563 { | |
14564 # ifdef FEAT_RELTIME | |
14565 proftime_T tm; | |
14566 # endif | |
14567 | |
14568 rettv->v_type = VAR_FLOAT; | |
14569 rettv->vval.v_float = 0; | |
14570 # ifdef FEAT_RELTIME | |
14571 if (list2proftime(&argvars[0], &tm) == OK) | |
14572 rettv->vval.v_float = profile_float(&tm); | |
14573 # endif | |
14574 } | |
14575 #endif | |
14576 | |
14577 /* | |
14578 * "reltimestr()" function | |
14579 */ | |
14580 static void | |
14581 f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) | |
14582 { | |
14583 #ifdef FEAT_RELTIME | |
14584 proftime_T tm; | |
14585 #endif | |
14586 | |
14587 rettv->v_type = VAR_STRING; | |
14588 rettv->vval.v_string = NULL; | |
14589 #ifdef FEAT_RELTIME | |
14590 if (list2proftime(&argvars[0], &tm) == OK) | |
14591 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); | |
14592 #endif | |
14593 } | |
14594 | |
14595 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) | |
14596 static void make_connection(void); | |
14597 static int check_connection(void); | |
14598 | |
14599 static void | |
14600 make_connection(void) | |
14601 { | |
14602 if (X_DISPLAY == NULL | |
14603 # ifdef FEAT_GUI | |
14604 && !gui.in_use | |
14605 # endif | |
14606 ) | |
14607 { | |
14608 x_force_connect = TRUE; | |
14609 setup_term_clip(); | |
14610 x_force_connect = FALSE; | |
14611 } | |
14612 } | |
14613 | |
14614 static int | |
14615 check_connection(void) | |
14616 { | |
14617 make_connection(); | |
14618 if (X_DISPLAY == NULL) | |
14619 { | |
14620 EMSG(_("E240: No connection to Vim server")); | |
14621 return FAIL; | |
14622 } | |
14623 return OK; | |
14624 } | |
14625 #endif | |
14626 | |
14627 #ifdef FEAT_CLIENTSERVER | |
14628 static void | |
14629 remote_common(typval_T *argvars, typval_T *rettv, int expr) | |
14630 { | |
14631 char_u *server_name; | |
14632 char_u *keys; | |
14633 char_u *r = NULL; | |
14634 char_u buf[NUMBUFLEN]; | |
14635 # ifdef WIN32 | |
14636 HWND w; | |
14637 # else | |
14638 Window w; | |
14639 # endif | |
14640 | |
14641 if (check_restricted() || check_secure()) | |
14642 return; | |
14643 | |
14644 # ifdef FEAT_X11 | |
14645 if (check_connection() == FAIL) | |
14646 return; | |
14647 # endif | |
14648 | |
14649 server_name = get_tv_string_chk(&argvars[0]); | |
14650 if (server_name == NULL) | |
14651 return; /* type error; errmsg already given */ | |
14652 keys = get_tv_string_buf(&argvars[1], buf); | |
14653 # ifdef WIN32 | |
14654 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0) | |
14655 # else | |
14656 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE) | |
14657 < 0) | |
14658 # endif | |
14659 { | |
14660 if (r != NULL) | |
14661 EMSG(r); /* sending worked but evaluation failed */ | |
14662 else | |
14663 EMSG2(_("E241: Unable to send to %s"), server_name); | |
14664 return; | |
14665 } | |
14666 | |
14667 rettv->vval.v_string = r; | |
14668 | |
14669 if (argvars[2].v_type != VAR_UNKNOWN) | |
14670 { | |
14671 dictitem_T v; | |
14672 char_u str[30]; | |
14673 char_u *idvar; | |
14674 | |
14675 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w); | |
14676 v.di_tv.v_type = VAR_STRING; | |
14677 v.di_tv.vval.v_string = vim_strsave(str); | |
14678 idvar = get_tv_string_chk(&argvars[2]); | |
14679 if (idvar != NULL) | |
14680 set_var(idvar, &v.di_tv, FALSE); | |
14681 vim_free(v.di_tv.vval.v_string); | |
14682 } | |
14683 } | |
14684 #endif | |
14685 | |
14686 /* | |
14687 * "remote_expr()" function | |
14688 */ | |
14689 static void | |
14690 f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv) | |
14691 { | |
14692 rettv->v_type = VAR_STRING; | |
14693 rettv->vval.v_string = NULL; | |
14694 #ifdef FEAT_CLIENTSERVER | |
14695 remote_common(argvars, rettv, TRUE); | |
14696 #endif | |
14697 } | |
14698 | |
14699 /* | |
14700 * "remote_foreground()" function | |
14701 */ | |
14702 static void | |
14703 f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
14704 { | |
14705 #ifdef FEAT_CLIENTSERVER | |
14706 # ifdef WIN32 | |
14707 /* On Win32 it's done in this application. */ | |
14708 { | |
14709 char_u *server_name = get_tv_string_chk(&argvars[0]); | |
14710 | |
14711 if (server_name != NULL) | |
14712 serverForeground(server_name); | |
14713 } | |
14714 # else | |
14715 /* Send a foreground() expression to the server. */ | |
14716 argvars[1].v_type = VAR_STRING; | |
14717 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()"); | |
14718 argvars[2].v_type = VAR_UNKNOWN; | |
14719 remote_common(argvars, rettv, TRUE); | |
14720 vim_free(argvars[1].vval.v_string); | |
14721 # endif | |
14722 #endif | |
14723 } | |
14724 | |
14725 static void | |
14726 f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv) | |
14727 { | |
14728 #ifdef FEAT_CLIENTSERVER | |
14729 dictitem_T v; | |
14730 char_u *s = NULL; | |
14731 # ifdef WIN32 | |
14732 long_u n = 0; | |
14733 # endif | |
14734 char_u *serverid; | |
14735 | |
14736 if (check_restricted() || check_secure()) | |
14737 { | |
14738 rettv->vval.v_number = -1; | |
14739 return; | |
14740 } | |
14741 serverid = get_tv_string_chk(&argvars[0]); | |
14742 if (serverid == NULL) | |
14743 { | |
14744 rettv->vval.v_number = -1; | |
14745 return; /* type error; errmsg already given */ | |
14746 } | |
14747 # ifdef WIN32 | |
14748 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n); | |
14749 if (n == 0) | |
14750 rettv->vval.v_number = -1; | |
14751 else | |
14752 { | |
14753 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE); | |
14754 rettv->vval.v_number = (s != NULL); | |
14755 } | |
14756 # else | |
14757 if (check_connection() == FAIL) | |
14758 return; | |
14759 | |
14760 rettv->vval.v_number = serverPeekReply(X_DISPLAY, | |
14761 serverStrToWin(serverid), &s); | |
14762 # endif | |
14763 | |
14764 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0) | |
14765 { | |
14766 char_u *retvar; | |
14767 | |
14768 v.di_tv.v_type = VAR_STRING; | |
14769 v.di_tv.vval.v_string = vim_strsave(s); | |
14770 retvar = get_tv_string_chk(&argvars[1]); | |
14771 if (retvar != NULL) | |
14772 set_var(retvar, &v.di_tv, FALSE); | |
14773 vim_free(v.di_tv.vval.v_string); | |
14774 } | |
14775 #else | |
14776 rettv->vval.v_number = -1; | |
14777 #endif | |
14778 } | |
14779 | |
14780 static void | |
14781 f_remote_read(typval_T *argvars UNUSED, typval_T *rettv) | |
14782 { | |
14783 char_u *r = NULL; | |
14784 | |
14785 #ifdef FEAT_CLIENTSERVER | |
14786 char_u *serverid = get_tv_string_chk(&argvars[0]); | |
14787 | |
14788 if (serverid != NULL && !check_restricted() && !check_secure()) | |
14789 { | |
14790 # ifdef WIN32 | |
14791 /* The server's HWND is encoded in the 'id' parameter */ | |
14792 long_u n = 0; | |
14793 | |
14794 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n); | |
14795 if (n != 0) | |
14796 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE); | |
14797 if (r == NULL) | |
14798 # else | |
14799 if (check_connection() == FAIL || serverReadReply(X_DISPLAY, | |
14800 serverStrToWin(serverid), &r, FALSE) < 0) | |
14801 # endif | |
14802 EMSG(_("E277: Unable to read a server reply")); | |
14803 } | |
14804 #endif | |
14805 rettv->v_type = VAR_STRING; | |
14806 rettv->vval.v_string = r; | |
14807 } | |
14808 | |
14809 /* | |
14810 * "remote_send()" function | |
14811 */ | |
14812 static void | |
14813 f_remote_send(typval_T *argvars UNUSED, typval_T *rettv) | |
14814 { | |
14815 rettv->v_type = VAR_STRING; | |
14816 rettv->vval.v_string = NULL; | |
14817 #ifdef FEAT_CLIENTSERVER | |
14818 remote_common(argvars, rettv, FALSE); | |
14819 #endif | |
14820 } | |
14821 | |
14822 /* | |
14823 * "remove()" function | |
14824 */ | |
14825 static void | |
14826 f_remove(typval_T *argvars, typval_T *rettv) | |
14827 { | |
14828 list_T *l; | |
14829 listitem_T *item, *item2; | |
14830 listitem_T *li; | |
14831 long idx; | |
14832 long end; | |
14833 char_u *key; | |
14834 dict_T *d; | |
14835 dictitem_T *di; | |
14836 char_u *arg_errmsg = (char_u *)N_("remove() argument"); | |
14837 | |
14838 if (argvars[0].v_type == VAR_DICT) | |
14839 { | |
14840 if (argvars[2].v_type != VAR_UNKNOWN) | |
14841 EMSG2(_(e_toomanyarg), "remove()"); | |
14842 else if ((d = argvars[0].vval.v_dict) != NULL | |
14843 && !tv_check_lock(d->dv_lock, arg_errmsg, TRUE)) | |
14844 { | |
14845 key = get_tv_string_chk(&argvars[1]); | |
14846 if (key != NULL) | |
14847 { | |
14848 di = dict_find(d, key, -1); | |
14849 if (di == NULL) | |
14850 EMSG2(_(e_dictkey), key); | |
14851 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE) | |
14852 && !var_check_ro(di->di_flags, arg_errmsg, TRUE)) | |
14853 { | |
14854 *rettv = di->di_tv; | |
14855 init_tv(&di->di_tv); | |
14856 dictitem_remove(d, di); | |
14857 } | |
14858 } | |
14859 } | |
14860 } | |
14861 else if (argvars[0].v_type != VAR_LIST) | |
14862 EMSG2(_(e_listdictarg), "remove()"); | |
14863 else if ((l = argvars[0].vval.v_list) != NULL | |
14864 && !tv_check_lock(l->lv_lock, arg_errmsg, TRUE)) | |
14865 { | |
14866 int error = FALSE; | |
14867 | |
14868 idx = (long)get_tv_number_chk(&argvars[1], &error); | |
14869 if (error) | |
14870 ; /* type error: do nothing, errmsg already given */ | |
14871 else if ((item = list_find(l, idx)) == NULL) | |
14872 EMSGN(_(e_listidx), idx); | |
14873 else | |
14874 { | |
14875 if (argvars[2].v_type == VAR_UNKNOWN) | |
14876 { | |
14877 /* Remove one item, return its value. */ | |
14878 vimlist_remove(l, item, item); | |
14879 *rettv = item->li_tv; | |
14880 vim_free(item); | |
14881 } | |
14882 else | |
14883 { | |
14884 /* Remove range of items, return list with values. */ | |
14885 end = (long)get_tv_number_chk(&argvars[2], &error); | |
14886 if (error) | |
14887 ; /* type error: do nothing */ | |
14888 else if ((item2 = list_find(l, end)) == NULL) | |
14889 EMSGN(_(e_listidx), end); | |
14890 else | |
14891 { | |
14892 int cnt = 0; | |
14893 | |
14894 for (li = item; li != NULL; li = li->li_next) | |
14895 { | |
14896 ++cnt; | |
14897 if (li == item2) | |
14898 break; | |
14899 } | |
14900 if (li == NULL) /* didn't find "item2" after "item" */ | |
14901 EMSG(_(e_invrange)); | |
14902 else | |
14903 { | |
14904 vimlist_remove(l, item, item2); | |
14905 if (rettv_list_alloc(rettv) == OK) | |
14906 { | |
14907 l = rettv->vval.v_list; | |
14908 l->lv_first = item; | |
14909 l->lv_last = item2; | |
14910 item->li_prev = NULL; | |
14911 item2->li_next = NULL; | |
14912 l->lv_len = cnt; | |
14913 } | |
14914 } | |
14915 } | |
14916 } | |
14917 } | |
14918 } | |
14919 } | |
14920 | |
14921 /* | |
14922 * "rename({from}, {to})" function | |
14923 */ | |
14924 static void | |
14925 f_rename(typval_T *argvars, typval_T *rettv) | |
14926 { | |
14927 char_u buf[NUMBUFLEN]; | |
14928 | |
14929 if (check_restricted() || check_secure()) | |
14930 rettv->vval.v_number = -1; | |
14931 else | |
14932 rettv->vval.v_number = vim_rename(get_tv_string(&argvars[0]), | |
14933 get_tv_string_buf(&argvars[1], buf)); | |
14934 } | |
14935 | |
14936 /* | |
14937 * "repeat()" function | |
14938 */ | |
14939 static void | |
14940 f_repeat(typval_T *argvars, typval_T *rettv) | |
14941 { | |
14942 char_u *p; | |
14943 int n; | |
14944 int slen; | |
14945 int len; | |
14946 char_u *r; | |
14947 int i; | |
14948 | |
14949 n = (int)get_tv_number(&argvars[1]); | |
14950 if (argvars[0].v_type == VAR_LIST) | |
14951 { | |
14952 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL) | |
14953 while (n-- > 0) | |
14954 if (list_extend(rettv->vval.v_list, | |
14955 argvars[0].vval.v_list, NULL) == FAIL) | |
14956 break; | |
14957 } | |
14958 else | |
14959 { | |
14960 p = get_tv_string(&argvars[0]); | |
14961 rettv->v_type = VAR_STRING; | |
14962 rettv->vval.v_string = NULL; | |
14963 | |
14964 slen = (int)STRLEN(p); | |
14965 len = slen * n; | |
14966 if (len <= 0) | |
14967 return; | |
14968 | |
14969 r = alloc(len + 1); | |
14970 if (r != NULL) | |
14971 { | |
14972 for (i = 0; i < n; i++) | |
14973 mch_memmove(r + i * slen, p, (size_t)slen); | |
14974 r[len] = NUL; | |
14975 } | |
14976 | |
14977 rettv->vval.v_string = r; | |
14978 } | |
14979 } | |
14980 | |
14981 /* | |
14982 * "resolve()" function | |
14983 */ | |
14984 static void | |
14985 f_resolve(typval_T *argvars, typval_T *rettv) | |
14986 { | |
14987 char_u *p; | |
14988 #ifdef HAVE_READLINK | |
14989 char_u *buf = NULL; | |
14990 #endif | |
14991 | |
14992 p = get_tv_string(&argvars[0]); | |
14993 #ifdef FEAT_SHORTCUT | |
14994 { | |
14995 char_u *v = NULL; | |
14996 | |
14997 v = mch_resolve_shortcut(p); | |
14998 if (v != NULL) | |
14999 rettv->vval.v_string = v; | |
15000 else | |
15001 rettv->vval.v_string = vim_strsave(p); | |
15002 } | |
15003 #else | |
15004 # ifdef HAVE_READLINK | |
15005 { | |
15006 char_u *cpy; | |
15007 int len; | |
15008 char_u *remain = NULL; | |
15009 char_u *q; | |
15010 int is_relative_to_current = FALSE; | |
15011 int has_trailing_pathsep = FALSE; | |
15012 int limit = 100; | |
15013 | |
15014 p = vim_strsave(p); | |
15015 | |
15016 if (p[0] == '.' && (vim_ispathsep(p[1]) | |
15017 || (p[1] == '.' && (vim_ispathsep(p[2]))))) | |
15018 is_relative_to_current = TRUE; | |
15019 | |
15020 len = STRLEN(p); | |
15021 if (len > 0 && after_pathsep(p, p + len)) | |
15022 { | |
15023 has_trailing_pathsep = TRUE; | |
15024 p[len - 1] = NUL; /* the trailing slash breaks readlink() */ | |
15025 } | |
15026 | |
15027 q = getnextcomp(p); | |
15028 if (*q != NUL) | |
15029 { | |
15030 /* Separate the first path component in "p", and keep the | |
15031 * remainder (beginning with the path separator). */ | |
15032 remain = vim_strsave(q - 1); | |
15033 q[-1] = NUL; | |
15034 } | |
15035 | |
15036 buf = alloc(MAXPATHL + 1); | |
15037 if (buf == NULL) | |
15038 goto fail; | |
15039 | |
15040 for (;;) | |
15041 { | |
15042 for (;;) | |
15043 { | |
15044 len = readlink((char *)p, (char *)buf, MAXPATHL); | |
15045 if (len <= 0) | |
15046 break; | |
15047 buf[len] = NUL; | |
15048 | |
15049 if (limit-- == 0) | |
15050 { | |
15051 vim_free(p); | |
15052 vim_free(remain); | |
15053 EMSG(_("E655: Too many symbolic links (cycle?)")); | |
15054 rettv->vval.v_string = NULL; | |
15055 goto fail; | |
15056 } | |
15057 | |
15058 /* Ensure that the result will have a trailing path separator | |
15059 * if the argument has one. */ | |
15060 if (remain == NULL && has_trailing_pathsep) | |
15061 add_pathsep(buf); | |
15062 | |
15063 /* Separate the first path component in the link value and | |
15064 * concatenate the remainders. */ | |
15065 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf); | |
15066 if (*q != NUL) | |
15067 { | |
15068 if (remain == NULL) | |
15069 remain = vim_strsave(q - 1); | |
15070 else | |
15071 { | |
15072 cpy = concat_str(q - 1, remain); | |
15073 if (cpy != NULL) | |
15074 { | |
15075 vim_free(remain); | |
15076 remain = cpy; | |
15077 } | |
15078 } | |
15079 q[-1] = NUL; | |
15080 } | |
15081 | |
15082 q = gettail(p); | |
15083 if (q > p && *q == NUL) | |
15084 { | |
15085 /* Ignore trailing path separator. */ | |
15086 q[-1] = NUL; | |
15087 q = gettail(p); | |
15088 } | |
15089 if (q > p && !mch_isFullName(buf)) | |
15090 { | |
15091 /* symlink is relative to directory of argument */ | |
15092 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1)); | |
15093 if (cpy != NULL) | |
15094 { | |
15095 STRCPY(cpy, p); | |
15096 STRCPY(gettail(cpy), buf); | |
15097 vim_free(p); | |
15098 p = cpy; | |
15099 } | |
15100 } | |
15101 else | |
15102 { | |
15103 vim_free(p); | |
15104 p = vim_strsave(buf); | |
15105 } | |
15106 } | |
15107 | |
15108 if (remain == NULL) | |
15109 break; | |
15110 | |
15111 /* Append the first path component of "remain" to "p". */ | |
15112 q = getnextcomp(remain + 1); | |
15113 len = q - remain - (*q != NUL); | |
15114 cpy = vim_strnsave(p, STRLEN(p) + len); | |
15115 if (cpy != NULL) | |
15116 { | |
15117 STRNCAT(cpy, remain, len); | |
15118 vim_free(p); | |
15119 p = cpy; | |
15120 } | |
15121 /* Shorten "remain". */ | |
15122 if (*q != NUL) | |
15123 STRMOVE(remain, q - 1); | |
15124 else | |
15125 { | |
15126 vim_free(remain); | |
15127 remain = NULL; | |
15128 } | |
15129 } | |
15130 | |
15131 /* If the result is a relative path name, make it explicitly relative to | |
15132 * the current directory if and only if the argument had this form. */ | |
15133 if (!vim_ispathsep(*p)) | |
15134 { | |
15135 if (is_relative_to_current | |
15136 && *p != NUL | |
15137 && !(p[0] == '.' | |
15138 && (p[1] == NUL | |
15139 || vim_ispathsep(p[1]) | |
15140 || (p[1] == '.' | |
15141 && (p[2] == NUL | |
15142 || vim_ispathsep(p[2])))))) | |
15143 { | |
15144 /* Prepend "./". */ | |
15145 cpy = concat_str((char_u *)"./", p); | |
15146 if (cpy != NULL) | |
15147 { | |
15148 vim_free(p); | |
15149 p = cpy; | |
15150 } | |
15151 } | |
15152 else if (!is_relative_to_current) | |
15153 { | |
15154 /* Strip leading "./". */ | |
15155 q = p; | |
15156 while (q[0] == '.' && vim_ispathsep(q[1])) | |
15157 q += 2; | |
15158 if (q > p) | |
15159 STRMOVE(p, p + 2); | |
15160 } | |
15161 } | |
15162 | |
15163 /* Ensure that the result will have no trailing path separator | |
15164 * if the argument had none. But keep "/" or "//". */ | |
15165 if (!has_trailing_pathsep) | |
15166 { | |
15167 q = p + STRLEN(p); | |
15168 if (after_pathsep(p, q)) | |
15169 *gettail_sep(p) = NUL; | |
15170 } | |
15171 | |
15172 rettv->vval.v_string = p; | |
15173 } | |
15174 # else | |
15175 rettv->vval.v_string = vim_strsave(p); | |
15176 # endif | |
15177 #endif | |
15178 | |
15179 simplify_filename(rettv->vval.v_string); | |
15180 | |
15181 #ifdef HAVE_READLINK | |
15182 fail: | |
15183 vim_free(buf); | |
15184 #endif | |
15185 rettv->v_type = VAR_STRING; | |
15186 } | |
15187 | |
15188 /* | |
15189 * "reverse({list})" function | |
15190 */ | |
15191 static void | |
15192 f_reverse(typval_T *argvars, typval_T *rettv) | |
15193 { | |
15194 list_T *l; | |
15195 listitem_T *li, *ni; | |
15196 | |
15197 if (argvars[0].v_type != VAR_LIST) | |
15198 EMSG2(_(e_listarg), "reverse()"); | |
15199 else if ((l = argvars[0].vval.v_list) != NULL | |
15200 && !tv_check_lock(l->lv_lock, | |
15201 (char_u *)N_("reverse() argument"), TRUE)) | |
15202 { | |
15203 li = l->lv_last; | |
15204 l->lv_first = l->lv_last = NULL; | |
15205 l->lv_len = 0; | |
15206 while (li != NULL) | |
15207 { | |
15208 ni = li->li_prev; | |
15209 list_append(l, li); | |
15210 li = ni; | |
15211 } | |
15212 rettv->vval.v_list = l; | |
15213 rettv->v_type = VAR_LIST; | |
15214 ++l->lv_refcount; | |
15215 l->lv_idx = l->lv_len - l->lv_idx - 1; | |
15216 } | |
15217 } | |
15218 | |
15219 #define SP_NOMOVE 0x01 /* don't move cursor */ | |
15220 #define SP_REPEAT 0x02 /* repeat to find outer pair */ | |
15221 #define SP_RETCOUNT 0x04 /* return matchcount */ | |
15222 #define SP_SETPCMARK 0x08 /* set previous context mark */ | |
15223 #define SP_START 0x10 /* accept match at start position */ | |
15224 #define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */ | |
15225 #define SP_END 0x40 /* leave cursor at end of match */ | |
15226 #define SP_COLUMN 0x80 /* start at cursor column */ | |
15227 | |
15228 static int get_search_arg(typval_T *varp, int *flagsp); | |
15229 | |
15230 /* | |
15231 * Get flags for a search function. | |
15232 * Possibly sets "p_ws". | |
15233 * Returns BACKWARD, FORWARD or zero (for an error). | |
15234 */ | |
15235 static int | |
15236 get_search_arg(typval_T *varp, int *flagsp) | |
15237 { | |
15238 int dir = FORWARD; | |
15239 char_u *flags; | |
15240 char_u nbuf[NUMBUFLEN]; | |
15241 int mask; | |
15242 | |
15243 if (varp->v_type != VAR_UNKNOWN) | |
15244 { | |
15245 flags = get_tv_string_buf_chk(varp, nbuf); | |
15246 if (flags == NULL) | |
15247 return 0; /* type error; errmsg already given */ | |
15248 while (*flags != NUL) | |
15249 { | |
15250 switch (*flags) | |
15251 { | |
15252 case 'b': dir = BACKWARD; break; | |
15253 case 'w': p_ws = TRUE; break; | |
15254 case 'W': p_ws = FALSE; break; | |
15255 default: mask = 0; | |
15256 if (flagsp != NULL) | |
15257 switch (*flags) | |
15258 { | |
15259 case 'c': mask = SP_START; break; | |
15260 case 'e': mask = SP_END; break; | |
15261 case 'm': mask = SP_RETCOUNT; break; | |
15262 case 'n': mask = SP_NOMOVE; break; | |
15263 case 'p': mask = SP_SUBPAT; break; | |
15264 case 'r': mask = SP_REPEAT; break; | |
15265 case 's': mask = SP_SETPCMARK; break; | |
15266 case 'z': mask = SP_COLUMN; break; | |
15267 } | |
15268 if (mask == 0) | |
15269 { | |
15270 EMSG2(_(e_invarg2), flags); | |
15271 dir = 0; | |
15272 } | |
15273 else | |
15274 *flagsp |= mask; | |
15275 } | |
15276 if (dir == 0) | |
15277 break; | |
15278 ++flags; | |
15279 } | |
15280 } | |
15281 return dir; | |
15282 } | |
15283 | |
15284 /* | |
15285 * Shared by search() and searchpos() functions. | |
15286 */ | |
15287 static int | |
15288 search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) | |
15289 { | |
15290 int flags; | |
15291 char_u *pat; | |
15292 pos_T pos; | |
15293 pos_T save_cursor; | |
15294 int save_p_ws = p_ws; | |
15295 int dir; | |
15296 int retval = 0; /* default: FAIL */ | |
15297 long lnum_stop = 0; | |
15298 proftime_T tm; | |
15299 #ifdef FEAT_RELTIME | |
15300 long time_limit = 0; | |
15301 #endif | |
15302 int options = SEARCH_KEEP; | |
15303 int subpatnum; | |
15304 | |
15305 pat = get_tv_string(&argvars[0]); | |
15306 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */ | |
15307 if (dir == 0) | |
15308 goto theend; | |
15309 flags = *flagsp; | |
15310 if (flags & SP_START) | |
15311 options |= SEARCH_START; | |
15312 if (flags & SP_END) | |
15313 options |= SEARCH_END; | |
15314 if (flags & SP_COLUMN) | |
15315 options |= SEARCH_COL; | |
15316 | |
15317 /* Optional arguments: line number to stop searching and timeout. */ | |
15318 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) | |
15319 { | |
15320 lnum_stop = (long)get_tv_number_chk(&argvars[2], NULL); | |
15321 if (lnum_stop < 0) | |
15322 goto theend; | |
15323 #ifdef FEAT_RELTIME | |
15324 if (argvars[3].v_type != VAR_UNKNOWN) | |
15325 { | |
15326 time_limit = (long)get_tv_number_chk(&argvars[3], NULL); | |
15327 if (time_limit < 0) | |
15328 goto theend; | |
15329 } | |
15330 #endif | |
15331 } | |
15332 | |
15333 #ifdef FEAT_RELTIME | |
15334 /* Set the time limit, if there is one. */ | |
15335 profile_setlimit(time_limit, &tm); | |
15336 #endif | |
15337 | |
15338 /* | |
15339 * This function does not accept SP_REPEAT and SP_RETCOUNT flags. | |
15340 * Check to make sure only those flags are set. | |
15341 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both | |
15342 * flags cannot be set. Check for that condition also. | |
15343 */ | |
15344 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0) | |
15345 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) | |
15346 { | |
15347 EMSG2(_(e_invarg2), get_tv_string(&argvars[1])); | |
15348 goto theend; | |
15349 } | |
15350 | |
15351 pos = save_cursor = curwin->w_cursor; | |
15352 subpatnum = searchit(curwin, curbuf, &pos, dir, pat, 1L, | |
15353 options, RE_SEARCH, (linenr_T)lnum_stop, &tm); | |
15354 if (subpatnum != FAIL) | |
15355 { | |
15356 if (flags & SP_SUBPAT) | |
15357 retval = subpatnum; | |
15358 else | |
15359 retval = pos.lnum; | |
15360 if (flags & SP_SETPCMARK) | |
15361 setpcmark(); | |
15362 curwin->w_cursor = pos; | |
15363 if (match_pos != NULL) | |
15364 { | |
15365 /* Store the match cursor position */ | |
15366 match_pos->lnum = pos.lnum; | |
15367 match_pos->col = pos.col + 1; | |
15368 } | |
15369 /* "/$" will put the cursor after the end of the line, may need to | |
15370 * correct that here */ | |
15371 check_cursor(); | |
15372 } | |
15373 | |
15374 /* If 'n' flag is used: restore cursor position. */ | |
15375 if (flags & SP_NOMOVE) | |
15376 curwin->w_cursor = save_cursor; | |
15377 else | |
15378 curwin->w_set_curswant = TRUE; | |
15379 theend: | |
15380 p_ws = save_p_ws; | |
15381 | |
15382 return retval; | |
15383 } | |
15384 | |
15385 #ifdef FEAT_FLOAT | |
15386 | |
15387 /* | |
15388 * round() is not in C90, use ceil() or floor() instead. | |
15389 */ | |
15390 float_T | |
15391 vim_round(float_T f) | |
15392 { | |
15393 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5); | |
15394 } | |
15395 | |
15396 /* | |
15397 * "round({float})" function | |
15398 */ | |
15399 static void | |
15400 f_round(typval_T *argvars, typval_T *rettv) | |
15401 { | |
15402 float_T f = 0.0; | |
15403 | |
15404 rettv->v_type = VAR_FLOAT; | |
15405 if (get_float_arg(argvars, &f) == OK) | |
15406 rettv->vval.v_float = vim_round(f); | |
15407 else | |
15408 rettv->vval.v_float = 0.0; | |
15409 } | |
15410 #endif | |
15411 | |
15412 /* | |
15413 * "screenattr()" function | |
15414 */ | |
15415 static void | |
15416 f_screenattr(typval_T *argvars, typval_T *rettv) | |
15417 { | |
15418 int row; | |
15419 int col; | |
15420 int c; | |
15421 | |
15422 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; | |
15423 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; | |
15424 if (row < 0 || row >= screen_Rows | |
15425 || col < 0 || col >= screen_Columns) | |
15426 c = -1; | |
15427 else | |
15428 c = ScreenAttrs[LineOffset[row] + col]; | |
15429 rettv->vval.v_number = c; | |
15430 } | |
15431 | |
15432 /* | |
15433 * "screenchar()" function | |
15434 */ | |
15435 static void | |
15436 f_screenchar(typval_T *argvars, typval_T *rettv) | |
15437 { | |
15438 int row; | |
15439 int col; | |
15440 int off; | |
15441 int c; | |
15442 | |
15443 row = (int)get_tv_number_chk(&argvars[0], NULL) - 1; | |
15444 col = (int)get_tv_number_chk(&argvars[1], NULL) - 1; | |
15445 if (row < 0 || row >= screen_Rows | |
15446 || col < 0 || col >= screen_Columns) | |
15447 c = -1; | |
15448 else | |
15449 { | |
15450 off = LineOffset[row] + col; | |
15451 #ifdef FEAT_MBYTE | |
15452 if (enc_utf8 && ScreenLinesUC[off] != 0) | |
15453 c = ScreenLinesUC[off]; | |
15454 else | |
15455 #endif | |
15456 c = ScreenLines[off]; | |
15457 } | |
15458 rettv->vval.v_number = c; | |
15459 } | |
15460 | |
15461 /* | |
15462 * "screencol()" function | |
15463 * | |
15464 * First column is 1 to be consistent with virtcol(). | |
15465 */ | |
15466 static void | |
15467 f_screencol(typval_T *argvars UNUSED, typval_T *rettv) | |
15468 { | |
15469 rettv->vval.v_number = screen_screencol() + 1; | |
15470 } | |
15471 | |
15472 /* | |
15473 * "screenrow()" function | |
15474 */ | |
15475 static void | |
15476 f_screenrow(typval_T *argvars UNUSED, typval_T *rettv) | |
15477 { | |
15478 rettv->vval.v_number = screen_screenrow() + 1; | |
15479 } | |
15480 | |
15481 /* | |
15482 * "search()" function | |
15483 */ | |
15484 static void | |
15485 f_search(typval_T *argvars, typval_T *rettv) | |
15486 { | |
15487 int flags = 0; | |
15488 | |
15489 rettv->vval.v_number = search_cmn(argvars, NULL, &flags); | |
15490 } | |
15491 | |
15492 /* | |
15493 * "searchdecl()" function | |
15494 */ | |
15495 static void | |
15496 f_searchdecl(typval_T *argvars, typval_T *rettv) | |
15497 { | |
15498 int locally = 1; | |
15499 int thisblock = 0; | |
15500 int error = FALSE; | |
15501 char_u *name; | |
15502 | |
15503 rettv->vval.v_number = 1; /* default: FAIL */ | |
15504 | |
15505 name = get_tv_string_chk(&argvars[0]); | |
15506 if (argvars[1].v_type != VAR_UNKNOWN) | |
15507 { | |
15508 locally = (int)get_tv_number_chk(&argvars[1], &error) == 0; | |
15509 if (!error && argvars[2].v_type != VAR_UNKNOWN) | |
15510 thisblock = (int)get_tv_number_chk(&argvars[2], &error) != 0; | |
15511 } | |
15512 if (!error && name != NULL) | |
15513 rettv->vval.v_number = find_decl(name, (int)STRLEN(name), | |
15514 locally, thisblock, SEARCH_KEEP) == FAIL; | |
15515 } | |
15516 | |
15517 /* | |
15518 * Used by searchpair() and searchpairpos() | |
15519 */ | |
15520 static int | |
15521 searchpair_cmn(typval_T *argvars, pos_T *match_pos) | |
15522 { | |
15523 char_u *spat, *mpat, *epat; | |
15524 char_u *skip; | |
15525 int save_p_ws = p_ws; | |
15526 int dir; | |
15527 int flags = 0; | |
15528 char_u nbuf1[NUMBUFLEN]; | |
15529 char_u nbuf2[NUMBUFLEN]; | |
15530 char_u nbuf3[NUMBUFLEN]; | |
15531 int retval = 0; /* default: FAIL */ | |
15532 long lnum_stop = 0; | |
15533 long time_limit = 0; | |
15534 | |
15535 /* Get the three pattern arguments: start, middle, end. */ | |
15536 spat = get_tv_string_chk(&argvars[0]); | |
15537 mpat = get_tv_string_buf_chk(&argvars[1], nbuf1); | |
15538 epat = get_tv_string_buf_chk(&argvars[2], nbuf2); | |
15539 if (spat == NULL || mpat == NULL || epat == NULL) | |
15540 goto theend; /* type error */ | |
15541 | |
15542 /* Handle the optional fourth argument: flags */ | |
15543 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */ | |
15544 if (dir == 0) | |
15545 goto theend; | |
15546 | |
15547 /* Don't accept SP_END or SP_SUBPAT. | |
15548 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set. | |
15549 */ | |
15550 if ((flags & (SP_END | SP_SUBPAT)) != 0 | |
15551 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK))) | |
15552 { | |
15553 EMSG2(_(e_invarg2), get_tv_string(&argvars[3])); | |
15554 goto theend; | |
15555 } | |
15556 | |
15557 /* Using 'r' implies 'W', otherwise it doesn't work. */ | |
15558 if (flags & SP_REPEAT) | |
15559 p_ws = FALSE; | |
15560 | |
15561 /* Optional fifth argument: skip expression */ | |
15562 if (argvars[3].v_type == VAR_UNKNOWN | |
15563 || argvars[4].v_type == VAR_UNKNOWN) | |
15564 skip = (char_u *)""; | |
15565 else | |
15566 { | |
15567 skip = get_tv_string_buf_chk(&argvars[4], nbuf3); | |
15568 if (argvars[5].v_type != VAR_UNKNOWN) | |
15569 { | |
15570 lnum_stop = (long)get_tv_number_chk(&argvars[5], NULL); | |
15571 if (lnum_stop < 0) | |
15572 goto theend; | |
15573 #ifdef FEAT_RELTIME | |
15574 if (argvars[6].v_type != VAR_UNKNOWN) | |
15575 { | |
15576 time_limit = (long)get_tv_number_chk(&argvars[6], NULL); | |
15577 if (time_limit < 0) | |
15578 goto theend; | |
15579 } | |
15580 #endif | |
15581 } | |
15582 } | |
15583 if (skip == NULL) | |
15584 goto theend; /* type error */ | |
15585 | |
15586 retval = do_searchpair(spat, mpat, epat, dir, skip, flags, | |
15587 match_pos, lnum_stop, time_limit); | |
15588 | |
15589 theend: | |
15590 p_ws = save_p_ws; | |
15591 | |
15592 return retval; | |
15593 } | |
15594 | |
15595 /* | |
15596 * "searchpair()" function | |
15597 */ | |
15598 static void | |
15599 f_searchpair(typval_T *argvars, typval_T *rettv) | |
15600 { | |
15601 rettv->vval.v_number = searchpair_cmn(argvars, NULL); | |
15602 } | |
15603 | |
15604 /* | |
15605 * "searchpairpos()" function | |
15606 */ | |
15607 static void | |
15608 f_searchpairpos(typval_T *argvars, typval_T *rettv) | |
15609 { | |
15610 pos_T match_pos; | |
15611 int lnum = 0; | |
15612 int col = 0; | |
15613 | |
15614 if (rettv_list_alloc(rettv) == FAIL) | |
15615 return; | |
15616 | |
15617 if (searchpair_cmn(argvars, &match_pos) > 0) | |
15618 { | |
15619 lnum = match_pos.lnum; | |
15620 col = match_pos.col; | |
15621 } | |
15622 | |
15623 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); | |
15624 list_append_number(rettv->vval.v_list, (varnumber_T)col); | |
15625 } | |
15626 | |
15627 /* | |
15628 * Search for a start/middle/end thing. | |
15629 * Used by searchpair(), see its documentation for the details. | |
15630 * Returns 0 or -1 for no match, | |
15631 */ | |
15632 long | |
15633 do_searchpair( | |
15634 char_u *spat, /* start pattern */ | |
15635 char_u *mpat, /* middle pattern */ | |
15636 char_u *epat, /* end pattern */ | |
15637 int dir, /* BACKWARD or FORWARD */ | |
15638 char_u *skip, /* skip expression */ | |
15639 int flags, /* SP_SETPCMARK and other SP_ values */ | |
15640 pos_T *match_pos, | |
15641 linenr_T lnum_stop, /* stop at this line if not zero */ | |
15642 long time_limit UNUSED) /* stop after this many msec */ | |
15643 { | |
15644 char_u *save_cpo; | |
15645 char_u *pat, *pat2 = NULL, *pat3 = NULL; | |
15646 long retval = 0; | |
15647 pos_T pos; | |
15648 pos_T firstpos; | |
15649 pos_T foundpos; | |
15650 pos_T save_cursor; | |
15651 pos_T save_pos; | |
15652 int n; | |
15653 int r; | |
15654 int nest = 1; | |
15655 int err; | |
15656 int options = SEARCH_KEEP; | |
15657 proftime_T tm; | |
15658 | |
15659 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
15660 save_cpo = p_cpo; | |
15661 p_cpo = empty_option; | |
15662 | |
15663 #ifdef FEAT_RELTIME | |
15664 /* Set the time limit, if there is one. */ | |
15665 profile_setlimit(time_limit, &tm); | |
15666 #endif | |
15667 | |
15668 /* Make two search patterns: start/end (pat2, for in nested pairs) and | |
15669 * start/middle/end (pat3, for the top pair). */ | |
15670 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15)); | |
15671 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23)); | |
15672 if (pat2 == NULL || pat3 == NULL) | |
15673 goto theend; | |
15674 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); | |
15675 if (*mpat == NUL) | |
15676 STRCPY(pat3, pat2); | |
15677 else | |
15678 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", | |
15679 spat, epat, mpat); | |
15680 if (flags & SP_START) | |
15681 options |= SEARCH_START; | |
15682 | |
15683 save_cursor = curwin->w_cursor; | |
15684 pos = curwin->w_cursor; | |
15685 clearpos(&firstpos); | |
15686 clearpos(&foundpos); | |
15687 pat = pat3; | |
15688 for (;;) | |
15689 { | |
15690 n = searchit(curwin, curbuf, &pos, dir, pat, 1L, | |
15691 options, RE_SEARCH, lnum_stop, &tm); | |
15692 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) | |
15693 /* didn't find it or found the first match again: FAIL */ | |
15694 break; | |
15695 | |
15696 if (firstpos.lnum == 0) | |
15697 firstpos = pos; | |
15698 if (equalpos(pos, foundpos)) | |
15699 { | |
15700 /* Found the same position again. Can happen with a pattern that | |
15701 * has "\zs" at the end and searching backwards. Advance one | |
15702 * character and try again. */ | |
15703 if (dir == BACKWARD) | |
15704 decl(&pos); | |
15705 else | |
15706 incl(&pos); | |
15707 } | |
15708 foundpos = pos; | |
15709 | |
15710 /* clear the start flag to avoid getting stuck here */ | |
15711 options &= ~SEARCH_START; | |
15712 | |
15713 /* If the skip pattern matches, ignore this match. */ | |
15714 if (*skip != NUL) | |
15715 { | |
15716 save_pos = curwin->w_cursor; | |
15717 curwin->w_cursor = pos; | |
15718 r = eval_to_bool(skip, &err, NULL, FALSE); | |
15719 curwin->w_cursor = save_pos; | |
15720 if (err) | |
15721 { | |
15722 /* Evaluating {skip} caused an error, break here. */ | |
15723 curwin->w_cursor = save_cursor; | |
15724 retval = -1; | |
15725 break; | |
15726 } | |
15727 if (r) | |
15728 continue; | |
15729 } | |
15730 | |
15731 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) | |
15732 { | |
15733 /* Found end when searching backwards or start when searching | |
15734 * forward: nested pair. */ | |
15735 ++nest; | |
15736 pat = pat2; /* nested, don't search for middle */ | |
15737 } | |
15738 else | |
15739 { | |
15740 /* Found end when searching forward or start when searching | |
15741 * backward: end of (nested) pair; or found middle in outer pair. */ | |
15742 if (--nest == 1) | |
15743 pat = pat3; /* outer level, search for middle */ | |
15744 } | |
15745 | |
15746 if (nest == 0) | |
15747 { | |
15748 /* Found the match: return matchcount or line number. */ | |
15749 if (flags & SP_RETCOUNT) | |
15750 ++retval; | |
15751 else | |
15752 retval = pos.lnum; | |
15753 if (flags & SP_SETPCMARK) | |
15754 setpcmark(); | |
15755 curwin->w_cursor = pos; | |
15756 if (!(flags & SP_REPEAT)) | |
15757 break; | |
15758 nest = 1; /* search for next unmatched */ | |
15759 } | |
15760 } | |
15761 | |
15762 if (match_pos != NULL) | |
15763 { | |
15764 /* Store the match cursor position */ | |
15765 match_pos->lnum = curwin->w_cursor.lnum; | |
15766 match_pos->col = curwin->w_cursor.col + 1; | |
15767 } | |
15768 | |
15769 /* If 'n' flag is used or search failed: restore cursor position. */ | |
15770 if ((flags & SP_NOMOVE) || retval == 0) | |
15771 curwin->w_cursor = save_cursor; | |
15772 | |
15773 theend: | |
15774 vim_free(pat2); | |
15775 vim_free(pat3); | |
15776 if (p_cpo == empty_option) | |
15777 p_cpo = save_cpo; | |
15778 else | |
15779 /* Darn, evaluating the {skip} expression changed the value. */ | |
15780 free_string_option(save_cpo); | |
15781 | |
15782 return retval; | |
15783 } | |
15784 | |
15785 /* | |
15786 * "searchpos()" function | |
15787 */ | |
15788 static void | |
15789 f_searchpos(typval_T *argvars, typval_T *rettv) | |
15790 { | |
15791 pos_T match_pos; | |
15792 int lnum = 0; | |
15793 int col = 0; | |
15794 int n; | |
15795 int flags = 0; | |
15796 | |
15797 if (rettv_list_alloc(rettv) == FAIL) | |
15798 return; | |
15799 | |
15800 n = search_cmn(argvars, &match_pos, &flags); | |
15801 if (n > 0) | |
15802 { | |
15803 lnum = match_pos.lnum; | |
15804 col = match_pos.col; | |
15805 } | |
15806 | |
15807 list_append_number(rettv->vval.v_list, (varnumber_T)lnum); | |
15808 list_append_number(rettv->vval.v_list, (varnumber_T)col); | |
15809 if (flags & SP_SUBPAT) | |
15810 list_append_number(rettv->vval.v_list, (varnumber_T)n); | |
15811 } | |
15812 | |
15813 static void | |
15814 f_server2client(typval_T *argvars UNUSED, typval_T *rettv) | |
15815 { | |
15816 #ifdef FEAT_CLIENTSERVER | |
15817 char_u buf[NUMBUFLEN]; | |
15818 char_u *server = get_tv_string_chk(&argvars[0]); | |
15819 char_u *reply = get_tv_string_buf_chk(&argvars[1], buf); | |
15820 | |
15821 rettv->vval.v_number = -1; | |
15822 if (server == NULL || reply == NULL) | |
15823 return; | |
15824 if (check_restricted() || check_secure()) | |
15825 return; | |
15826 # ifdef FEAT_X11 | |
15827 if (check_connection() == FAIL) | |
15828 return; | |
15829 # endif | |
15830 | |
15831 if (serverSendReply(server, reply) < 0) | |
15832 { | |
15833 EMSG(_("E258: Unable to send to client")); | |
15834 return; | |
15835 } | |
15836 rettv->vval.v_number = 0; | |
15837 #else | |
15838 rettv->vval.v_number = -1; | |
15839 #endif | |
15840 } | |
15841 | |
15842 static void | |
15843 f_serverlist(typval_T *argvars UNUSED, typval_T *rettv) | |
15844 { | |
15845 char_u *r = NULL; | |
15846 | |
15847 #ifdef FEAT_CLIENTSERVER | |
15848 # ifdef WIN32 | |
15849 r = serverGetVimNames(); | |
15850 # else | |
15851 make_connection(); | |
15852 if (X_DISPLAY != NULL) | |
15853 r = serverGetVimNames(X_DISPLAY); | |
15854 # endif | |
15855 #endif | |
15856 rettv->v_type = VAR_STRING; | |
15857 rettv->vval.v_string = r; | |
15858 } | |
15859 | |
15860 /* | |
15861 * "setbufvar()" function | |
15862 */ | |
15863 static void | |
15864 f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED) | |
15865 { | |
15866 buf_T *buf; | |
15867 char_u *varname, *bufvarname; | |
15868 typval_T *varp; | |
15869 char_u nbuf[NUMBUFLEN]; | |
15870 | |
15871 if (check_restricted() || check_secure()) | |
15872 return; | |
15873 (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ | |
15874 varname = get_tv_string_chk(&argvars[1]); | |
15875 buf = get_buf_tv(&argvars[0], FALSE); | |
15876 varp = &argvars[2]; | |
15877 | |
15878 if (buf != NULL && varname != NULL && varp != NULL) | |
15879 { | |
15880 if (*varname == '&') | |
15881 { | |
15882 long numval; | |
15883 char_u *strval; | |
15884 int error = FALSE; | |
15885 aco_save_T aco; | |
15886 | |
15887 /* set curbuf to be our buf, temporarily */ | |
15888 aucmd_prepbuf(&aco, buf); | |
15889 | |
15890 ++varname; | |
15891 numval = (long)get_tv_number_chk(varp, &error); | |
15892 strval = get_tv_string_buf_chk(varp, nbuf); | |
15893 if (!error && strval != NULL) | |
15894 set_option_value(varname, numval, strval, OPT_LOCAL); | |
15895 | |
15896 /* reset notion of buffer */ | |
15897 aucmd_restbuf(&aco); | |
15898 } | |
15899 else | |
15900 { | |
15901 buf_T *save_curbuf = curbuf; | |
15902 | |
15903 bufvarname = alloc((unsigned)STRLEN(varname) + 3); | |
15904 if (bufvarname != NULL) | |
15905 { | |
15906 curbuf = buf; | |
15907 STRCPY(bufvarname, "b:"); | |
15908 STRCPY(bufvarname + 2, varname); | |
15909 set_var(bufvarname, varp, TRUE); | |
15910 vim_free(bufvarname); | |
15911 curbuf = save_curbuf; | |
15912 } | |
15913 } | |
15914 } | |
15915 } | |
15916 | |
15917 static void | |
15918 f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) | |
15919 { | |
15920 dict_T *d; | |
15921 dictitem_T *di; | |
15922 char_u *csearch; | |
15923 | |
15924 if (argvars[0].v_type != VAR_DICT) | |
15925 { | |
15926 EMSG(_(e_dictreq)); | |
15927 return; | |
15928 } | |
15929 | |
15930 if ((d = argvars[0].vval.v_dict) != NULL) | |
15931 { | |
15932 csearch = get_dict_string(d, (char_u *)"char", FALSE); | |
15933 if (csearch != NULL) | |
15934 { | |
15935 #ifdef FEAT_MBYTE | |
15936 if (enc_utf8) | |
15937 { | |
15938 int pcc[MAX_MCO]; | |
15939 int c = utfc_ptr2char(csearch, pcc); | |
15940 | |
15941 set_last_csearch(c, csearch, utfc_ptr2len(csearch)); | |
15942 } | |
15943 else | |
15944 #endif | |
15945 set_last_csearch(PTR2CHAR(csearch), | |
15946 csearch, MB_PTR2LEN(csearch)); | |
15947 } | |
15948 | |
15949 di = dict_find(d, (char_u *)"forward", -1); | |
15950 if (di != NULL) | |
15951 set_csearch_direction((int)get_tv_number(&di->di_tv) | |
15952 ? FORWARD : BACKWARD); | |
15953 | |
15954 di = dict_find(d, (char_u *)"until", -1); | |
15955 if (di != NULL) | |
15956 set_csearch_until(!!get_tv_number(&di->di_tv)); | |
15957 } | |
15958 } | |
15959 | |
15960 /* | |
15961 * "setcmdpos()" function | |
15962 */ | |
15963 static void | |
15964 f_setcmdpos(typval_T *argvars, typval_T *rettv) | |
15965 { | |
15966 int pos = (int)get_tv_number(&argvars[0]) - 1; | |
15967 | |
15968 if (pos >= 0) | |
15969 rettv->vval.v_number = set_cmdline_pos(pos); | |
15970 } | |
15971 | |
15972 /* | |
15973 * "setfperm({fname}, {mode})" function | |
15974 */ | |
15975 static void | |
15976 f_setfperm(typval_T *argvars, typval_T *rettv) | |
15977 { | |
15978 char_u *fname; | |
15979 char_u modebuf[NUMBUFLEN]; | |
15980 char_u *mode_str; | |
15981 int i; | |
15982 int mask; | |
15983 int mode = 0; | |
15984 | |
15985 rettv->vval.v_number = 0; | |
15986 fname = get_tv_string_chk(&argvars[0]); | |
15987 if (fname == NULL) | |
15988 return; | |
15989 mode_str = get_tv_string_buf_chk(&argvars[1], modebuf); | |
15990 if (mode_str == NULL) | |
15991 return; | |
15992 if (STRLEN(mode_str) != 9) | |
15993 { | |
15994 EMSG2(_(e_invarg2), mode_str); | |
15995 return; | |
15996 } | |
15997 | |
15998 mask = 1; | |
15999 for (i = 8; i >= 0; --i) | |
16000 { | |
16001 if (mode_str[i] != '-') | |
16002 mode |= mask; | |
16003 mask = mask << 1; | |
16004 } | |
16005 rettv->vval.v_number = mch_setperm(fname, mode) == OK; | |
16006 } | |
16007 | |
16008 /* | |
16009 * "setline()" function | |
16010 */ | |
16011 static void | |
16012 f_setline(typval_T *argvars, typval_T *rettv) | |
16013 { | |
16014 linenr_T lnum; | |
16015 char_u *line = NULL; | |
16016 list_T *l = NULL; | |
16017 listitem_T *li = NULL; | |
16018 long added = 0; | |
16019 linenr_T lcount = curbuf->b_ml.ml_line_count; | |
16020 | |
16021 lnum = get_tv_lnum(&argvars[0]); | |
16022 if (argvars[1].v_type == VAR_LIST) | |
16023 { | |
16024 l = argvars[1].vval.v_list; | |
16025 li = l->lv_first; | |
16026 } | |
16027 else | |
16028 line = get_tv_string_chk(&argvars[1]); | |
16029 | |
16030 /* default result is zero == OK */ | |
16031 for (;;) | |
16032 { | |
16033 if (l != NULL) | |
16034 { | |
16035 /* list argument, get next string */ | |
16036 if (li == NULL) | |
16037 break; | |
16038 line = get_tv_string_chk(&li->li_tv); | |
16039 li = li->li_next; | |
16040 } | |
16041 | |
16042 rettv->vval.v_number = 1; /* FAIL */ | |
16043 if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) | |
16044 break; | |
16045 | |
16046 /* When coming here from Insert mode, sync undo, so that this can be | |
16047 * undone separately from what was previously inserted. */ | |
16048 if (u_sync_once == 2) | |
16049 { | |
16050 u_sync_once = 1; /* notify that u_sync() was called */ | |
16051 u_sync(TRUE); | |
16052 } | |
16053 | |
16054 if (lnum <= curbuf->b_ml.ml_line_count) | |
16055 { | |
16056 /* existing line, replace it */ | |
16057 if (u_savesub(lnum) == OK && ml_replace(lnum, line, TRUE) == OK) | |
16058 { | |
16059 changed_bytes(lnum, 0); | |
16060 if (lnum == curwin->w_cursor.lnum) | |
16061 check_cursor_col(); | |
16062 rettv->vval.v_number = 0; /* OK */ | |
16063 } | |
16064 } | |
16065 else if (added > 0 || u_save(lnum - 1, lnum) == OK) | |
16066 { | |
16067 /* lnum is one past the last line, append the line */ | |
16068 ++added; | |
16069 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK) | |
16070 rettv->vval.v_number = 0; /* OK */ | |
16071 } | |
16072 | |
16073 if (l == NULL) /* only one string argument */ | |
16074 break; | |
16075 ++lnum; | |
16076 } | |
16077 | |
16078 if (added > 0) | |
16079 appended_lines_mark(lcount, added); | |
16080 } | |
16081 | |
16082 static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg, typval_T *rettv); | |
16083 | |
16084 /* | |
16085 * Used by "setqflist()" and "setloclist()" functions | |
16086 */ | |
16087 static void | |
16088 set_qf_ll_list( | |
16089 win_T *wp UNUSED, | |
16090 typval_T *list_arg UNUSED, | |
16091 typval_T *action_arg UNUSED, | |
16092 typval_T *rettv) | |
16093 { | |
16094 #ifdef FEAT_QUICKFIX | |
16095 static char *e_invact = N_("E927: Invalid action: '%s'"); | |
16096 char_u *act; | |
16097 int action = 0; | |
16098 #endif | |
16099 | |
16100 rettv->vval.v_number = -1; | |
16101 | |
16102 #ifdef FEAT_QUICKFIX | |
16103 if (list_arg->v_type != VAR_LIST) | |
16104 EMSG(_(e_listreq)); | |
16105 else | |
16106 { | |
16107 list_T *l = list_arg->vval.v_list; | |
16108 | |
16109 if (action_arg->v_type == VAR_STRING) | |
16110 { | |
16111 act = get_tv_string_chk(action_arg); | |
16112 if (act == NULL) | |
16113 return; /* type error; errmsg already given */ | |
16114 if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) | |
16115 action = *act; | |
16116 else | |
16117 EMSG2(_(e_invact), act); | |
16118 } | |
16119 else if (action_arg->v_type == VAR_UNKNOWN) | |
16120 action = ' '; | |
16121 else | |
16122 EMSG(_(e_stringreq)); | |
16123 | |
16124 if (l != NULL && action && set_errorlist(wp, l, action, | |
16125 (char_u *)(wp == NULL ? "setqflist()" : "setloclist()")) == OK) | |
16126 rettv->vval.v_number = 0; | |
16127 } | |
16128 #endif | |
16129 } | |
16130 | |
16131 /* | |
16132 * "setloclist()" function | |
16133 */ | |
16134 static void | |
16135 f_setloclist(typval_T *argvars, typval_T *rettv) | |
16136 { | |
16137 win_T *win; | |
16138 | |
16139 rettv->vval.v_number = -1; | |
16140 | |
16141 win = find_win_by_nr(&argvars[0], NULL); | |
16142 if (win != NULL) | |
16143 set_qf_ll_list(win, &argvars[1], &argvars[2], rettv); | |
16144 } | |
16145 | |
16146 /* | |
16147 * "setmatches()" function | |
16148 */ | |
16149 static void | |
16150 f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
16151 { | |
16152 #ifdef FEAT_SEARCH_EXTRA | |
16153 list_T *l; | |
16154 listitem_T *li; | |
16155 dict_T *d; | |
16156 list_T *s = NULL; | |
16157 | |
16158 rettv->vval.v_number = -1; | |
16159 if (argvars[0].v_type != VAR_LIST) | |
16160 { | |
16161 EMSG(_(e_listreq)); | |
16162 return; | |
16163 } | |
16164 if ((l = argvars[0].vval.v_list) != NULL) | |
16165 { | |
16166 | |
16167 /* To some extent make sure that we are dealing with a list from | |
16168 * "getmatches()". */ | |
16169 li = l->lv_first; | |
16170 while (li != NULL) | |
16171 { | |
16172 if (li->li_tv.v_type != VAR_DICT | |
16173 || (d = li->li_tv.vval.v_dict) == NULL) | |
16174 { | |
16175 EMSG(_(e_invarg)); | |
16176 return; | |
16177 } | |
16178 if (!(dict_find(d, (char_u *)"group", -1) != NULL | |
16179 && (dict_find(d, (char_u *)"pattern", -1) != NULL | |
16180 || dict_find(d, (char_u *)"pos1", -1) != NULL) | |
16181 && dict_find(d, (char_u *)"priority", -1) != NULL | |
16182 && dict_find(d, (char_u *)"id", -1) != NULL)) | |
16183 { | |
16184 EMSG(_(e_invarg)); | |
16185 return; | |
16186 } | |
16187 li = li->li_next; | |
16188 } | |
16189 | |
16190 clear_matches(curwin); | |
16191 li = l->lv_first; | |
16192 while (li != NULL) | |
16193 { | |
16194 int i = 0; | |
16195 char_u buf[5]; | |
16196 dictitem_T *di; | |
16197 char_u *group; | |
16198 int priority; | |
16199 int id; | |
16200 char_u *conceal; | |
16201 | |
16202 d = li->li_tv.vval.v_dict; | |
16203 if (dict_find(d, (char_u *)"pattern", -1) == NULL) | |
16204 { | |
16205 if (s == NULL) | |
16206 { | |
16207 s = list_alloc(); | |
16208 if (s == NULL) | |
16209 return; | |
16210 } | |
16211 | |
16212 /* match from matchaddpos() */ | |
16213 for (i = 1; i < 9; i++) | |
16214 { | |
16215 sprintf((char *)buf, (char *)"pos%d", i); | |
16216 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL) | |
16217 { | |
16218 if (di->di_tv.v_type != VAR_LIST) | |
16219 return; | |
16220 | |
16221 list_append_tv(s, &di->di_tv); | |
16222 s->lv_refcount++; | |
16223 } | |
16224 else | |
16225 break; | |
16226 } | |
16227 } | |
16228 | |
16229 group = get_dict_string(d, (char_u *)"group", FALSE); | |
16230 priority = (int)get_dict_number(d, (char_u *)"priority"); | |
16231 id = (int)get_dict_number(d, (char_u *)"id"); | |
16232 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL | |
16233 ? get_dict_string(d, (char_u *)"conceal", FALSE) | |
16234 : NULL; | |
16235 if (i == 0) | |
16236 { | |
16237 match_add(curwin, group, | |
16238 get_dict_string(d, (char_u *)"pattern", FALSE), | |
16239 priority, id, NULL, conceal); | |
16240 } | |
16241 else | |
16242 { | |
16243 match_add(curwin, group, NULL, priority, id, s, conceal); | |
16244 list_unref(s); | |
16245 s = NULL; | |
16246 } | |
16247 | |
16248 li = li->li_next; | |
16249 } | |
16250 rettv->vval.v_number = 0; | |
16251 } | |
16252 #endif | |
16253 } | |
16254 | |
16255 /* | |
16256 * "setpos()" function | |
16257 */ | |
16258 static void | |
16259 f_setpos(typval_T *argvars, typval_T *rettv) | |
16260 { | |
16261 pos_T pos; | |
16262 int fnum; | |
16263 char_u *name; | |
16264 colnr_T curswant = -1; | |
16265 | |
16266 rettv->vval.v_number = -1; | |
16267 name = get_tv_string_chk(argvars); | |
16268 if (name != NULL) | |
16269 { | |
16270 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) | |
16271 { | |
16272 if (--pos.col < 0) | |
16273 pos.col = 0; | |
16274 if (name[0] == '.' && name[1] == NUL) | |
16275 { | |
16276 /* set cursor */ | |
16277 if (fnum == curbuf->b_fnum) | |
16278 { | |
16279 curwin->w_cursor = pos; | |
16280 if (curswant >= 0) | |
16281 { | |
16282 curwin->w_curswant = curswant - 1; | |
16283 curwin->w_set_curswant = FALSE; | |
16284 } | |
16285 check_cursor(); | |
16286 rettv->vval.v_number = 0; | |
16287 } | |
16288 else | |
16289 EMSG(_(e_invarg)); | |
16290 } | |
16291 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) | |
16292 { | |
16293 /* set mark */ | |
16294 if (setmark_pos(name[1], &pos, fnum) == OK) | |
16295 rettv->vval.v_number = 0; | |
16296 } | |
16297 else | |
16298 EMSG(_(e_invarg)); | |
16299 } | |
16300 } | |
16301 } | |
16302 | |
16303 /* | |
16304 * "setqflist()" function | |
16305 */ | |
16306 static void | |
16307 f_setqflist(typval_T *argvars, typval_T *rettv) | |
16308 { | |
16309 set_qf_ll_list(NULL, &argvars[0], &argvars[1], rettv); | |
16310 } | |
16311 | |
16312 /* | |
16313 * "setreg()" function | |
16314 */ | |
16315 static void | |
16316 f_setreg(typval_T *argvars, typval_T *rettv) | |
16317 { | |
16318 int regname; | |
16319 char_u *strregname; | |
16320 char_u *stropt; | |
16321 char_u *strval; | |
16322 int append; | |
16323 char_u yank_type; | |
16324 long block_len; | |
16325 | |
16326 block_len = -1; | |
16327 yank_type = MAUTO; | |
16328 append = FALSE; | |
16329 | |
16330 strregname = get_tv_string_chk(argvars); | |
16331 rettv->vval.v_number = 1; /* FAIL is default */ | |
16332 | |
16333 if (strregname == NULL) | |
16334 return; /* type error; errmsg already given */ | |
16335 regname = *strregname; | |
16336 if (regname == 0 || regname == '@') | |
16337 regname = '"'; | |
16338 | |
16339 if (argvars[2].v_type != VAR_UNKNOWN) | |
16340 { | |
16341 stropt = get_tv_string_chk(&argvars[2]); | |
16342 if (stropt == NULL) | |
16343 return; /* type error */ | |
16344 for (; *stropt != NUL; ++stropt) | |
16345 switch (*stropt) | |
16346 { | |
16347 case 'a': case 'A': /* append */ | |
16348 append = TRUE; | |
16349 break; | |
16350 case 'v': case 'c': /* character-wise selection */ | |
16351 yank_type = MCHAR; | |
16352 break; | |
16353 case 'V': case 'l': /* line-wise selection */ | |
16354 yank_type = MLINE; | |
16355 break; | |
16356 case 'b': case Ctrl_V: /* block-wise selection */ | |
16357 yank_type = MBLOCK; | |
16358 if (VIM_ISDIGIT(stropt[1])) | |
16359 { | |
16360 ++stropt; | |
16361 block_len = getdigits(&stropt) - 1; | |
16362 --stropt; | |
16363 } | |
16364 break; | |
16365 } | |
16366 } | |
16367 | |
16368 if (argvars[1].v_type == VAR_LIST) | |
16369 { | |
16370 char_u **lstval; | |
16371 char_u **allocval; | |
16372 char_u buf[NUMBUFLEN]; | |
16373 char_u **curval; | |
16374 char_u **curallocval; | |
16375 list_T *ll = argvars[1].vval.v_list; | |
16376 listitem_T *li; | |
16377 int len; | |
16378 | |
16379 /* If the list is NULL handle like an empty list. */ | |
16380 len = ll == NULL ? 0 : ll->lv_len; | |
16381 | |
16382 /* First half: use for pointers to result lines; second half: use for | |
16383 * pointers to allocated copies. */ | |
16384 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2)); | |
16385 if (lstval == NULL) | |
16386 return; | |
16387 curval = lstval; | |
16388 allocval = lstval + len + 2; | |
16389 curallocval = allocval; | |
16390 | |
16391 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL; | |
16392 li = li->li_next) | |
16393 { | |
16394 strval = get_tv_string_buf_chk(&li->li_tv, buf); | |
16395 if (strval == NULL) | |
16396 goto free_lstval; | |
16397 if (strval == buf) | |
16398 { | |
16399 /* Need to make a copy, next get_tv_string_buf_chk() will | |
16400 * overwrite the string. */ | |
16401 strval = vim_strsave(buf); | |
16402 if (strval == NULL) | |
16403 goto free_lstval; | |
16404 *curallocval++ = strval; | |
16405 } | |
16406 *curval++ = strval; | |
16407 } | |
16408 *curval++ = NULL; | |
16409 | |
16410 write_reg_contents_lst(regname, lstval, -1, | |
16411 append, yank_type, block_len); | |
16412 free_lstval: | |
16413 while (curallocval > allocval) | |
16414 vim_free(*--curallocval); | |
16415 vim_free(lstval); | |
16416 } | |
16417 else | |
16418 { | |
16419 strval = get_tv_string_chk(&argvars[1]); | |
16420 if (strval == NULL) | |
16421 return; | |
16422 write_reg_contents_ex(regname, strval, -1, | |
16423 append, yank_type, block_len); | |
16424 } | |
16425 rettv->vval.v_number = 0; | |
16426 } | |
16427 | |
16428 /* | |
16429 * "settabvar()" function | |
16430 */ | |
16431 static void | |
16432 f_settabvar(typval_T *argvars, typval_T *rettv) | |
16433 { | |
16434 #ifdef FEAT_WINDOWS | |
16435 tabpage_T *save_curtab; | |
16436 tabpage_T *tp; | |
16437 #endif | |
16438 char_u *varname, *tabvarname; | |
16439 typval_T *varp; | |
16440 | |
16441 rettv->vval.v_number = 0; | |
16442 | |
16443 if (check_restricted() || check_secure()) | |
16444 return; | |
16445 | |
16446 #ifdef FEAT_WINDOWS | |
16447 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
16448 #endif | |
16449 varname = get_tv_string_chk(&argvars[1]); | |
16450 varp = &argvars[2]; | |
16451 | |
16452 if (varname != NULL && varp != NULL | |
16453 #ifdef FEAT_WINDOWS | |
16454 && tp != NULL | |
16455 #endif | |
16456 ) | |
16457 { | |
16458 #ifdef FEAT_WINDOWS | |
16459 save_curtab = curtab; | |
16460 goto_tabpage_tp(tp, FALSE, FALSE); | |
16461 #endif | |
16462 | |
16463 tabvarname = alloc((unsigned)STRLEN(varname) + 3); | |
16464 if (tabvarname != NULL) | |
16465 { | |
16466 STRCPY(tabvarname, "t:"); | |
16467 STRCPY(tabvarname + 2, varname); | |
16468 set_var(tabvarname, varp, TRUE); | |
16469 vim_free(tabvarname); | |
16470 } | |
16471 | |
16472 #ifdef FEAT_WINDOWS | |
16473 /* Restore current tabpage */ | |
16474 if (valid_tabpage(save_curtab)) | |
16475 goto_tabpage_tp(save_curtab, FALSE, FALSE); | |
16476 #endif | |
16477 } | |
16478 } | |
16479 | |
16480 /* | |
16481 * "settabwinvar()" function | |
16482 */ | |
16483 static void | |
16484 f_settabwinvar(typval_T *argvars, typval_T *rettv) | |
16485 { | |
16486 setwinvar(argvars, rettv, 1); | |
16487 } | |
16488 | |
16489 /* | |
16490 * "setwinvar()" function | |
16491 */ | |
16492 static void | |
16493 f_setwinvar(typval_T *argvars, typval_T *rettv) | |
16494 { | |
16495 setwinvar(argvars, rettv, 0); | |
16496 } | |
16497 | |
16498 /* | |
16499 * "setwinvar()" and "settabwinvar()" functions | |
16500 */ | |
16501 | |
16502 static void | |
16503 setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off) | |
16504 { | |
16505 win_T *win; | |
16506 #ifdef FEAT_WINDOWS | |
16507 win_T *save_curwin; | |
16508 tabpage_T *save_curtab; | |
16509 int need_switch_win; | |
16510 #endif | |
16511 char_u *varname, *winvarname; | |
16512 typval_T *varp; | |
16513 char_u nbuf[NUMBUFLEN]; | |
16514 tabpage_T *tp = NULL; | |
16515 | |
16516 if (check_restricted() || check_secure()) | |
16517 return; | |
16518 | |
16519 #ifdef FEAT_WINDOWS | |
16520 if (off == 1) | |
16521 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
16522 else | |
16523 tp = curtab; | |
16524 #endif | |
16525 win = find_win_by_nr(&argvars[off], tp); | |
16526 varname = get_tv_string_chk(&argvars[off + 1]); | |
16527 varp = &argvars[off + 2]; | |
16528 | |
16529 if (win != NULL && varname != NULL && varp != NULL) | |
16530 { | |
16531 #ifdef FEAT_WINDOWS | |
16532 need_switch_win = !(tp == curtab && win == curwin); | |
16533 if (!need_switch_win | |
16534 || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) | |
16535 #endif | |
16536 { | |
16537 if (*varname == '&') | |
16538 { | |
16539 long numval; | |
16540 char_u *strval; | |
16541 int error = FALSE; | |
16542 | |
16543 ++varname; | |
16544 numval = (long)get_tv_number_chk(varp, &error); | |
16545 strval = get_tv_string_buf_chk(varp, nbuf); | |
16546 if (!error && strval != NULL) | |
16547 set_option_value(varname, numval, strval, OPT_LOCAL); | |
16548 } | |
16549 else | |
16550 { | |
16551 winvarname = alloc((unsigned)STRLEN(varname) + 3); | |
16552 if (winvarname != NULL) | |
16553 { | |
16554 STRCPY(winvarname, "w:"); | |
16555 STRCPY(winvarname + 2, varname); | |
16556 set_var(winvarname, varp, TRUE); | |
16557 vim_free(winvarname); | |
16558 } | |
16559 } | |
16560 } | |
16561 #ifdef FEAT_WINDOWS | |
16562 if (need_switch_win) | |
16563 restore_win(save_curwin, save_curtab, TRUE); | |
16564 #endif | |
16565 } | |
16566 } | |
16567 | |
16568 #ifdef FEAT_CRYPT | |
16569 /* | |
16570 * "sha256({string})" function | |
16571 */ | |
16572 static void | |
16573 f_sha256(typval_T *argvars, typval_T *rettv) | |
16574 { | |
16575 char_u *p; | |
16576 | |
16577 p = get_tv_string(&argvars[0]); | |
16578 rettv->vval.v_string = vim_strsave( | |
16579 sha256_bytes(p, (int)STRLEN(p), NULL, 0)); | |
16580 rettv->v_type = VAR_STRING; | |
16581 } | |
16582 #endif /* FEAT_CRYPT */ | |
16583 | |
16584 /* | |
16585 * "shellescape({string})" function | |
16586 */ | |
16587 static void | |
16588 f_shellescape(typval_T *argvars, typval_T *rettv) | |
16589 { | |
16590 rettv->vval.v_string = vim_strsave_shellescape( | |
16591 get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE); | |
16592 rettv->v_type = VAR_STRING; | |
16593 } | |
16594 | |
16595 /* | |
16596 * shiftwidth() function | |
16597 */ | |
16598 static void | |
16599 f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv) | |
16600 { | |
16601 rettv->vval.v_number = get_sw_value(curbuf); | |
16602 } | |
16603 | |
16604 /* | |
16605 * "simplify()" function | |
16606 */ | |
16607 static void | |
16608 f_simplify(typval_T *argvars, typval_T *rettv) | |
16609 { | |
16610 char_u *p; | |
16611 | |
16612 p = get_tv_string(&argvars[0]); | |
16613 rettv->vval.v_string = vim_strsave(p); | |
16614 simplify_filename(rettv->vval.v_string); /* simplify in place */ | |
16615 rettv->v_type = VAR_STRING; | |
16616 } | |
16617 | |
16618 #ifdef FEAT_FLOAT | |
16619 /* | |
16620 * "sin()" function | |
16621 */ | |
16622 static void | |
16623 f_sin(typval_T *argvars, typval_T *rettv) | |
16624 { | |
16625 float_T f = 0.0; | |
16626 | |
16627 rettv->v_type = VAR_FLOAT; | |
16628 if (get_float_arg(argvars, &f) == OK) | |
16629 rettv->vval.v_float = sin(f); | |
16630 else | |
16631 rettv->vval.v_float = 0.0; | |
16632 } | |
16633 | |
16634 /* | |
16635 * "sinh()" function | |
16636 */ | |
16637 static void | |
16638 f_sinh(typval_T *argvars, typval_T *rettv) | |
16639 { | |
16640 float_T f = 0.0; | |
16641 | |
16642 rettv->v_type = VAR_FLOAT; | |
16643 if (get_float_arg(argvars, &f) == OK) | |
16644 rettv->vval.v_float = sinh(f); | |
16645 else | |
16646 rettv->vval.v_float = 0.0; | |
16647 } | |
16648 #endif | |
16649 | |
16650 static int | |
16651 #ifdef __BORLANDC__ | |
16652 _RTLENTRYF | |
16653 #endif | |
16654 item_compare(const void *s1, const void *s2); | |
16655 static int | |
16656 #ifdef __BORLANDC__ | |
16657 _RTLENTRYF | |
16658 #endif | |
16659 item_compare2(const void *s1, const void *s2); | |
16660 | |
16661 /* struct used in the array that's given to qsort() */ | |
16662 typedef struct | |
16663 { | |
16664 listitem_T *item; | |
16665 int idx; | |
16666 } sortItem_T; | |
16667 | |
16668 /* struct storing information about current sort */ | |
16669 typedef struct | |
16670 { | |
16671 int item_compare_ic; | |
16672 int item_compare_numeric; | |
16673 int item_compare_numbers; | |
16674 #ifdef FEAT_FLOAT | |
16675 int item_compare_float; | |
16676 #endif | |
16677 char_u *item_compare_func; | |
16678 partial_T *item_compare_partial; | |
16679 dict_T *item_compare_selfdict; | |
16680 int item_compare_func_err; | |
16681 int item_compare_keep_zero; | |
16682 } sortinfo_T; | |
16683 static sortinfo_T *sortinfo = NULL; | |
16684 static void do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort); | |
16685 #define ITEM_COMPARE_FAIL 999 | |
16686 | |
16687 /* | |
16688 * Compare functions for f_sort() and f_uniq() below. | |
16689 */ | |
16690 static int | |
16691 #ifdef __BORLANDC__ | |
16692 _RTLENTRYF | |
16693 #endif | |
16694 item_compare(const void *s1, const void *s2) | |
16695 { | |
16696 sortItem_T *si1, *si2; | |
16697 typval_T *tv1, *tv2; | |
16698 char_u *p1, *p2; | |
16699 char_u *tofree1 = NULL, *tofree2 = NULL; | |
16700 int res; | |
16701 char_u numbuf1[NUMBUFLEN]; | |
16702 char_u numbuf2[NUMBUFLEN]; | |
16703 | |
16704 si1 = (sortItem_T *)s1; | |
16705 si2 = (sortItem_T *)s2; | |
16706 tv1 = &si1->item->li_tv; | |
16707 tv2 = &si2->item->li_tv; | |
16708 | |
16709 if (sortinfo->item_compare_numbers) | |
16710 { | |
16711 varnumber_T v1 = get_tv_number(tv1); | |
16712 varnumber_T v2 = get_tv_number(tv2); | |
16713 | |
16714 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | |
16715 } | |
16716 | |
16717 #ifdef FEAT_FLOAT | |
16718 if (sortinfo->item_compare_float) | |
16719 { | |
16720 float_T v1 = get_tv_float(tv1); | |
16721 float_T v2 = get_tv_float(tv2); | |
16722 | |
16723 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1; | |
16724 } | |
16725 #endif | |
16726 | |
16727 /* tv2string() puts quotes around a string and allocates memory. Don't do | |
16728 * that for string variables. Use a single quote when comparing with a | |
16729 * non-string to do what the docs promise. */ | |
16730 if (tv1->v_type == VAR_STRING) | |
16731 { | |
16732 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric) | |
16733 p1 = (char_u *)"'"; | |
16734 else | |
16735 p1 = tv1->vval.v_string; | |
16736 } | |
16737 else | |
16738 p1 = tv2string(tv1, &tofree1, numbuf1, 0); | |
16739 if (tv2->v_type == VAR_STRING) | |
16740 { | |
16741 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric) | |
16742 p2 = (char_u *)"'"; | |
16743 else | |
16744 p2 = tv2->vval.v_string; | |
16745 } | |
16746 else | |
16747 p2 = tv2string(tv2, &tofree2, numbuf2, 0); | |
16748 if (p1 == NULL) | |
16749 p1 = (char_u *)""; | |
16750 if (p2 == NULL) | |
16751 p2 = (char_u *)""; | |
16752 if (!sortinfo->item_compare_numeric) | |
16753 { | |
16754 if (sortinfo->item_compare_ic) | |
16755 res = STRICMP(p1, p2); | |
16756 else | |
16757 res = STRCMP(p1, p2); | |
16758 } | |
16759 else | |
16760 { | |
16761 double n1, n2; | |
16762 n1 = strtod((char *)p1, (char **)&p1); | |
16763 n2 = strtod((char *)p2, (char **)&p2); | |
16764 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1; | |
16765 } | |
16766 | |
16767 /* When the result would be zero, compare the item indexes. Makes the | |
16768 * sort stable. */ | |
16769 if (res == 0 && !sortinfo->item_compare_keep_zero) | |
16770 res = si1->idx > si2->idx ? 1 : -1; | |
16771 | |
16772 vim_free(tofree1); | |
16773 vim_free(tofree2); | |
16774 return res; | |
16775 } | |
16776 | |
16777 static int | |
16778 #ifdef __BORLANDC__ | |
16779 _RTLENTRYF | |
16780 #endif | |
16781 item_compare2(const void *s1, const void *s2) | |
16782 { | |
16783 sortItem_T *si1, *si2; | |
16784 int res; | |
16785 typval_T rettv; | |
16786 typval_T argv[3]; | |
16787 int dummy; | |
16788 char_u *func_name; | |
16789 partial_T *partial = sortinfo->item_compare_partial; | |
16790 | |
16791 /* shortcut after failure in previous call; compare all items equal */ | |
16792 if (sortinfo->item_compare_func_err) | |
16793 return 0; | |
16794 | |
16795 si1 = (sortItem_T *)s1; | |
16796 si2 = (sortItem_T *)s2; | |
16797 | |
16798 if (partial == NULL) | |
16799 func_name = sortinfo->item_compare_func; | |
16800 else | |
16801 func_name = partial->pt_name; | |
16802 | |
16803 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED | |
16804 * in the copy without changing the original list items. */ | |
16805 copy_tv(&si1->item->li_tv, &argv[0]); | |
16806 copy_tv(&si2->item->li_tv, &argv[1]); | |
16807 | |
16808 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ | |
16809 res = call_func(func_name, (int)STRLEN(func_name), | |
16810 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, | |
16811 partial, sortinfo->item_compare_selfdict); | |
16812 clear_tv(&argv[0]); | |
16813 clear_tv(&argv[1]); | |
16814 | |
16815 if (res == FAIL) | |
16816 res = ITEM_COMPARE_FAIL; | |
16817 else | |
16818 res = (int)get_tv_number_chk(&rettv, &sortinfo->item_compare_func_err); | |
16819 if (sortinfo->item_compare_func_err) | |
16820 res = ITEM_COMPARE_FAIL; /* return value has wrong type */ | |
16821 clear_tv(&rettv); | |
16822 | |
16823 /* When the result would be zero, compare the pointers themselves. Makes | |
16824 * the sort stable. */ | |
16825 if (res == 0 && !sortinfo->item_compare_keep_zero) | |
16826 res = si1->idx > si2->idx ? 1 : -1; | |
16827 | |
16828 return res; | |
16829 } | |
16830 | |
16831 /* | |
16832 * "sort({list})" function | |
16833 */ | |
16834 static void | |
16835 do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) | |
16836 { | |
16837 list_T *l; | |
16838 listitem_T *li; | |
16839 sortItem_T *ptrs; | |
16840 sortinfo_T *old_sortinfo; | |
16841 sortinfo_T info; | |
16842 long len; | |
16843 long i; | |
16844 | |
16845 /* Pointer to current info struct used in compare function. Save and | |
16846 * restore the current one for nested calls. */ | |
16847 old_sortinfo = sortinfo; | |
16848 sortinfo = &info; | |
16849 | |
16850 if (argvars[0].v_type != VAR_LIST) | |
16851 EMSG2(_(e_listarg), sort ? "sort()" : "uniq()"); | |
16852 else | |
16853 { | |
16854 l = argvars[0].vval.v_list; | |
16855 if (l == NULL || tv_check_lock(l->lv_lock, | |
16856 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), | |
16857 TRUE)) | |
16858 goto theend; | |
16859 rettv->vval.v_list = l; | |
16860 rettv->v_type = VAR_LIST; | |
16861 ++l->lv_refcount; | |
16862 | |
16863 len = list_len(l); | |
16864 if (len <= 1) | |
16865 goto theend; /* short list sorts pretty quickly */ | |
16866 | |
16867 info.item_compare_ic = FALSE; | |
16868 info.item_compare_numeric = FALSE; | |
16869 info.item_compare_numbers = FALSE; | |
16870 #ifdef FEAT_FLOAT | |
16871 info.item_compare_float = FALSE; | |
16872 #endif | |
16873 info.item_compare_func = NULL; | |
16874 info.item_compare_partial = NULL; | |
16875 info.item_compare_selfdict = NULL; | |
16876 if (argvars[1].v_type != VAR_UNKNOWN) | |
16877 { | |
16878 /* optional second argument: {func} */ | |
16879 if (argvars[1].v_type == VAR_FUNC) | |
16880 info.item_compare_func = argvars[1].vval.v_string; | |
16881 else if (argvars[1].v_type == VAR_PARTIAL) | |
16882 info.item_compare_partial = argvars[1].vval.v_partial; | |
16883 else | |
16884 { | |
16885 int error = FALSE; | |
16886 | |
16887 i = (long)get_tv_number_chk(&argvars[1], &error); | |
16888 if (error) | |
16889 goto theend; /* type error; errmsg already given */ | |
16890 if (i == 1) | |
16891 info.item_compare_ic = TRUE; | |
16892 else if (argvars[1].v_type != VAR_NUMBER) | |
16893 info.item_compare_func = get_tv_string(&argvars[1]); | |
16894 else if (i != 0) | |
16895 { | |
16896 EMSG(_(e_invarg)); | |
16897 goto theend; | |
16898 } | |
16899 if (info.item_compare_func != NULL) | |
16900 { | |
16901 if (*info.item_compare_func == NUL) | |
16902 { | |
16903 /* empty string means default sort */ | |
16904 info.item_compare_func = NULL; | |
16905 } | |
16906 else if (STRCMP(info.item_compare_func, "n") == 0) | |
16907 { | |
16908 info.item_compare_func = NULL; | |
16909 info.item_compare_numeric = TRUE; | |
16910 } | |
16911 else if (STRCMP(info.item_compare_func, "N") == 0) | |
16912 { | |
16913 info.item_compare_func = NULL; | |
16914 info.item_compare_numbers = TRUE; | |
16915 } | |
16916 #ifdef FEAT_FLOAT | |
16917 else if (STRCMP(info.item_compare_func, "f") == 0) | |
16918 { | |
16919 info.item_compare_func = NULL; | |
16920 info.item_compare_float = TRUE; | |
16921 } | |
16922 #endif | |
16923 else if (STRCMP(info.item_compare_func, "i") == 0) | |
16924 { | |
16925 info.item_compare_func = NULL; | |
16926 info.item_compare_ic = TRUE; | |
16927 } | |
16928 } | |
16929 } | |
16930 | |
16931 if (argvars[2].v_type != VAR_UNKNOWN) | |
16932 { | |
16933 /* optional third argument: {dict} */ | |
16934 if (argvars[2].v_type != VAR_DICT) | |
16935 { | |
16936 EMSG(_(e_dictreq)); | |
16937 goto theend; | |
16938 } | |
16939 info.item_compare_selfdict = argvars[2].vval.v_dict; | |
16940 } | |
16941 } | |
16942 | |
16943 /* Make an array with each entry pointing to an item in the List. */ | |
16944 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T))); | |
16945 if (ptrs == NULL) | |
16946 goto theend; | |
16947 | |
16948 i = 0; | |
16949 if (sort) | |
16950 { | |
16951 /* sort(): ptrs will be the list to sort */ | |
16952 for (li = l->lv_first; li != NULL; li = li->li_next) | |
16953 { | |
16954 ptrs[i].item = li; | |
16955 ptrs[i].idx = i; | |
16956 ++i; | |
16957 } | |
16958 | |
16959 info.item_compare_func_err = FALSE; | |
16960 info.item_compare_keep_zero = FALSE; | |
16961 /* test the compare function */ | |
16962 if ((info.item_compare_func != NULL | |
16963 || info.item_compare_partial != NULL) | |
16964 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) | |
16965 == ITEM_COMPARE_FAIL) | |
16966 EMSG(_("E702: Sort compare function failed")); | |
16967 else | |
16968 { | |
16969 /* Sort the array with item pointers. */ | |
16970 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), | |
16971 info.item_compare_func == NULL | |
16972 && info.item_compare_partial == NULL | |
16973 ? item_compare : item_compare2); | |
16974 | |
16975 if (!info.item_compare_func_err) | |
16976 { | |
16977 /* Clear the List and append the items in sorted order. */ | |
16978 l->lv_first = l->lv_last = l->lv_idx_item = NULL; | |
16979 l->lv_len = 0; | |
16980 for (i = 0; i < len; ++i) | |
16981 list_append(l, ptrs[i].item); | |
16982 } | |
16983 } | |
16984 } | |
16985 else | |
16986 { | |
16987 int (*item_compare_func_ptr)(const void *, const void *); | |
16988 | |
16989 /* f_uniq(): ptrs will be a stack of items to remove */ | |
16990 info.item_compare_func_err = FALSE; | |
16991 info.item_compare_keep_zero = TRUE; | |
16992 item_compare_func_ptr = info.item_compare_func != NULL | |
16993 || info.item_compare_partial != NULL | |
16994 ? item_compare2 : item_compare; | |
16995 | |
16996 for (li = l->lv_first; li != NULL && li->li_next != NULL; | |
16997 li = li->li_next) | |
16998 { | |
16999 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next) | |
17000 == 0) | |
17001 ptrs[i++].item = li; | |
17002 if (info.item_compare_func_err) | |
17003 { | |
17004 EMSG(_("E882: Uniq compare function failed")); | |
17005 break; | |
17006 } | |
17007 } | |
17008 | |
17009 if (!info.item_compare_func_err) | |
17010 { | |
17011 while (--i >= 0) | |
17012 { | |
17013 li = ptrs[i].item->li_next; | |
17014 ptrs[i].item->li_next = li->li_next; | |
17015 if (li->li_next != NULL) | |
17016 li->li_next->li_prev = ptrs[i].item; | |
17017 else | |
17018 l->lv_last = ptrs[i].item; | |
17019 list_fix_watch(l, li); | |
17020 listitem_free(li); | |
17021 l->lv_len--; | |
17022 } | |
17023 } | |
17024 } | |
17025 | |
17026 vim_free(ptrs); | |
17027 } | |
17028 theend: | |
17029 sortinfo = old_sortinfo; | |
17030 } | |
17031 | |
17032 /* | |
17033 * "sort({list})" function | |
17034 */ | |
17035 static void | |
17036 f_sort(typval_T *argvars, typval_T *rettv) | |
17037 { | |
17038 do_sort_uniq(argvars, rettv, TRUE); | |
17039 } | |
17040 | |
17041 /* | |
17042 * "uniq({list})" function | |
17043 */ | |
17044 static void | |
17045 f_uniq(typval_T *argvars, typval_T *rettv) | |
17046 { | |
17047 do_sort_uniq(argvars, rettv, FALSE); | |
17048 } | |
17049 | |
17050 /* | |
17051 * "soundfold({word})" function | |
17052 */ | |
17053 static void | |
17054 f_soundfold(typval_T *argvars, typval_T *rettv) | |
17055 { | |
17056 char_u *s; | |
17057 | |
17058 rettv->v_type = VAR_STRING; | |
17059 s = get_tv_string(&argvars[0]); | |
17060 #ifdef FEAT_SPELL | |
17061 rettv->vval.v_string = eval_soundfold(s); | |
17062 #else | |
17063 rettv->vval.v_string = vim_strsave(s); | |
17064 #endif | |
17065 } | |
17066 | |
17067 /* | |
17068 * "spellbadword()" function | |
17069 */ | |
17070 static void | |
17071 f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv) | |
17072 { | |
17073 char_u *word = (char_u *)""; | |
17074 hlf_T attr = HLF_COUNT; | |
17075 int len = 0; | |
17076 | |
17077 if (rettv_list_alloc(rettv) == FAIL) | |
17078 return; | |
17079 | |
17080 #ifdef FEAT_SPELL | |
17081 if (argvars[0].v_type == VAR_UNKNOWN) | |
17082 { | |
17083 /* Find the start and length of the badly spelled word. */ | |
17084 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); | |
17085 if (len != 0) | |
17086 word = ml_get_cursor(); | |
17087 } | |
17088 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) | |
17089 { | |
17090 char_u *str = get_tv_string_chk(&argvars[0]); | |
17091 int capcol = -1; | |
17092 | |
17093 if (str != NULL) | |
17094 { | |
17095 /* Check the argument for spelling. */ | |
17096 while (*str != NUL) | |
17097 { | |
17098 len = spell_check(curwin, str, &attr, &capcol, FALSE); | |
17099 if (attr != HLF_COUNT) | |
17100 { | |
17101 word = str; | |
17102 break; | |
17103 } | |
17104 str += len; | |
17105 } | |
17106 } | |
17107 } | |
17108 #endif | |
17109 | |
17110 list_append_string(rettv->vval.v_list, word, len); | |
17111 list_append_string(rettv->vval.v_list, (char_u *)( | |
17112 attr == HLF_SPB ? "bad" : | |
17113 attr == HLF_SPR ? "rare" : | |
17114 attr == HLF_SPL ? "local" : | |
17115 attr == HLF_SPC ? "caps" : | |
17116 ""), -1); | |
17117 } | |
17118 | |
17119 /* | |
17120 * "spellsuggest()" function | |
17121 */ | |
17122 static void | |
17123 f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv) | |
17124 { | |
17125 #ifdef FEAT_SPELL | |
17126 char_u *str; | |
17127 int typeerr = FALSE; | |
17128 int maxcount; | |
17129 garray_T ga; | |
17130 int i; | |
17131 listitem_T *li; | |
17132 int need_capital = FALSE; | |
17133 #endif | |
17134 | |
17135 if (rettv_list_alloc(rettv) == FAIL) | |
17136 return; | |
17137 | |
17138 #ifdef FEAT_SPELL | |
17139 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) | |
17140 { | |
17141 str = get_tv_string(&argvars[0]); | |
17142 if (argvars[1].v_type != VAR_UNKNOWN) | |
17143 { | |
17144 maxcount = (int)get_tv_number_chk(&argvars[1], &typeerr); | |
17145 if (maxcount <= 0) | |
17146 return; | |
17147 if (argvars[2].v_type != VAR_UNKNOWN) | |
17148 { | |
17149 need_capital = (int)get_tv_number_chk(&argvars[2], &typeerr); | |
17150 if (typeerr) | |
17151 return; | |
17152 } | |
17153 } | |
17154 else | |
17155 maxcount = 25; | |
17156 | |
17157 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE); | |
17158 | |
17159 for (i = 0; i < ga.ga_len; ++i) | |
17160 { | |
17161 str = ((char_u **)ga.ga_data)[i]; | |
17162 | |
17163 li = listitem_alloc(); | |
17164 if (li == NULL) | |
17165 vim_free(str); | |
17166 else | |
17167 { | |
17168 li->li_tv.v_type = VAR_STRING; | |
17169 li->li_tv.v_lock = 0; | |
17170 li->li_tv.vval.v_string = str; | |
17171 list_append(rettv->vval.v_list, li); | |
17172 } | |
17173 } | |
17174 ga_clear(&ga); | |
17175 } | |
17176 #endif | |
17177 } | |
17178 | |
17179 static void | |
17180 f_split(typval_T *argvars, typval_T *rettv) | |
17181 { | |
17182 char_u *str; | |
17183 char_u *end; | |
17184 char_u *pat = NULL; | |
17185 regmatch_T regmatch; | |
17186 char_u patbuf[NUMBUFLEN]; | |
17187 char_u *save_cpo; | |
17188 int match; | |
17189 colnr_T col = 0; | |
17190 int keepempty = FALSE; | |
17191 int typeerr = FALSE; | |
17192 | |
17193 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
17194 save_cpo = p_cpo; | |
17195 p_cpo = (char_u *)""; | |
17196 | |
17197 str = get_tv_string(&argvars[0]); | |
17198 if (argvars[1].v_type != VAR_UNKNOWN) | |
17199 { | |
17200 pat = get_tv_string_buf_chk(&argvars[1], patbuf); | |
17201 if (pat == NULL) | |
17202 typeerr = TRUE; | |
17203 if (argvars[2].v_type != VAR_UNKNOWN) | |
17204 keepempty = (int)get_tv_number_chk(&argvars[2], &typeerr); | |
17205 } | |
17206 if (pat == NULL || *pat == NUL) | |
17207 pat = (char_u *)"[\\x01- ]\\+"; | |
17208 | |
17209 if (rettv_list_alloc(rettv) == FAIL) | |
17210 return; | |
17211 if (typeerr) | |
17212 return; | |
17213 | |
17214 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); | |
17215 if (regmatch.regprog != NULL) | |
17216 { | |
17217 regmatch.rm_ic = FALSE; | |
17218 while (*str != NUL || keepempty) | |
17219 { | |
17220 if (*str == NUL) | |
17221 match = FALSE; /* empty item at the end */ | |
17222 else | |
17223 match = vim_regexec_nl(®match, str, col); | |
17224 if (match) | |
17225 end = regmatch.startp[0]; | |
17226 else | |
17227 end = str + STRLEN(str); | |
17228 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0 | |
17229 && *str != NUL && match && end < regmatch.endp[0])) | |
17230 { | |
17231 if (list_append_string(rettv->vval.v_list, str, | |
17232 (int)(end - str)) == FAIL) | |
17233 break; | |
17234 } | |
17235 if (!match) | |
17236 break; | |
17237 /* Advance to just after the match. */ | |
17238 if (regmatch.endp[0] > str) | |
17239 col = 0; | |
17240 else | |
17241 { | |
17242 /* Don't get stuck at the same match. */ | |
17243 #ifdef FEAT_MBYTE | |
17244 col = (*mb_ptr2len)(regmatch.endp[0]); | |
17245 #else | |
17246 col = 1; | |
17247 #endif | |
17248 } | |
17249 str = regmatch.endp[0]; | |
17250 } | |
17251 | |
17252 vim_regfree(regmatch.regprog); | |
17253 } | |
17254 | |
17255 p_cpo = save_cpo; | |
17256 } | |
17257 | |
17258 #ifdef FEAT_FLOAT | |
17259 /* | |
17260 * "sqrt()" function | |
17261 */ | |
17262 static void | |
17263 f_sqrt(typval_T *argvars, typval_T *rettv) | |
17264 { | |
17265 float_T f = 0.0; | |
17266 | |
17267 rettv->v_type = VAR_FLOAT; | |
17268 if (get_float_arg(argvars, &f) == OK) | |
17269 rettv->vval.v_float = sqrt(f); | |
17270 else | |
17271 rettv->vval.v_float = 0.0; | |
17272 } | |
17273 | |
17274 /* | |
17275 * "str2float()" function | |
17276 */ | |
17277 static void | |
17278 f_str2float(typval_T *argvars, typval_T *rettv) | |
17279 { | |
17280 char_u *p = skipwhite(get_tv_string(&argvars[0])); | |
17281 | |
17282 if (*p == '+') | |
17283 p = skipwhite(p + 1); | |
17284 (void)string2float(p, &rettv->vval.v_float); | |
17285 rettv->v_type = VAR_FLOAT; | |
17286 } | |
17287 #endif | |
17288 | |
17289 /* | |
17290 * "str2nr()" function | |
17291 */ | |
17292 static void | |
17293 f_str2nr(typval_T *argvars, typval_T *rettv) | |
17294 { | |
17295 int base = 10; | |
17296 char_u *p; | |
17297 varnumber_T n; | |
17298 int what; | |
17299 | |
17300 if (argvars[1].v_type != VAR_UNKNOWN) | |
17301 { | |
17302 base = (int)get_tv_number(&argvars[1]); | |
17303 if (base != 2 && base != 8 && base != 10 && base != 16) | |
17304 { | |
17305 EMSG(_(e_invarg)); | |
17306 return; | |
17307 } | |
17308 } | |
17309 | |
17310 p = skipwhite(get_tv_string(&argvars[0])); | |
17311 if (*p == '+') | |
17312 p = skipwhite(p + 1); | |
17313 switch (base) | |
17314 { | |
17315 case 2: what = STR2NR_BIN + STR2NR_FORCE; break; | |
17316 case 8: what = STR2NR_OCT + STR2NR_FORCE; break; | |
17317 case 16: what = STR2NR_HEX + STR2NR_FORCE; break; | |
17318 default: what = 0; | |
17319 } | |
17320 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0); | |
17321 rettv->vval.v_number = n; | |
17322 } | |
17323 | |
17324 #ifdef HAVE_STRFTIME | |
17325 /* | |
17326 * "strftime({format}[, {time}])" function | |
17327 */ | |
17328 static void | |
17329 f_strftime(typval_T *argvars, typval_T *rettv) | |
17330 { | |
17331 char_u result_buf[256]; | |
17332 struct tm *curtime; | |
17333 time_t seconds; | |
17334 char_u *p; | |
17335 | |
17336 rettv->v_type = VAR_STRING; | |
17337 | |
17338 p = get_tv_string(&argvars[0]); | |
17339 if (argvars[1].v_type == VAR_UNKNOWN) | |
17340 seconds = time(NULL); | |
17341 else | |
17342 seconds = (time_t)get_tv_number(&argvars[1]); | |
17343 curtime = localtime(&seconds); | |
17344 /* MSVC returns NULL for an invalid value of seconds. */ | |
17345 if (curtime == NULL) | |
17346 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); | |
17347 else | |
17348 { | |
17349 # ifdef FEAT_MBYTE | |
17350 vimconv_T conv; | |
17351 char_u *enc; | |
17352 | |
17353 conv.vc_type = CONV_NONE; | |
17354 enc = enc_locale(); | |
17355 convert_setup(&conv, p_enc, enc); | |
17356 if (conv.vc_type != CONV_NONE) | |
17357 p = string_convert(&conv, p, NULL); | |
17358 # endif | |
17359 if (p != NULL) | |
17360 (void)strftime((char *)result_buf, sizeof(result_buf), | |
17361 (char *)p, curtime); | |
17362 else | |
17363 result_buf[0] = NUL; | |
17364 | |
17365 # ifdef FEAT_MBYTE | |
17366 if (conv.vc_type != CONV_NONE) | |
17367 vim_free(p); | |
17368 convert_setup(&conv, enc, p_enc); | |
17369 if (conv.vc_type != CONV_NONE) | |
17370 rettv->vval.v_string = string_convert(&conv, result_buf, NULL); | |
17371 else | |
17372 # endif | |
17373 rettv->vval.v_string = vim_strsave(result_buf); | |
17374 | |
17375 # ifdef FEAT_MBYTE | |
17376 /* Release conversion descriptors */ | |
17377 convert_setup(&conv, NULL, NULL); | |
17378 vim_free(enc); | |
17379 # endif | |
17380 } | |
17381 } | |
17382 #endif | |
17383 | |
17384 /* | |
17385 * "strgetchar()" function | |
17386 */ | |
17387 static void | |
17388 f_strgetchar(typval_T *argvars, typval_T *rettv) | |
17389 { | |
17390 char_u *str; | |
17391 int len; | |
17392 int error = FALSE; | |
17393 int charidx; | |
17394 | |
17395 rettv->vval.v_number = -1; | |
17396 str = get_tv_string_chk(&argvars[0]); | |
17397 if (str == NULL) | |
17398 return; | |
17399 len = (int)STRLEN(str); | |
17400 charidx = (int)get_tv_number_chk(&argvars[1], &error); | |
17401 if (error) | |
17402 return; | |
17403 #ifdef FEAT_MBYTE | |
17404 { | |
17405 int byteidx = 0; | |
17406 | |
17407 while (charidx >= 0 && byteidx < len) | |
17408 { | |
17409 if (charidx == 0) | |
17410 { | |
17411 rettv->vval.v_number = mb_ptr2char(str + byteidx); | |
17412 break; | |
17413 } | |
17414 --charidx; | |
17415 byteidx += mb_cptr2len(str + byteidx); | |
17416 } | |
17417 } | |
17418 #else | |
17419 if (charidx < len) | |
17420 rettv->vval.v_number = str[charidx]; | |
17421 #endif | |
17422 } | |
17423 | |
17424 /* | |
17425 * "stridx()" function | |
17426 */ | |
17427 static void | |
17428 f_stridx(typval_T *argvars, typval_T *rettv) | |
17429 { | |
17430 char_u buf[NUMBUFLEN]; | |
17431 char_u *needle; | |
17432 char_u *haystack; | |
17433 char_u *save_haystack; | |
17434 char_u *pos; | |
17435 int start_idx; | |
17436 | |
17437 needle = get_tv_string_chk(&argvars[1]); | |
17438 save_haystack = haystack = get_tv_string_buf_chk(&argvars[0], buf); | |
17439 rettv->vval.v_number = -1; | |
17440 if (needle == NULL || haystack == NULL) | |
17441 return; /* type error; errmsg already given */ | |
17442 | |
17443 if (argvars[2].v_type != VAR_UNKNOWN) | |
17444 { | |
17445 int error = FALSE; | |
17446 | |
17447 start_idx = (int)get_tv_number_chk(&argvars[2], &error); | |
17448 if (error || start_idx >= (int)STRLEN(haystack)) | |
17449 return; | |
17450 if (start_idx >= 0) | |
17451 haystack += start_idx; | |
17452 } | |
17453 | |
17454 pos = (char_u *)strstr((char *)haystack, (char *)needle); | |
17455 if (pos != NULL) | |
17456 rettv->vval.v_number = (varnumber_T)(pos - save_haystack); | |
17457 } | |
17458 | |
17459 /* | |
17460 * "string()" function | |
17461 */ | |
17462 static void | |
17463 f_string(typval_T *argvars, typval_T *rettv) | |
17464 { | |
17465 char_u *tofree; | |
17466 char_u numbuf[NUMBUFLEN]; | |
17467 | |
17468 rettv->v_type = VAR_STRING; | |
17469 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, | |
17470 get_copyID()); | |
17471 /* Make a copy if we have a value but it's not in allocated memory. */ | |
17472 if (rettv->vval.v_string != NULL && tofree == NULL) | |
17473 rettv->vval.v_string = vim_strsave(rettv->vval.v_string); | |
17474 } | |
17475 | |
17476 /* | |
17477 * "strlen()" function | |
17478 */ | |
17479 static void | |
17480 f_strlen(typval_T *argvars, typval_T *rettv) | |
17481 { | |
17482 rettv->vval.v_number = (varnumber_T)(STRLEN( | |
17483 get_tv_string(&argvars[0]))); | |
17484 } | |
17485 | |
17486 /* | |
17487 * "strchars()" function | |
17488 */ | |
17489 static void | |
17490 f_strchars(typval_T *argvars, typval_T *rettv) | |
17491 { | |
17492 char_u *s = get_tv_string(&argvars[0]); | |
17493 int skipcc = 0; | |
17494 #ifdef FEAT_MBYTE | |
17495 varnumber_T len = 0; | |
17496 int (*func_mb_ptr2char_adv)(char_u **pp); | |
17497 #endif | |
17498 | |
17499 if (argvars[1].v_type != VAR_UNKNOWN) | |
17500 skipcc = (int)get_tv_number_chk(&argvars[1], NULL); | |
17501 if (skipcc < 0 || skipcc > 1) | |
17502 EMSG(_(e_invarg)); | |
17503 else | |
17504 { | |
17505 #ifdef FEAT_MBYTE | |
17506 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; | |
17507 while (*s != NUL) | |
17508 { | |
17509 func_mb_ptr2char_adv(&s); | |
17510 ++len; | |
17511 } | |
17512 rettv->vval.v_number = len; | |
17513 #else | |
17514 rettv->vval.v_number = (varnumber_T)(STRLEN(s)); | |
17515 #endif | |
17516 } | |
17517 } | |
17518 | |
17519 /* | |
17520 * "strdisplaywidth()" function | |
17521 */ | |
17522 static void | |
17523 f_strdisplaywidth(typval_T *argvars, typval_T *rettv) | |
17524 { | |
17525 char_u *s = get_tv_string(&argvars[0]); | |
17526 int col = 0; | |
17527 | |
17528 if (argvars[1].v_type != VAR_UNKNOWN) | |
17529 col = (int)get_tv_number(&argvars[1]); | |
17530 | |
17531 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col); | |
17532 } | |
17533 | |
17534 /* | |
17535 * "strwidth()" function | |
17536 */ | |
17537 static void | |
17538 f_strwidth(typval_T *argvars, typval_T *rettv) | |
17539 { | |
17540 char_u *s = get_tv_string(&argvars[0]); | |
17541 | |
17542 rettv->vval.v_number = (varnumber_T)( | |
17543 #ifdef FEAT_MBYTE | |
17544 mb_string2cells(s, -1) | |
17545 #else | |
17546 STRLEN(s) | |
17547 #endif | |
17548 ); | |
17549 } | |
17550 | |
17551 /* | |
17552 * "strcharpart()" function | |
17553 */ | |
17554 static void | |
17555 f_strcharpart(typval_T *argvars, typval_T *rettv) | |
17556 { | |
17557 #ifdef FEAT_MBYTE | |
17558 char_u *p; | |
17559 int nchar; | |
17560 int nbyte = 0; | |
17561 int charlen; | |
17562 int len = 0; | |
17563 int slen; | |
17564 int error = FALSE; | |
17565 | |
17566 p = get_tv_string(&argvars[0]); | |
17567 slen = (int)STRLEN(p); | |
17568 | |
17569 nchar = (int)get_tv_number_chk(&argvars[1], &error); | |
17570 if (!error) | |
17571 { | |
17572 if (nchar > 0) | |
17573 while (nchar > 0 && nbyte < slen) | |
17574 { | |
17575 nbyte += mb_cptr2len(p + nbyte); | |
17576 --nchar; | |
17577 } | |
17578 else | |
17579 nbyte = nchar; | |
17580 if (argvars[2].v_type != VAR_UNKNOWN) | |
17581 { | |
17582 charlen = (int)get_tv_number(&argvars[2]); | |
17583 while (charlen > 0 && nbyte + len < slen) | |
17584 { | |
17585 int off = nbyte + len; | |
17586 | |
17587 if (off < 0) | |
17588 len += 1; | |
17589 else | |
17590 len += mb_cptr2len(p + off); | |
17591 --charlen; | |
17592 } | |
17593 } | |
17594 else | |
17595 len = slen - nbyte; /* default: all bytes that are available. */ | |
17596 } | |
17597 | |
17598 /* | |
17599 * Only return the overlap between the specified part and the actual | |
17600 * string. | |
17601 */ | |
17602 if (nbyte < 0) | |
17603 { | |
17604 len += nbyte; | |
17605 nbyte = 0; | |
17606 } | |
17607 else if (nbyte > slen) | |
17608 nbyte = slen; | |
17609 if (len < 0) | |
17610 len = 0; | |
17611 else if (nbyte + len > slen) | |
17612 len = slen - nbyte; | |
17613 | |
17614 rettv->v_type = VAR_STRING; | |
17615 rettv->vval.v_string = vim_strnsave(p + nbyte, len); | |
17616 #else | |
17617 f_strpart(argvars, rettv); | |
17618 #endif | |
17619 } | |
17620 | |
17621 /* | |
17622 * "strpart()" function | |
17623 */ | |
17624 static void | |
17625 f_strpart(typval_T *argvars, typval_T *rettv) | |
17626 { | |
17627 char_u *p; | |
17628 int n; | |
17629 int len; | |
17630 int slen; | |
17631 int error = FALSE; | |
17632 | |
17633 p = get_tv_string(&argvars[0]); | |
17634 slen = (int)STRLEN(p); | |
17635 | |
17636 n = (int)get_tv_number_chk(&argvars[1], &error); | |
17637 if (error) | |
17638 len = 0; | |
17639 else if (argvars[2].v_type != VAR_UNKNOWN) | |
17640 len = (int)get_tv_number(&argvars[2]); | |
17641 else | |
17642 len = slen - n; /* default len: all bytes that are available. */ | |
17643 | |
17644 /* | |
17645 * Only return the overlap between the specified part and the actual | |
17646 * string. | |
17647 */ | |
17648 if (n < 0) | |
17649 { | |
17650 len += n; | |
17651 n = 0; | |
17652 } | |
17653 else if (n > slen) | |
17654 n = slen; | |
17655 if (len < 0) | |
17656 len = 0; | |
17657 else if (n + len > slen) | |
17658 len = slen - n; | |
17659 | |
17660 rettv->v_type = VAR_STRING; | |
17661 rettv->vval.v_string = vim_strnsave(p + n, len); | |
17662 } | |
17663 | |
17664 /* | |
17665 * "strridx()" function | |
17666 */ | |
17667 static void | |
17668 f_strridx(typval_T *argvars, typval_T *rettv) | |
17669 { | |
17670 char_u buf[NUMBUFLEN]; | |
17671 char_u *needle; | |
17672 char_u *haystack; | |
17673 char_u *rest; | |
17674 char_u *lastmatch = NULL; | |
17675 int haystack_len, end_idx; | |
17676 | |
17677 needle = get_tv_string_chk(&argvars[1]); | |
17678 haystack = get_tv_string_buf_chk(&argvars[0], buf); | |
17679 | |
17680 rettv->vval.v_number = -1; | |
17681 if (needle == NULL || haystack == NULL) | |
17682 return; /* type error; errmsg already given */ | |
17683 | |
17684 haystack_len = (int)STRLEN(haystack); | |
17685 if (argvars[2].v_type != VAR_UNKNOWN) | |
17686 { | |
17687 /* Third argument: upper limit for index */ | |
17688 end_idx = (int)get_tv_number_chk(&argvars[2], NULL); | |
17689 if (end_idx < 0) | |
17690 return; /* can never find a match */ | |
17691 } | |
17692 else | |
17693 end_idx = haystack_len; | |
17694 | |
17695 if (*needle == NUL) | |
17696 { | |
17697 /* Empty string matches past the end. */ | |
17698 lastmatch = haystack + end_idx; | |
17699 } | |
17700 else | |
17701 { | |
17702 for (rest = haystack; *rest != '\0'; ++rest) | |
17703 { | |
17704 rest = (char_u *)strstr((char *)rest, (char *)needle); | |
17705 if (rest == NULL || rest > haystack + end_idx) | |
17706 break; | |
17707 lastmatch = rest; | |
17708 } | |
17709 } | |
17710 | |
17711 if (lastmatch == NULL) | |
17712 rettv->vval.v_number = -1; | |
17713 else | |
17714 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack); | |
17715 } | |
17716 | |
17717 /* | |
17718 * "strtrans()" function | |
17719 */ | |
17720 static void | |
17721 f_strtrans(typval_T *argvars, typval_T *rettv) | |
17722 { | |
17723 rettv->v_type = VAR_STRING; | |
17724 rettv->vval.v_string = transstr(get_tv_string(&argvars[0])); | |
17725 } | |
17726 | |
17727 /* | |
17728 * "submatch()" function | |
17729 */ | |
17730 static void | |
17731 f_submatch(typval_T *argvars, typval_T *rettv) | |
17732 { | |
17733 int error = FALSE; | |
17734 int no; | |
17735 int retList = 0; | |
17736 | |
17737 no = (int)get_tv_number_chk(&argvars[0], &error); | |
17738 if (error) | |
17739 return; | |
17740 error = FALSE; | |
17741 if (argvars[1].v_type != VAR_UNKNOWN) | |
17742 retList = (int)get_tv_number_chk(&argvars[1], &error); | |
17743 if (error) | |
17744 return; | |
17745 | |
17746 if (retList == 0) | |
17747 { | |
17748 rettv->v_type = VAR_STRING; | |
17749 rettv->vval.v_string = reg_submatch(no); | |
17750 } | |
17751 else | |
17752 { | |
17753 rettv->v_type = VAR_LIST; | |
17754 rettv->vval.v_list = reg_submatch_list(no); | |
17755 } | |
17756 } | |
17757 | |
17758 /* | |
17759 * "substitute()" function | |
17760 */ | |
17761 static void | |
17762 f_substitute(typval_T *argvars, typval_T *rettv) | |
17763 { | |
17764 char_u patbuf[NUMBUFLEN]; | |
17765 char_u subbuf[NUMBUFLEN]; | |
17766 char_u flagsbuf[NUMBUFLEN]; | |
17767 | |
17768 char_u *str = get_tv_string_chk(&argvars[0]); | |
17769 char_u *pat = get_tv_string_buf_chk(&argvars[1], patbuf); | |
17770 char_u *sub = get_tv_string_buf_chk(&argvars[2], subbuf); | |
17771 char_u *flg = get_tv_string_buf_chk(&argvars[3], flagsbuf); | |
17772 | |
17773 rettv->v_type = VAR_STRING; | |
17774 if (str == NULL || pat == NULL || sub == NULL || flg == NULL) | |
17775 rettv->vval.v_string = NULL; | |
17776 else | |
17777 rettv->vval.v_string = do_string_sub(str, pat, sub, flg); | |
17778 } | |
17779 | |
17780 /* | |
17781 * "synID(lnum, col, trans)" function | |
17782 */ | |
17783 static void | |
17784 f_synID(typval_T *argvars UNUSED, typval_T *rettv) | |
17785 { | |
17786 int id = 0; | |
17787 #ifdef FEAT_SYN_HL | |
17788 linenr_T lnum; | |
17789 colnr_T col; | |
17790 int trans; | |
17791 int transerr = FALSE; | |
17792 | |
17793 lnum = get_tv_lnum(argvars); /* -1 on type error */ | |
17794 col = (linenr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ | |
17795 trans = (int)get_tv_number_chk(&argvars[2], &transerr); | |
17796 | |
17797 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count | |
17798 && col >= 0 && col < (long)STRLEN(ml_get(lnum))) | |
17799 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE); | |
17800 #endif | |
17801 | |
17802 rettv->vval.v_number = id; | |
17803 } | |
17804 | |
17805 /* | |
17806 * "synIDattr(id, what [, mode])" function | |
17807 */ | |
17808 static void | |
17809 f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) | |
17810 { | |
17811 char_u *p = NULL; | |
17812 #ifdef FEAT_SYN_HL | |
17813 int id; | |
17814 char_u *what; | |
17815 char_u *mode; | |
17816 char_u modebuf[NUMBUFLEN]; | |
17817 int modec; | |
17818 | |
17819 id = (int)get_tv_number(&argvars[0]); | |
17820 what = get_tv_string(&argvars[1]); | |
17821 if (argvars[2].v_type != VAR_UNKNOWN) | |
17822 { | |
17823 mode = get_tv_string_buf(&argvars[2], modebuf); | |
17824 modec = TOLOWER_ASC(mode[0]); | |
17825 if (modec != 't' && modec != 'c' && modec != 'g') | |
17826 modec = 0; /* replace invalid with current */ | |
17827 } | |
17828 else | |
17829 { | |
17830 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) | |
17831 if (USE_24BIT) | |
17832 modec = 'g'; | |
17833 else | |
17834 #endif | |
17835 if (t_colors > 1) | |
17836 modec = 'c'; | |
17837 else | |
17838 modec = 't'; | |
17839 } | |
17840 | |
17841 | |
17842 switch (TOLOWER_ASC(what[0])) | |
17843 { | |
17844 case 'b': | |
17845 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */ | |
17846 p = highlight_color(id, what, modec); | |
17847 else /* bold */ | |
17848 p = highlight_has_attr(id, HL_BOLD, modec); | |
17849 break; | |
17850 | |
17851 case 'f': /* fg[#] or font */ | |
17852 p = highlight_color(id, what, modec); | |
17853 break; | |
17854 | |
17855 case 'i': | |
17856 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */ | |
17857 p = highlight_has_attr(id, HL_INVERSE, modec); | |
17858 else /* italic */ | |
17859 p = highlight_has_attr(id, HL_ITALIC, modec); | |
17860 break; | |
17861 | |
17862 case 'n': /* name */ | |
17863 p = get_highlight_name(NULL, id - 1); | |
17864 break; | |
17865 | |
17866 case 'r': /* reverse */ | |
17867 p = highlight_has_attr(id, HL_INVERSE, modec); | |
17868 break; | |
17869 | |
17870 case 's': | |
17871 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */ | |
17872 p = highlight_color(id, what, modec); | |
17873 else /* standout */ | |
17874 p = highlight_has_attr(id, HL_STANDOUT, modec); | |
17875 break; | |
17876 | |
17877 case 'u': | |
17878 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') | |
17879 /* underline */ | |
17880 p = highlight_has_attr(id, HL_UNDERLINE, modec); | |
17881 else | |
17882 /* undercurl */ | |
17883 p = highlight_has_attr(id, HL_UNDERCURL, modec); | |
17884 break; | |
17885 } | |
17886 | |
17887 if (p != NULL) | |
17888 p = vim_strsave(p); | |
17889 #endif | |
17890 rettv->v_type = VAR_STRING; | |
17891 rettv->vval.v_string = p; | |
17892 } | |
17893 | |
17894 /* | |
17895 * "synIDtrans(id)" function | |
17896 */ | |
17897 static void | |
17898 f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv) | |
17899 { | |
17900 int id; | |
17901 | |
17902 #ifdef FEAT_SYN_HL | |
17903 id = (int)get_tv_number(&argvars[0]); | |
17904 | |
17905 if (id > 0) | |
17906 id = syn_get_final_id(id); | |
17907 else | |
17908 #endif | |
17909 id = 0; | |
17910 | |
17911 rettv->vval.v_number = id; | |
17912 } | |
17913 | |
17914 /* | |
17915 * "synconcealed(lnum, col)" function | |
17916 */ | |
17917 static void | |
17918 f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) | |
17919 { | |
17920 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) | |
17921 linenr_T lnum; | |
17922 colnr_T col; | |
17923 int syntax_flags = 0; | |
17924 int cchar; | |
17925 int matchid = 0; | |
17926 char_u str[NUMBUFLEN]; | |
17927 #endif | |
17928 | |
17929 rettv->v_type = VAR_LIST; | |
17930 rettv->vval.v_list = NULL; | |
17931 | |
17932 #if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL) | |
17933 lnum = get_tv_lnum(argvars); /* -1 on type error */ | |
17934 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ | |
17935 | |
17936 vim_memset(str, NUL, sizeof(str)); | |
17937 | |
17938 if (rettv_list_alloc(rettv) != FAIL) | |
17939 { | |
17940 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count | |
17941 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) | |
17942 && curwin->w_p_cole > 0) | |
17943 { | |
17944 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE); | |
17945 syntax_flags = get_syntax_info(&matchid); | |
17946 | |
17947 /* get the conceal character */ | |
17948 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3) | |
17949 { | |
17950 cchar = syn_get_sub_char(); | |
17951 if (cchar == NUL && curwin->w_p_cole == 1 && lcs_conceal != NUL) | |
17952 cchar = lcs_conceal; | |
17953 if (cchar != NUL) | |
17954 { | |
17955 # ifdef FEAT_MBYTE | |
17956 if (has_mbyte) | |
17957 (*mb_char2bytes)(cchar, str); | |
17958 else | |
17959 # endif | |
17960 str[0] = cchar; | |
17961 } | |
17962 } | |
17963 } | |
17964 | |
17965 list_append_number(rettv->vval.v_list, | |
17966 (syntax_flags & HL_CONCEAL) != 0); | |
17967 /* -1 to auto-determine strlen */ | |
17968 list_append_string(rettv->vval.v_list, str, -1); | |
17969 list_append_number(rettv->vval.v_list, matchid); | |
17970 } | |
17971 #endif | |
17972 } | |
17973 | |
17974 /* | |
17975 * "synstack(lnum, col)" function | |
17976 */ | |
17977 static void | |
17978 f_synstack(typval_T *argvars UNUSED, typval_T *rettv) | |
17979 { | |
17980 #ifdef FEAT_SYN_HL | |
17981 linenr_T lnum; | |
17982 colnr_T col; | |
17983 int i; | |
17984 int id; | |
17985 #endif | |
17986 | |
17987 rettv->v_type = VAR_LIST; | |
17988 rettv->vval.v_list = NULL; | |
17989 | |
17990 #ifdef FEAT_SYN_HL | |
17991 lnum = get_tv_lnum(argvars); /* -1 on type error */ | |
17992 col = (colnr_T)get_tv_number(&argvars[1]) - 1; /* -1 on type error */ | |
17993 | |
17994 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count | |
17995 && col >= 0 && col <= (long)STRLEN(ml_get(lnum)) | |
17996 && rettv_list_alloc(rettv) != FAIL) | |
17997 { | |
17998 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE); | |
17999 for (i = 0; ; ++i) | |
18000 { | |
18001 id = syn_get_stack_item(i); | |
18002 if (id < 0) | |
18003 break; | |
18004 if (list_append_number(rettv->vval.v_list, id) == FAIL) | |
18005 break; | |
18006 } | |
18007 } | |
18008 #endif | |
18009 } | |
18010 | |
18011 static void | |
18012 get_cmd_output_as_rettv( | |
18013 typval_T *argvars, | |
18014 typval_T *rettv, | |
18015 int retlist) | |
18016 { | |
18017 char_u *res = NULL; | |
18018 char_u *p; | |
18019 char_u *infile = NULL; | |
18020 char_u buf[NUMBUFLEN]; | |
18021 int err = FALSE; | |
18022 FILE *fd; | |
18023 list_T *list = NULL; | |
18024 int flags = SHELL_SILENT; | |
18025 | |
18026 rettv->v_type = VAR_STRING; | |
18027 rettv->vval.v_string = NULL; | |
18028 if (check_restricted() || check_secure()) | |
18029 goto errret; | |
18030 | |
18031 if (argvars[1].v_type != VAR_UNKNOWN) | |
18032 { | |
18033 /* | |
18034 * Write the string to a temp file, to be used for input of the shell | |
18035 * command. | |
18036 */ | |
18037 if ((infile = vim_tempname('i', TRUE)) == NULL) | |
18038 { | |
18039 EMSG(_(e_notmp)); | |
18040 goto errret; | |
18041 } | |
18042 | |
18043 fd = mch_fopen((char *)infile, WRITEBIN); | |
18044 if (fd == NULL) | |
18045 { | |
18046 EMSG2(_(e_notopen), infile); | |
18047 goto errret; | |
18048 } | |
18049 if (argvars[1].v_type == VAR_LIST) | |
18050 { | |
18051 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL) | |
18052 err = TRUE; | |
18053 } | |
18054 else | |
18055 { | |
18056 size_t len; | |
18057 | |
18058 p = get_tv_string_buf_chk(&argvars[1], buf); | |
18059 if (p == NULL) | |
18060 { | |
18061 fclose(fd); | |
18062 goto errret; /* type error; errmsg already given */ | |
18063 } | |
18064 len = STRLEN(p); | |
18065 if (len > 0 && fwrite(p, len, 1, fd) != 1) | |
18066 err = TRUE; | |
18067 } | |
18068 if (fclose(fd) != 0) | |
18069 err = TRUE; | |
18070 if (err) | |
18071 { | |
18072 EMSG(_("E677: Error writing temp file")); | |
18073 goto errret; | |
18074 } | |
18075 } | |
18076 | |
18077 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell | |
18078 * echoes typeahead, that messes up the display. */ | |
18079 if (!msg_silent) | |
18080 flags += SHELL_COOKED; | |
18081 | |
18082 if (retlist) | |
18083 { | |
18084 int len; | |
18085 listitem_T *li; | |
18086 char_u *s = NULL; | |
18087 char_u *start; | |
18088 char_u *end; | |
18089 int i; | |
18090 | |
18091 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, &len); | |
18092 if (res == NULL) | |
18093 goto errret; | |
18094 | |
18095 list = list_alloc(); | |
18096 if (list == NULL) | |
18097 goto errret; | |
18098 | |
18099 for (i = 0; i < len; ++i) | |
18100 { | |
18101 start = res + i; | |
18102 while (i < len && res[i] != NL) | |
18103 ++i; | |
18104 end = res + i; | |
18105 | |
18106 s = alloc((unsigned)(end - start + 1)); | |
18107 if (s == NULL) | |
18108 goto errret; | |
18109 | |
18110 for (p = s; start < end; ++p, ++start) | |
18111 *p = *start == NUL ? NL : *start; | |
18112 *p = NUL; | |
18113 | |
18114 li = listitem_alloc(); | |
18115 if (li == NULL) | |
18116 { | |
18117 vim_free(s); | |
18118 goto errret; | |
18119 } | |
18120 li->li_tv.v_type = VAR_STRING; | |
18121 li->li_tv.v_lock = 0; | |
18122 li->li_tv.vval.v_string = s; | |
18123 list_append(list, li); | |
18124 } | |
18125 | |
18126 ++list->lv_refcount; | |
18127 rettv->v_type = VAR_LIST; | |
18128 rettv->vval.v_list = list; | |
18129 list = NULL; | |
18130 } | |
18131 else | |
18132 { | |
18133 res = get_cmd_output(get_tv_string(&argvars[0]), infile, flags, NULL); | |
18134 #ifdef USE_CR | |
18135 /* translate <CR> into <NL> */ | |
18136 if (res != NULL) | |
18137 { | |
18138 char_u *s; | |
18139 | |
18140 for (s = res; *s; ++s) | |
18141 { | |
18142 if (*s == CAR) | |
18143 *s = NL; | |
18144 } | |
18145 } | |
18146 #else | |
18147 # ifdef USE_CRNL | |
18148 /* translate <CR><NL> into <NL> */ | |
18149 if (res != NULL) | |
18150 { | |
18151 char_u *s, *d; | |
18152 | |
18153 d = res; | |
18154 for (s = res; *s; ++s) | |
18155 { | |
18156 if (s[0] == CAR && s[1] == NL) | |
18157 ++s; | |
18158 *d++ = *s; | |
18159 } | |
18160 *d = NUL; | |
18161 } | |
18162 # endif | |
18163 #endif | |
18164 rettv->vval.v_string = res; | |
18165 res = NULL; | |
18166 } | |
18167 | |
18168 errret: | |
18169 if (infile != NULL) | |
18170 { | |
18171 mch_remove(infile); | |
18172 vim_free(infile); | |
18173 } | |
18174 if (res != NULL) | |
18175 vim_free(res); | |
18176 if (list != NULL) | |
18177 list_free(list); | |
18178 } | |
18179 | |
18180 /* | |
18181 * "system()" function | |
18182 */ | |
18183 static void | |
18184 f_system(typval_T *argvars, typval_T *rettv) | |
18185 { | |
18186 get_cmd_output_as_rettv(argvars, rettv, FALSE); | |
18187 } | |
18188 | |
18189 /* | |
18190 * "systemlist()" function | |
18191 */ | |
18192 static void | |
18193 f_systemlist(typval_T *argvars, typval_T *rettv) | |
18194 { | |
18195 get_cmd_output_as_rettv(argvars, rettv, TRUE); | |
18196 } | |
18197 | |
18198 /* | |
18199 * "tabpagebuflist()" function | |
18200 */ | |
18201 static void | |
18202 f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
18203 { | |
18204 #ifdef FEAT_WINDOWS | |
18205 tabpage_T *tp; | |
18206 win_T *wp = NULL; | |
18207 | |
18208 if (argvars[0].v_type == VAR_UNKNOWN) | |
18209 wp = firstwin; | |
18210 else | |
18211 { | |
18212 tp = find_tabpage((int)get_tv_number(&argvars[0])); | |
18213 if (tp != NULL) | |
18214 wp = (tp == curtab) ? firstwin : tp->tp_firstwin; | |
18215 } | |
18216 if (wp != NULL && rettv_list_alloc(rettv) != FAIL) | |
18217 { | |
18218 for (; wp != NULL; wp = wp->w_next) | |
18219 if (list_append_number(rettv->vval.v_list, | |
18220 wp->w_buffer->b_fnum) == FAIL) | |
18221 break; | |
18222 } | |
18223 #endif | |
18224 } | |
18225 | |
18226 | |
18227 /* | |
18228 * "tabpagenr()" function | |
18229 */ | |
18230 static void | |
18231 f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv) | |
18232 { | |
18233 int nr = 1; | |
18234 #ifdef FEAT_WINDOWS | |
18235 char_u *arg; | |
18236 | |
18237 if (argvars[0].v_type != VAR_UNKNOWN) | |
18238 { | |
18239 arg = get_tv_string_chk(&argvars[0]); | |
18240 nr = 0; | |
18241 if (arg != NULL) | |
18242 { | |
18243 if (STRCMP(arg, "$") == 0) | |
18244 nr = tabpage_index(NULL) - 1; | |
18245 else | |
18246 EMSG2(_(e_invexpr2), arg); | |
18247 } | |
18248 } | |
18249 else | |
18250 nr = tabpage_index(curtab); | |
18251 #endif | |
18252 rettv->vval.v_number = nr; | |
18253 } | |
18254 | |
18255 | |
18256 #ifdef FEAT_WINDOWS | |
18257 static int get_winnr(tabpage_T *tp, typval_T *argvar); | |
18258 | |
18259 /* | |
18260 * Common code for tabpagewinnr() and winnr(). | |
18261 */ | |
18262 static int | |
18263 get_winnr(tabpage_T *tp, typval_T *argvar) | |
18264 { | |
18265 win_T *twin; | |
18266 int nr = 1; | |
18267 win_T *wp; | |
18268 char_u *arg; | |
18269 | |
18270 twin = (tp == curtab) ? curwin : tp->tp_curwin; | |
18271 if (argvar->v_type != VAR_UNKNOWN) | |
18272 { | |
18273 arg = get_tv_string_chk(argvar); | |
18274 if (arg == NULL) | |
18275 nr = 0; /* type error; errmsg already given */ | |
18276 else if (STRCMP(arg, "$") == 0) | |
18277 twin = (tp == curtab) ? lastwin : tp->tp_lastwin; | |
18278 else if (STRCMP(arg, "#") == 0) | |
18279 { | |
18280 twin = (tp == curtab) ? prevwin : tp->tp_prevwin; | |
18281 if (twin == NULL) | |
18282 nr = 0; | |
18283 } | |
18284 else | |
18285 { | |
18286 EMSG2(_(e_invexpr2), arg); | |
18287 nr = 0; | |
18288 } | |
18289 } | |
18290 | |
18291 if (nr > 0) | |
18292 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; | |
18293 wp != twin; wp = wp->w_next) | |
18294 { | |
18295 if (wp == NULL) | |
18296 { | |
18297 /* didn't find it in this tabpage */ | |
18298 nr = 0; | |
18299 break; | |
18300 } | |
18301 ++nr; | |
18302 } | |
18303 return nr; | |
18304 } | |
18305 #endif | |
18306 | |
18307 /* | |
18308 * "tabpagewinnr()" function | |
18309 */ | |
18310 static void | |
18311 f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv) | |
18312 { | |
18313 int nr = 1; | |
18314 #ifdef FEAT_WINDOWS | |
18315 tabpage_T *tp; | |
18316 | |
18317 tp = find_tabpage((int)get_tv_number(&argvars[0])); | |
18318 if (tp == NULL) | |
18319 nr = 0; | |
18320 else | |
18321 nr = get_winnr(tp, &argvars[1]); | |
18322 #endif | |
18323 rettv->vval.v_number = nr; | |
18324 } | |
18325 | |
18326 | |
18327 /* | |
18328 * "tagfiles()" function | |
18329 */ | |
18330 static void | |
18331 f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv) | |
18332 { | |
18333 char_u *fname; | |
18334 tagname_T tn; | |
18335 int first; | |
18336 | |
18337 if (rettv_list_alloc(rettv) == FAIL) | |
18338 return; | |
18339 fname = alloc(MAXPATHL); | |
18340 if (fname == NULL) | |
18341 return; | |
18342 | |
18343 for (first = TRUE; ; first = FALSE) | |
18344 if (get_tagfname(&tn, first, fname) == FAIL | |
18345 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL) | |
18346 break; | |
18347 tagname_free(&tn); | |
18348 vim_free(fname); | |
18349 } | |
18350 | |
18351 /* | |
18352 * "taglist()" function | |
18353 */ | |
18354 static void | |
18355 f_taglist(typval_T *argvars, typval_T *rettv) | |
18356 { | |
18357 char_u *tag_pattern; | |
18358 | |
18359 tag_pattern = get_tv_string(&argvars[0]); | |
18360 | |
18361 rettv->vval.v_number = FALSE; | |
18362 if (*tag_pattern == NUL) | |
18363 return; | |
18364 | |
18365 if (rettv_list_alloc(rettv) == OK) | |
18366 (void)get_tags(rettv->vval.v_list, tag_pattern); | |
18367 } | |
18368 | |
18369 /* | |
18370 * "tempname()" function | |
18371 */ | |
18372 static void | |
18373 f_tempname(typval_T *argvars UNUSED, typval_T *rettv) | |
18374 { | |
18375 static int x = 'A'; | |
18376 | |
18377 rettv->v_type = VAR_STRING; | |
18378 rettv->vval.v_string = vim_tempname(x, FALSE); | |
18379 | |
18380 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different | |
18381 * names. Skip 'I' and 'O', they are used for shell redirection. */ | |
18382 do | |
18383 { | |
18384 if (x == 'Z') | |
18385 x = '0'; | |
18386 else if (x == '9') | |
18387 x = 'A'; | |
18388 else | |
18389 { | |
18390 #ifdef EBCDIC | |
18391 if (x == 'I') | |
18392 x = 'J'; | |
18393 else if (x == 'R') | |
18394 x = 'S'; | |
18395 else | |
18396 #endif | |
18397 ++x; | |
18398 } | |
18399 } while (x == 'I' || x == 'O'); | |
18400 } | |
18401 | |
18402 #ifdef FEAT_FLOAT | |
18403 /* | |
18404 * "tan()" function | |
18405 */ | |
18406 static void | |
18407 f_tan(typval_T *argvars, typval_T *rettv) | |
18408 { | |
18409 float_T f = 0.0; | |
18410 | |
18411 rettv->v_type = VAR_FLOAT; | |
18412 if (get_float_arg(argvars, &f) == OK) | |
18413 rettv->vval.v_float = tan(f); | |
18414 else | |
18415 rettv->vval.v_float = 0.0; | |
18416 } | |
18417 | |
18418 /* | |
18419 * "tanh()" function | |
18420 */ | |
18421 static void | |
18422 f_tanh(typval_T *argvars, typval_T *rettv) | |
18423 { | |
18424 float_T f = 0.0; | |
18425 | |
18426 rettv->v_type = VAR_FLOAT; | |
18427 if (get_float_arg(argvars, &f) == OK) | |
18428 rettv->vval.v_float = tanh(f); | |
18429 else | |
18430 rettv->vval.v_float = 0.0; | |
18431 } | |
18432 #endif | |
18433 | |
18434 /* | |
18435 * "test_alloc_fail(id, countdown, repeat)" function | |
18436 */ | |
18437 static void | |
18438 f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED) | |
18439 { | |
18440 if (argvars[0].v_type != VAR_NUMBER | |
18441 || argvars[0].vval.v_number <= 0 | |
18442 || argvars[1].v_type != VAR_NUMBER | |
18443 || argvars[1].vval.v_number < 0 | |
18444 || argvars[2].v_type != VAR_NUMBER) | |
18445 EMSG(_(e_invarg)); | |
18446 else | |
18447 { | |
18448 alloc_fail_id = argvars[0].vval.v_number; | |
18449 if (alloc_fail_id >= aid_last) | |
18450 EMSG(_(e_invarg)); | |
18451 alloc_fail_countdown = argvars[1].vval.v_number; | |
18452 alloc_fail_repeat = argvars[2].vval.v_number; | |
18453 did_outofmem_msg = FALSE; | |
18454 } | |
18455 } | |
18456 | |
18457 /* | |
18458 * "test_autochdir()" | |
18459 */ | |
18460 static void | |
18461 f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
18462 { | |
18463 #if defined(FEAT_AUTOCHDIR) | |
18464 test_autochdir = TRUE; | |
18465 #endif | |
18466 } | |
18467 | |
18468 /* | |
18469 * "test_disable_char_avail({expr})" function | |
18470 */ | |
18471 static void | |
18472 f_test_disable_char_avail(typval_T *argvars, typval_T *rettv UNUSED) | |
18473 { | |
18474 disable_char_avail_for_testing = (int)get_tv_number(&argvars[0]); | |
18475 } | |
18476 | |
18477 /* | |
18478 * "test_garbagecollect_now()" function | |
18479 */ | |
18480 static void | |
18481 f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
18482 { | |
18483 /* This is dangerous, any Lists and Dicts used internally may be freed | |
18484 * while still in use. */ | |
18485 garbage_collect(TRUE); | |
18486 } | |
18487 | |
18488 #ifdef FEAT_JOB_CHANNEL | |
18489 static void | |
18490 f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv) | |
18491 { | |
18492 rettv->v_type = VAR_CHANNEL; | |
18493 rettv->vval.v_channel = NULL; | |
18494 } | |
18495 #endif | |
18496 | |
18497 static void | |
18498 f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv) | |
18499 { | |
18500 rettv->v_type = VAR_DICT; | |
18501 rettv->vval.v_dict = NULL; | |
18502 } | |
18503 | |
18504 #ifdef FEAT_JOB_CHANNEL | |
18505 static void | |
18506 f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv) | |
18507 { | |
18508 rettv->v_type = VAR_JOB; | |
18509 rettv->vval.v_job = NULL; | |
18510 } | |
18511 #endif | |
18512 | |
18513 static void | |
18514 f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv) | |
18515 { | |
18516 rettv->v_type = VAR_LIST; | |
18517 rettv->vval.v_list = NULL; | |
18518 } | |
18519 | |
18520 static void | |
18521 f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv) | |
18522 { | |
18523 rettv->v_type = VAR_PARTIAL; | |
18524 rettv->vval.v_partial = NULL; | |
18525 } | |
18526 | |
18527 static void | |
18528 f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv) | |
18529 { | |
18530 rettv->v_type = VAR_STRING; | |
18531 rettv->vval.v_string = NULL; | |
18532 } | |
18533 | |
18534 static void | |
18535 f_test_settime(typval_T *argvars, typval_T *rettv UNUSED) | |
18536 { | |
18537 time_for_testing = (time_t)get_tv_number(&argvars[0]); | |
18538 } | |
18539 | |
18540 #if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO) | |
18541 /* | |
18542 * Get a callback from "arg". It can be a Funcref or a function name. | |
18543 * When "arg" is zero return an empty string. | |
18544 * Return NULL for an invalid argument. | |
18545 */ | |
18546 char_u * | |
18547 get_callback(typval_T *arg, partial_T **pp) | |
18548 { | |
18549 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) | |
18550 { | |
18551 *pp = arg->vval.v_partial; | |
18552 ++(*pp)->pt_refcount; | |
18553 return (*pp)->pt_name; | |
18554 } | |
18555 *pp = NULL; | |
18556 if (arg->v_type == VAR_FUNC) | |
18557 { | |
18558 func_ref(arg->vval.v_string); | |
18559 return arg->vval.v_string; | |
18560 } | |
18561 if (arg->v_type == VAR_STRING) | |
18562 return arg->vval.v_string; | |
18563 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) | |
18564 return (char_u *)""; | |
18565 EMSG(_("E921: Invalid callback argument")); | |
18566 return NULL; | |
18567 } | |
18568 | |
18569 /* | |
18570 * Unref/free "callback" and "partial" retured by get_callback(). | |
18571 */ | |
18572 void | |
18573 free_callback(char_u *callback, partial_T *partial) | |
18574 { | |
18575 if (partial != NULL) | |
18576 partial_unref(partial); | |
18577 else if (callback != NULL) | |
18578 { | |
18579 func_unref(callback); | |
18580 vim_free(callback); | |
18581 } | |
18582 } | |
18583 #endif | |
18584 | |
18585 #ifdef FEAT_TIMERS | |
18586 /* | |
18587 * "timer_start(time, callback [, options])" function | |
18588 */ | |
18589 static void | |
18590 f_timer_start(typval_T *argvars, typval_T *rettv) | |
18591 { | |
18592 long msec = (long)get_tv_number(&argvars[0]); | |
18593 timer_T *timer; | |
18594 int repeat = 0; | |
18595 char_u *callback; | |
18596 dict_T *dict; | |
18597 | |
18598 if (check_secure()) | |
18599 return; | |
18600 if (argvars[2].v_type != VAR_UNKNOWN) | |
18601 { | |
18602 if (argvars[2].v_type != VAR_DICT | |
18603 || (dict = argvars[2].vval.v_dict) == NULL) | |
18604 { | |
18605 EMSG2(_(e_invarg2), get_tv_string(&argvars[2])); | |
18606 return; | |
18607 } | |
18608 if (dict_find(dict, (char_u *)"repeat", -1) != NULL) | |
18609 repeat = get_dict_number(dict, (char_u *)"repeat"); | |
18610 } | |
18611 | |
18612 timer = create_timer(msec, repeat); | |
18613 callback = get_callback(&argvars[1], &timer->tr_partial); | |
18614 if (callback == NULL) | |
18615 { | |
18616 stop_timer(timer); | |
18617 rettv->vval.v_number = -1; | |
18618 } | |
18619 else | |
18620 { | |
18621 timer->tr_callback = vim_strsave(callback); | |
18622 rettv->vval.v_number = timer->tr_id; | |
18623 } | |
18624 } | |
18625 | |
18626 /* | |
18627 * "timer_stop(timer)" function | |
18628 */ | |
18629 static void | |
18630 f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) | |
18631 { | |
18632 timer_T *timer; | |
18633 | |
18634 if (argvars[0].v_type != VAR_NUMBER) | |
18635 { | |
18636 EMSG(_(e_number_exp)); | |
18637 return; | |
18638 } | |
18639 timer = find_timer((int)get_tv_number(&argvars[0])); | |
18640 if (timer != NULL) | |
18641 stop_timer(timer); | |
18642 } | |
18643 #endif | |
18644 | |
18645 /* | |
18646 * "tolower(string)" function | |
18647 */ | |
18648 static void | |
18649 f_tolower(typval_T *argvars, typval_T *rettv) | |
18650 { | |
18651 char_u *p; | |
18652 | |
18653 p = vim_strsave(get_tv_string(&argvars[0])); | |
18654 rettv->v_type = VAR_STRING; | |
18655 rettv->vval.v_string = p; | |
18656 | |
18657 if (p != NULL) | |
18658 while (*p != NUL) | |
18659 { | |
18660 #ifdef FEAT_MBYTE | |
18661 int l; | |
18662 | |
18663 if (enc_utf8) | |
18664 { | |
18665 int c, lc; | |
18666 | |
18667 c = utf_ptr2char(p); | |
18668 lc = utf_tolower(c); | |
18669 l = utf_ptr2len(p); | |
18670 /* TODO: reallocate string when byte count changes. */ | |
18671 if (utf_char2len(lc) == l) | |
18672 utf_char2bytes(lc, p); | |
18673 p += l; | |
18674 } | |
18675 else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) | |
18676 p += l; /* skip multi-byte character */ | |
18677 else | |
18678 #endif | |
18679 { | |
18680 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */ | |
18681 ++p; | |
18682 } | |
18683 } | |
18684 } | |
18685 | |
18686 /* | |
18687 * "toupper(string)" function | |
18688 */ | |
18689 static void | |
18690 f_toupper(typval_T *argvars, typval_T *rettv) | |
18691 { | |
18692 rettv->v_type = VAR_STRING; | |
18693 rettv->vval.v_string = strup_save(get_tv_string(&argvars[0])); | |
18694 } | |
18695 | |
18696 /* | |
18697 * "tr(string, fromstr, tostr)" function | |
18698 */ | |
18699 static void | |
18700 f_tr(typval_T *argvars, typval_T *rettv) | |
18701 { | |
18702 char_u *in_str; | |
18703 char_u *fromstr; | |
18704 char_u *tostr; | |
18705 char_u *p; | |
18706 #ifdef FEAT_MBYTE | |
18707 int inlen; | |
18708 int fromlen; | |
18709 int tolen; | |
18710 int idx; | |
18711 char_u *cpstr; | |
18712 int cplen; | |
18713 int first = TRUE; | |
18714 #endif | |
18715 char_u buf[NUMBUFLEN]; | |
18716 char_u buf2[NUMBUFLEN]; | |
18717 garray_T ga; | |
18718 | |
18719 in_str = get_tv_string(&argvars[0]); | |
18720 fromstr = get_tv_string_buf_chk(&argvars[1], buf); | |
18721 tostr = get_tv_string_buf_chk(&argvars[2], buf2); | |
18722 | |
18723 /* Default return value: empty string. */ | |
18724 rettv->v_type = VAR_STRING; | |
18725 rettv->vval.v_string = NULL; | |
18726 if (fromstr == NULL || tostr == NULL) | |
18727 return; /* type error; errmsg already given */ | |
18728 ga_init2(&ga, (int)sizeof(char), 80); | |
18729 | |
18730 #ifdef FEAT_MBYTE | |
18731 if (!has_mbyte) | |
18732 #endif | |
18733 /* not multi-byte: fromstr and tostr must be the same length */ | |
18734 if (STRLEN(fromstr) != STRLEN(tostr)) | |
18735 { | |
18736 #ifdef FEAT_MBYTE | |
18737 error: | |
18738 #endif | |
18739 EMSG2(_(e_invarg2), fromstr); | |
18740 ga_clear(&ga); | |
18741 return; | |
18742 } | |
18743 | |
18744 /* fromstr and tostr have to contain the same number of chars */ | |
18745 while (*in_str != NUL) | |
18746 { | |
18747 #ifdef FEAT_MBYTE | |
18748 if (has_mbyte) | |
18749 { | |
18750 inlen = (*mb_ptr2len)(in_str); | |
18751 cpstr = in_str; | |
18752 cplen = inlen; | |
18753 idx = 0; | |
18754 for (p = fromstr; *p != NUL; p += fromlen) | |
18755 { | |
18756 fromlen = (*mb_ptr2len)(p); | |
18757 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0) | |
18758 { | |
18759 for (p = tostr; *p != NUL; p += tolen) | |
18760 { | |
18761 tolen = (*mb_ptr2len)(p); | |
18762 if (idx-- == 0) | |
18763 { | |
18764 cplen = tolen; | |
18765 cpstr = p; | |
18766 break; | |
18767 } | |
18768 } | |
18769 if (*p == NUL) /* tostr is shorter than fromstr */ | |
18770 goto error; | |
18771 break; | |
18772 } | |
18773 ++idx; | |
18774 } | |
18775 | |
18776 if (first && cpstr == in_str) | |
18777 { | |
18778 /* Check that fromstr and tostr have the same number of | |
18779 * (multi-byte) characters. Done only once when a character | |
18780 * of in_str doesn't appear in fromstr. */ | |
18781 first = FALSE; | |
18782 for (p = tostr; *p != NUL; p += tolen) | |
18783 { | |
18784 tolen = (*mb_ptr2len)(p); | |
18785 --idx; | |
18786 } | |
18787 if (idx != 0) | |
18788 goto error; | |
18789 } | |
18790 | |
18791 (void)ga_grow(&ga, cplen); | |
18792 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen); | |
18793 ga.ga_len += cplen; | |
18794 | |
18795 in_str += inlen; | |
18796 } | |
18797 else | |
18798 #endif | |
18799 { | |
18800 /* When not using multi-byte chars we can do it faster. */ | |
18801 p = vim_strchr(fromstr, *in_str); | |
18802 if (p != NULL) | |
18803 ga_append(&ga, tostr[p - fromstr]); | |
18804 else | |
18805 ga_append(&ga, *in_str); | |
18806 ++in_str; | |
18807 } | |
18808 } | |
18809 | |
18810 /* add a terminating NUL */ | |
18811 (void)ga_grow(&ga, 1); | |
18812 ga_append(&ga, NUL); | |
18813 | |
18814 rettv->vval.v_string = ga.ga_data; | |
18815 } | |
18816 | |
18817 #ifdef FEAT_FLOAT | |
18818 /* | |
18819 * "trunc({float})" function | |
18820 */ | |
18821 static void | |
18822 f_trunc(typval_T *argvars, typval_T *rettv) | |
18823 { | |
18824 float_T f = 0.0; | |
18825 | |
18826 rettv->v_type = VAR_FLOAT; | |
18827 if (get_float_arg(argvars, &f) == OK) | |
18828 /* trunc() is not in C90, use floor() or ceil() instead. */ | |
18829 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f); | |
18830 else | |
18831 rettv->vval.v_float = 0.0; | |
18832 } | |
18833 #endif | |
18834 | |
18835 /* | |
18836 * "type(expr)" function | |
18837 */ | |
18838 static void | |
18839 f_type(typval_T *argvars, typval_T *rettv) | |
18840 { | |
18841 int n = -1; | |
18842 | |
18843 switch (argvars[0].v_type) | |
18844 { | |
18845 case VAR_NUMBER: n = 0; break; | |
18846 case VAR_STRING: n = 1; break; | |
18847 case VAR_PARTIAL: | |
18848 case VAR_FUNC: n = 2; break; | |
18849 case VAR_LIST: n = 3; break; | |
18850 case VAR_DICT: n = 4; break; | |
18851 case VAR_FLOAT: n = 5; break; | |
18852 case VAR_SPECIAL: | |
18853 if (argvars[0].vval.v_number == VVAL_FALSE | |
18854 || argvars[0].vval.v_number == VVAL_TRUE) | |
18855 n = 6; | |
18856 else | |
18857 n = 7; | |
18858 break; | |
18859 case VAR_JOB: n = 8; break; | |
18860 case VAR_CHANNEL: n = 9; break; | |
18861 case VAR_UNKNOWN: | |
18862 EMSG2(_(e_intern2), "f_type(UNKNOWN)"); | |
18863 n = -1; | |
18864 break; | |
18865 } | |
18866 rettv->vval.v_number = n; | |
18867 } | |
18868 | |
18869 /* | |
18870 * "undofile(name)" function | |
18871 */ | |
18872 static void | |
18873 f_undofile(typval_T *argvars UNUSED, typval_T *rettv) | |
18874 { | |
18875 rettv->v_type = VAR_STRING; | |
18876 #ifdef FEAT_PERSISTENT_UNDO | |
18877 { | |
18878 char_u *fname = get_tv_string(&argvars[0]); | |
18879 | |
18880 if (*fname == NUL) | |
18881 { | |
18882 /* If there is no file name there will be no undo file. */ | |
18883 rettv->vval.v_string = NULL; | |
18884 } | |
18885 else | |
18886 { | |
18887 char_u *ffname = FullName_save(fname, FALSE); | |
18888 | |
18889 if (ffname != NULL) | |
18890 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE); | |
18891 vim_free(ffname); | |
18892 } | |
18893 } | |
18894 #else | |
18895 rettv->vval.v_string = NULL; | |
18896 #endif | |
18897 } | |
18898 | |
18899 /* | |
18900 * "undotree()" function | |
18901 */ | |
18902 static void | |
18903 f_undotree(typval_T *argvars UNUSED, typval_T *rettv) | |
18904 { | |
18905 if (rettv_dict_alloc(rettv) == OK) | |
18906 { | |
18907 dict_T *dict = rettv->vval.v_dict; | |
18908 list_T *list; | |
18909 | |
18910 dict_add_nr_str(dict, "synced", (long)curbuf->b_u_synced, NULL); | |
18911 dict_add_nr_str(dict, "seq_last", curbuf->b_u_seq_last, NULL); | |
18912 dict_add_nr_str(dict, "save_last", | |
18913 (long)curbuf->b_u_save_nr_last, NULL); | |
18914 dict_add_nr_str(dict, "seq_cur", curbuf->b_u_seq_cur, NULL); | |
18915 dict_add_nr_str(dict, "time_cur", (long)curbuf->b_u_time_cur, NULL); | |
18916 dict_add_nr_str(dict, "save_cur", (long)curbuf->b_u_save_nr_cur, NULL); | |
18917 | |
18918 list = list_alloc(); | |
18919 if (list != NULL) | |
18920 { | |
18921 u_eval_tree(curbuf->b_u_oldhead, list); | |
18922 dict_add_list(dict, "entries", list); | |
18923 } | |
18924 } | |
18925 } | |
18926 | |
18927 /* | |
18928 * "values(dict)" function | |
18929 */ | |
18930 static void | |
18931 f_values(typval_T *argvars, typval_T *rettv) | |
18932 { | |
18933 dict_list(argvars, rettv, 1); | |
18934 } | |
18935 | |
18936 /* | |
18937 * "virtcol(string)" function | |
18938 */ | |
18939 static void | |
18940 f_virtcol(typval_T *argvars, typval_T *rettv) | |
18941 { | |
18942 colnr_T vcol = 0; | |
18943 pos_T *fp; | |
18944 int fnum = curbuf->b_fnum; | |
18945 | |
18946 fp = var2fpos(&argvars[0], FALSE, &fnum); | |
18947 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count | |
18948 && fnum == curbuf->b_fnum) | |
18949 { | |
18950 getvvcol(curwin, fp, NULL, NULL, &vcol); | |
18951 ++vcol; | |
18952 } | |
18953 | |
18954 rettv->vval.v_number = vcol; | |
18955 } | |
18956 | |
18957 /* | |
18958 * "visualmode()" function | |
18959 */ | |
18960 static void | |
18961 f_visualmode(typval_T *argvars, typval_T *rettv) | |
18962 { | |
18963 char_u str[2]; | |
18964 | |
18965 rettv->v_type = VAR_STRING; | |
18966 str[0] = curbuf->b_visual_mode_eval; | |
18967 str[1] = NUL; | |
18968 rettv->vval.v_string = vim_strsave(str); | |
18969 | |
18970 /* A non-zero number or non-empty string argument: reset mode. */ | |
18971 if (non_zero_arg(&argvars[0])) | |
18972 curbuf->b_visual_mode_eval = NUL; | |
18973 } | |
18974 | |
18975 /* | |
18976 * "wildmenumode()" function | |
18977 */ | |
18978 static void | |
18979 f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED) | |
18980 { | |
18981 #ifdef FEAT_WILDMENU | |
18982 if (wild_menu_showing) | |
18983 rettv->vval.v_number = 1; | |
18984 #endif | |
18985 } | |
18986 | |
18987 /* | |
18988 * "winbufnr(nr)" function | |
18989 */ | |
18990 static void | |
18991 f_winbufnr(typval_T *argvars, typval_T *rettv) | |
18992 { | |
18993 win_T *wp; | |
18994 | |
18995 wp = find_win_by_nr(&argvars[0], NULL); | |
18996 if (wp == NULL) | |
18997 rettv->vval.v_number = -1; | |
18998 else | |
18999 rettv->vval.v_number = wp->w_buffer->b_fnum; | |
19000 } | |
19001 | |
19002 /* | |
19003 * "wincol()" function | |
19004 */ | |
19005 static void | |
19006 f_wincol(typval_T *argvars UNUSED, typval_T *rettv) | |
19007 { | |
19008 validate_cursor(); | |
19009 rettv->vval.v_number = curwin->w_wcol + 1; | |
19010 } | |
19011 | |
19012 /* | |
19013 * "winheight(nr)" function | |
19014 */ | |
19015 static void | |
19016 f_winheight(typval_T *argvars, typval_T *rettv) | |
19017 { | |
19018 win_T *wp; | |
19019 | |
19020 wp = find_win_by_nr(&argvars[0], NULL); | |
19021 if (wp == NULL) | |
19022 rettv->vval.v_number = -1; | |
19023 else | |
19024 rettv->vval.v_number = wp->w_height; | |
19025 } | |
19026 | |
19027 /* | |
19028 * "winline()" function | |
19029 */ | |
19030 static void | |
19031 f_winline(typval_T *argvars UNUSED, typval_T *rettv) | |
19032 { | |
19033 validate_cursor(); | |
19034 rettv->vval.v_number = curwin->w_wrow + 1; | |
19035 } | |
19036 | |
19037 /* | |
19038 * "winnr()" function | |
19039 */ | |
19040 static void | |
19041 f_winnr(typval_T *argvars UNUSED, typval_T *rettv) | |
19042 { | |
19043 int nr = 1; | |
19044 | |
19045 #ifdef FEAT_WINDOWS | |
19046 nr = get_winnr(curtab, &argvars[0]); | |
19047 #endif | |
19048 rettv->vval.v_number = nr; | |
19049 } | |
19050 | |
19051 /* | |
19052 * "winrestcmd()" function | |
19053 */ | |
19054 static void | |
19055 f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv) | |
19056 { | |
19057 #ifdef FEAT_WINDOWS | |
19058 win_T *wp; | |
19059 int winnr = 1; | |
19060 garray_T ga; | |
19061 char_u buf[50]; | |
19062 | |
19063 ga_init2(&ga, (int)sizeof(char), 70); | |
19064 for (wp = firstwin; wp != NULL; wp = wp->w_next) | |
19065 { | |
19066 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height); | |
19067 ga_concat(&ga, buf); | |
19068 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width); | |
19069 ga_concat(&ga, buf); | |
19070 ++winnr; | |
19071 } | |
19072 ga_append(&ga, NUL); | |
19073 | |
19074 rettv->vval.v_string = ga.ga_data; | |
19075 #else | |
19076 rettv->vval.v_string = NULL; | |
19077 #endif | |
19078 rettv->v_type = VAR_STRING; | |
19079 } | |
19080 | |
19081 /* | |
19082 * "winrestview()" function | |
19083 */ | |
19084 static void | |
19085 f_winrestview(typval_T *argvars, typval_T *rettv UNUSED) | |
19086 { | |
19087 dict_T *dict; | |
19088 | |
19089 if (argvars[0].v_type != VAR_DICT | |
19090 || (dict = argvars[0].vval.v_dict) == NULL) | |
19091 EMSG(_(e_invarg)); | |
19092 else | |
19093 { | |
19094 if (dict_find(dict, (char_u *)"lnum", -1) != NULL) | |
19095 curwin->w_cursor.lnum = (linenr_T)get_dict_number(dict, (char_u *)"lnum"); | |
19096 if (dict_find(dict, (char_u *)"col", -1) != NULL) | |
19097 curwin->w_cursor.col = (colnr_T)get_dict_number(dict, (char_u *)"col"); | |
19098 #ifdef FEAT_VIRTUALEDIT | |
19099 if (dict_find(dict, (char_u *)"coladd", -1) != NULL) | |
19100 curwin->w_cursor.coladd = (colnr_T)get_dict_number(dict, (char_u *)"coladd"); | |
19101 #endif | |
19102 if (dict_find(dict, (char_u *)"curswant", -1) != NULL) | |
19103 { | |
19104 curwin->w_curswant = (colnr_T)get_dict_number(dict, (char_u *)"curswant"); | |
19105 curwin->w_set_curswant = FALSE; | |
19106 } | |
19107 | |
19108 if (dict_find(dict, (char_u *)"topline", -1) != NULL) | |
19109 set_topline(curwin, (linenr_T)get_dict_number(dict, (char_u *)"topline")); | |
19110 #ifdef FEAT_DIFF | |
19111 if (dict_find(dict, (char_u *)"topfill", -1) != NULL) | |
19112 curwin->w_topfill = (int)get_dict_number(dict, (char_u *)"topfill"); | |
19113 #endif | |
19114 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL) | |
19115 curwin->w_leftcol = (colnr_T)get_dict_number(dict, (char_u *)"leftcol"); | |
19116 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL) | |
19117 curwin->w_skipcol = (colnr_T)get_dict_number(dict, (char_u *)"skipcol"); | |
19118 | |
19119 check_cursor(); | |
19120 win_new_height(curwin, curwin->w_height); | |
19121 # ifdef FEAT_WINDOWS | |
19122 win_new_width(curwin, W_WIDTH(curwin)); | |
19123 # endif | |
19124 changed_window_setting(); | |
19125 | |
19126 if (curwin->w_topline <= 0) | |
19127 curwin->w_topline = 1; | |
19128 if (curwin->w_topline > curbuf->b_ml.ml_line_count) | |
19129 curwin->w_topline = curbuf->b_ml.ml_line_count; | |
19130 #ifdef FEAT_DIFF | |
19131 check_topfill(curwin, TRUE); | |
19132 #endif | |
19133 } | |
19134 } | |
19135 | |
19136 /* | |
19137 * "winsaveview()" function | |
19138 */ | |
19139 static void | |
19140 f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv) | |
19141 { | |
19142 dict_T *dict; | |
19143 | |
19144 if (rettv_dict_alloc(rettv) == FAIL) | |
19145 return; | |
19146 dict = rettv->vval.v_dict; | |
19147 | |
19148 dict_add_nr_str(dict, "lnum", (long)curwin->w_cursor.lnum, NULL); | |
19149 dict_add_nr_str(dict, "col", (long)curwin->w_cursor.col, NULL); | |
19150 #ifdef FEAT_VIRTUALEDIT | |
19151 dict_add_nr_str(dict, "coladd", (long)curwin->w_cursor.coladd, NULL); | |
19152 #endif | |
19153 update_curswant(); | |
19154 dict_add_nr_str(dict, "curswant", (long)curwin->w_curswant, NULL); | |
19155 | |
19156 dict_add_nr_str(dict, "topline", (long)curwin->w_topline, NULL); | |
19157 #ifdef FEAT_DIFF | |
19158 dict_add_nr_str(dict, "topfill", (long)curwin->w_topfill, NULL); | |
19159 #endif | |
19160 dict_add_nr_str(dict, "leftcol", (long)curwin->w_leftcol, NULL); | |
19161 dict_add_nr_str(dict, "skipcol", (long)curwin->w_skipcol, NULL); | |
19162 } | |
19163 | |
19164 /* | |
19165 * "winwidth(nr)" function | |
19166 */ | |
19167 static void | |
19168 f_winwidth(typval_T *argvars, typval_T *rettv) | |
19169 { | |
19170 win_T *wp; | |
19171 | |
19172 wp = find_win_by_nr(&argvars[0], NULL); | |
19173 if (wp == NULL) | |
19174 rettv->vval.v_number = -1; | |
19175 else | |
19176 #ifdef FEAT_WINDOWS | |
19177 rettv->vval.v_number = wp->w_width; | |
19178 #else | |
19179 rettv->vval.v_number = Columns; | |
19180 #endif | |
19181 } | |
19182 | |
19183 /* | |
19184 * "wordcount()" function | |
19185 */ | |
19186 static void | |
19187 f_wordcount(typval_T *argvars UNUSED, typval_T *rettv) | |
19188 { | |
19189 if (rettv_dict_alloc(rettv) == FAIL) | |
19190 return; | |
19191 cursor_pos_info(rettv->vval.v_dict); | |
19192 } | |
19193 | |
19194 /* | |
19195 * Write list of strings to file | |
19196 */ | |
19197 static int | |
19198 write_list(FILE *fd, list_T *list, int binary) | |
19199 { | |
19200 listitem_T *li; | |
19201 int c; | |
19202 int ret = OK; | |
19203 char_u *s; | |
19204 | |
19205 for (li = list->lv_first; li != NULL; li = li->li_next) | |
19206 { | |
19207 for (s = get_tv_string(&li->li_tv); *s != NUL; ++s) | |
19208 { | |
19209 if (*s == '\n') | |
19210 c = putc(NUL, fd); | |
19211 else | |
19212 c = putc(*s, fd); | |
19213 if (c == EOF) | |
19214 { | |
19215 ret = FAIL; | |
19216 break; | |
19217 } | |
19218 } | |
19219 if (!binary || li->li_next != NULL) | |
19220 if (putc('\n', fd) == EOF) | |
19221 { | |
19222 ret = FAIL; | |
19223 break; | |
19224 } | |
19225 if (ret == FAIL) | |
19226 { | |
19227 EMSG(_(e_write)); | |
19228 break; | |
19229 } | |
19230 } | |
19231 return ret; | |
19232 } | |
19233 | |
19234 /* | |
19235 * "writefile()" function | |
19236 */ | |
19237 static void | |
19238 f_writefile(typval_T *argvars, typval_T *rettv) | |
19239 { | |
19240 int binary = FALSE; | |
19241 int append = FALSE; | |
19242 char_u *fname; | |
19243 FILE *fd; | |
19244 int ret = 0; | |
19245 | |
19246 if (check_restricted() || check_secure()) | |
19247 return; | |
19248 | |
19249 if (argvars[0].v_type != VAR_LIST) | |
19250 { | |
19251 EMSG2(_(e_listarg), "writefile()"); | |
19252 return; | |
19253 } | |
19254 if (argvars[0].vval.v_list == NULL) | |
19255 return; | |
19256 | |
19257 if (argvars[2].v_type != VAR_UNKNOWN) | |
19258 { | |
19259 if (vim_strchr(get_tv_string(&argvars[2]), 'b') != NULL) | |
19260 binary = TRUE; | |
19261 if (vim_strchr(get_tv_string(&argvars[2]), 'a') != NULL) | |
19262 append = TRUE; | |
19263 } | |
19264 | |
19265 /* Always open the file in binary mode, library functions have a mind of | |
19266 * their own about CR-LF conversion. */ | |
19267 fname = get_tv_string(&argvars[1]); | |
19268 if (*fname == NUL || (fd = mch_fopen((char *)fname, | |
19269 append ? APPENDBIN : WRITEBIN)) == NULL) | |
19270 { | |
19271 EMSG2(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname); | |
19272 ret = -1; | |
19273 } | |
19274 else | |
19275 { | |
19276 if (write_list(fd, argvars[0].vval.v_list, binary) == FAIL) | |
19277 ret = -1; | |
19278 fclose(fd); | |
19279 } | |
19280 | |
19281 rettv->vval.v_number = ret; | |
19282 } | |
19283 | |
19284 /* | |
19285 * "xor(expr, expr)" function | |
19286 */ | |
19287 static void | |
19288 f_xor(typval_T *argvars, typval_T *rettv) | |
19289 { | |
19290 rettv->vval.v_number = get_tv_number_chk(&argvars[0], NULL) | |
19291 ^ get_tv_number_chk(&argvars[1], NULL); | |
19292 } | |
19293 | 5973 |
19294 | 5974 |
19295 /* | 5975 /* |
19296 * Translate a String variable into a position. | 5976 * Translate a String variable into a position. |
19297 * Returns NULL when there is an error. | 5977 * Returns NULL when there is an error. |
19298 */ | 5978 */ |
19299 static pos_T * | 5979 pos_T * |
19300 var2fpos( | 5980 var2fpos( |
19301 typval_T *varp, | 5981 typval_T *varp, |
19302 int dollar_lnum, /* TRUE when $ is last line */ | 5982 int dollar_lnum, /* TRUE when $ is last line */ |
19303 int *fnum) /* set to fnum for '0, 'A, etc. */ | 5983 int *fnum) /* set to fnum for '0, 'A, etc. */ |
19304 { | 5984 { |
19413 * Note that the column is passed on as-is, the caller may want to decrement | 6093 * Note that the column is passed on as-is, the caller may want to decrement |
19414 * it to use 1 for the first column. | 6094 * it to use 1 for the first column. |
19415 * Return FAIL when conversion is not possible, doesn't check the position for | 6095 * Return FAIL when conversion is not possible, doesn't check the position for |
19416 * validity. | 6096 * validity. |
19417 */ | 6097 */ |
19418 static int | 6098 int |
19419 list2fpos( | 6099 list2fpos( |
19420 typval_T *arg, | 6100 typval_T *arg, |
19421 pos_T *posp, | 6101 pos_T *posp, |
19422 int *fnump, | 6102 int *fnump, |
19423 colnr_T *curswantp) | 6103 colnr_T *curswantp) |
19529 * Return -1 if curly braces expansion failed. | 6209 * Return -1 if curly braces expansion failed. |
19530 * Return 0 if something else is wrong. | 6210 * Return 0 if something else is wrong. |
19531 * If the name contains 'magic' {}'s, expand them and return the | 6211 * If the name contains 'magic' {}'s, expand them and return the |
19532 * expanded name in an allocated string via 'alias' - caller must free. | 6212 * expanded name in an allocated string via 'alias' - caller must free. |
19533 */ | 6213 */ |
19534 static int | 6214 int |
19535 get_name_len( | 6215 get_name_len( |
19536 char_u **arg, | 6216 char_u **arg, |
19537 char_u **alias, | 6217 char_u **alias, |
19538 int evaluate, | 6218 int evaluate, |
19539 int verbose) | 6219 int verbose) |
20030 | 6710 |
20031 /* | 6711 /* |
20032 * Get the value of internal variable "name". | 6712 * Get the value of internal variable "name". |
20033 * Return OK or FAIL. | 6713 * Return OK or FAIL. |
20034 */ | 6714 */ |
20035 static int | 6715 int |
20036 get_var_tv( | 6716 get_var_tv( |
20037 char_u *name, | 6717 char_u *name, |
20038 int len, /* length of "name" */ | 6718 int len, /* length of "name" */ |
20039 typval_T *rettv, /* NULL when only checking existence */ | 6719 typval_T *rettv, /* NULL when only checking existence */ |
20040 dictitem_T **dip, /* non-NULL when typval's dict item is needed */ | 6720 dictitem_T **dip, /* non-NULL when typval's dict item is needed */ |
20322 } | 7002 } |
20323 | 7003 |
20324 /* | 7004 /* |
20325 * Set the value of a variable to NULL without freeing items. | 7005 * Set the value of a variable to NULL without freeing items. |
20326 */ | 7006 */ |
20327 static void | 7007 void |
20328 init_tv(typval_T *varp) | 7008 init_tv(typval_T *varp) |
20329 { | 7009 { |
20330 if (varp != NULL) | 7010 if (varp != NULL) |
20331 vim_memset(varp, 0, sizeof(typval_T)); | 7011 vim_memset(varp, 0, sizeof(typval_T)); |
20332 } | 7012 } |
20399 *denote = TRUE; | 7079 *denote = TRUE; |
20400 return n; | 7080 return n; |
20401 } | 7081 } |
20402 | 7082 |
20403 #ifdef FEAT_FLOAT | 7083 #ifdef FEAT_FLOAT |
20404 static float_T | 7084 float_T |
20405 get_tv_float(typval_T *varp) | 7085 get_tv_float(typval_T *varp) |
20406 { | 7086 { |
20407 switch (varp->v_type) | 7087 switch (varp->v_type) |
20408 { | 7088 { |
20409 case VAR_NUMBER: | 7089 case VAR_NUMBER: |
20443 return 0; | 7123 return 0; |
20444 } | 7124 } |
20445 #endif | 7125 #endif |
20446 | 7126 |
20447 /* | 7127 /* |
20448 * Get the lnum from the first argument. | |
20449 * Also accepts ".", "$", etc., but that only works for the current buffer. | |
20450 * Returns -1 on error. | |
20451 */ | |
20452 static linenr_T | |
20453 get_tv_lnum(typval_T *argvars) | |
20454 { | |
20455 typval_T rettv; | |
20456 linenr_T lnum; | |
20457 | |
20458 lnum = (linenr_T)get_tv_number_chk(&argvars[0], NULL); | |
20459 if (lnum == 0) /* no valid number, try using line() */ | |
20460 { | |
20461 rettv.v_type = VAR_NUMBER; | |
20462 f_line(argvars, &rettv); | |
20463 lnum = (linenr_T)rettv.vval.v_number; | |
20464 clear_tv(&rettv); | |
20465 } | |
20466 return lnum; | |
20467 } | |
20468 | |
20469 /* | |
20470 * Get the lnum from the first argument. | |
20471 * Also accepts "$", then "buf" is used. | |
20472 * Returns 0 on error. | |
20473 */ | |
20474 static linenr_T | |
20475 get_tv_lnum_buf(typval_T *argvars, buf_T *buf) | |
20476 { | |
20477 if (argvars[0].v_type == VAR_STRING | |
20478 && argvars[0].vval.v_string != NULL | |
20479 && argvars[0].vval.v_string[0] == '$' | |
20480 && buf != NULL) | |
20481 return buf->b_ml.ml_line_count; | |
20482 return (linenr_T)get_tv_number_chk(&argvars[0], NULL); | |
20483 } | |
20484 | |
20485 /* | |
20486 * Get the string value of a variable. | 7128 * Get the string value of a variable. |
20487 * If it is a Number variable, the number is converted into a string. | 7129 * If it is a Number variable, the number is converted into a string. |
20488 * get_tv_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE! | 7130 * get_tv_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE! |
20489 * get_tv_string_buf() uses a given buffer. | 7131 * get_tv_string_buf() uses a given buffer. |
20490 * If the String variable has never been set, return an empty string. | 7132 * If the String variable has never been set, return an empty string. |
20622 | 7264 |
20623 /* | 7265 /* |
20624 * Find variable "varname" in hashtab "ht" with name "htname". | 7266 * Find variable "varname" in hashtab "ht" with name "htname". |
20625 * Returns NULL if not found. | 7267 * Returns NULL if not found. |
20626 */ | 7268 */ |
20627 static dictitem_T * | 7269 dictitem_T * |
20628 find_var_in_ht( | 7270 find_var_in_ht( |
20629 hashtab_T *ht, | 7271 hashtab_T *ht, |
20630 int htname, | 7272 int htname, |
20631 char_u *varname, | 7273 char_u *varname, |
20632 int no_autoload) | 7274 int no_autoload) |
20934 /* | 7576 /* |
20935 * Set variable "name" to value in "tv". | 7577 * Set variable "name" to value in "tv". |
20936 * If the variable already exists, the value is updated. | 7578 * If the variable already exists, the value is updated. |
20937 * Otherwise the variable is created. | 7579 * Otherwise the variable is created. |
20938 */ | 7580 */ |
20939 static void | 7581 void |
20940 set_var( | 7582 set_var( |
20941 char_u *name, | 7583 char_u *name, |
20942 typval_T *tv, | 7584 typval_T *tv, |
20943 int copy) /* make copy of value in "tv" */ | 7585 int copy) /* make copy of value in "tv" */ |
20944 { | 7586 { |
21062 | 7704 |
21063 /* | 7705 /* |
21064 * Return TRUE if di_flags "flags" indicates variable "name" is fixed. | 7706 * Return TRUE if di_flags "flags" indicates variable "name" is fixed. |
21065 * Also give an error message. | 7707 * Also give an error message. |
21066 */ | 7708 */ |
21067 static int | 7709 int |
21068 var_check_fixed(int flags, char_u *name, int use_gettext) | 7710 var_check_fixed(int flags, char_u *name, int use_gettext) |
21069 { | 7711 { |
21070 if (flags & DI_FLAGS_FIX) | 7712 if (flags & DI_FLAGS_FIX) |
21071 { | 7713 { |
21072 EMSG2(_("E795: Cannot delete variable %s"), | 7714 EMSG2(_("E795: Cannot delete variable %s"), |
21305 EMSG2(_(e_intern2), "item_copy(UNKNOWN)"); | 7947 EMSG2(_(e_intern2), "item_copy(UNKNOWN)"); |
21306 ret = FAIL; | 7948 ret = FAIL; |
21307 } | 7949 } |
21308 --recurse; | 7950 --recurse; |
21309 return ret; | 7951 return ret; |
7952 } | |
7953 | |
7954 /* | |
7955 * This function is used by f_input() and f_inputdialog() functions. The third | |
7956 * argument to f_input() specifies the type of completion to use at the | |
7957 * prompt. The third argument to f_inputdialog() specifies the value to return | |
7958 * when the user cancels the prompt. | |
7959 */ | |
7960 void | |
7961 get_user_input( | |
7962 typval_T *argvars, | |
7963 typval_T *rettv, | |
7964 int inputdialog, | |
7965 int secret) | |
7966 { | |
7967 char_u *prompt = get_tv_string_chk(&argvars[0]); | |
7968 char_u *p = NULL; | |
7969 int c; | |
7970 char_u buf[NUMBUFLEN]; | |
7971 int cmd_silent_save = cmd_silent; | |
7972 char_u *defstr = (char_u *)""; | |
7973 int xp_type = EXPAND_NOTHING; | |
7974 char_u *xp_arg = NULL; | |
7975 | |
7976 rettv->v_type = VAR_STRING; | |
7977 rettv->vval.v_string = NULL; | |
7978 | |
7979 #ifdef NO_CONSOLE_INPUT | |
7980 /* While starting up, there is no place to enter text. */ | |
7981 if (no_console_input()) | |
7982 return; | |
7983 #endif | |
7984 | |
7985 cmd_silent = FALSE; /* Want to see the prompt. */ | |
7986 if (prompt != NULL) | |
7987 { | |
7988 /* Only the part of the message after the last NL is considered as | |
7989 * prompt for the command line */ | |
7990 p = vim_strrchr(prompt, '\n'); | |
7991 if (p == NULL) | |
7992 p = prompt; | |
7993 else | |
7994 { | |
7995 ++p; | |
7996 c = *p; | |
7997 *p = NUL; | |
7998 msg_start(); | |
7999 msg_clr_eos(); | |
8000 msg_puts_attr(prompt, echo_attr); | |
8001 msg_didout = FALSE; | |
8002 msg_starthere(); | |
8003 *p = c; | |
8004 } | |
8005 cmdline_row = msg_row; | |
8006 | |
8007 if (argvars[1].v_type != VAR_UNKNOWN) | |
8008 { | |
8009 defstr = get_tv_string_buf_chk(&argvars[1], buf); | |
8010 if (defstr != NULL) | |
8011 stuffReadbuffSpec(defstr); | |
8012 | |
8013 if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN) | |
8014 { | |
8015 char_u *xp_name; | |
8016 int xp_namelen; | |
8017 long argt; | |
8018 | |
8019 /* input() with a third argument: completion */ | |
8020 rettv->vval.v_string = NULL; | |
8021 | |
8022 xp_name = get_tv_string_buf_chk(&argvars[2], buf); | |
8023 if (xp_name == NULL) | |
8024 return; | |
8025 | |
8026 xp_namelen = (int)STRLEN(xp_name); | |
8027 | |
8028 if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt, | |
8029 &xp_arg) == FAIL) | |
8030 return; | |
8031 } | |
8032 } | |
8033 | |
8034 if (defstr != NULL) | |
8035 { | |
8036 int save_ex_normal_busy = ex_normal_busy; | |
8037 ex_normal_busy = 0; | |
8038 rettv->vval.v_string = | |
8039 getcmdline_prompt(secret ? NUL : '@', p, echo_attr, | |
8040 xp_type, xp_arg); | |
8041 ex_normal_busy = save_ex_normal_busy; | |
8042 } | |
8043 if (inputdialog && rettv->vval.v_string == NULL | |
8044 && argvars[1].v_type != VAR_UNKNOWN | |
8045 && argvars[2].v_type != VAR_UNKNOWN) | |
8046 rettv->vval.v_string = vim_strsave(get_tv_string_buf( | |
8047 &argvars[2], buf)); | |
8048 | |
8049 vim_free(xp_arg); | |
8050 | |
8051 /* since the user typed this, no need to wait for return */ | |
8052 need_wait_return = FALSE; | |
8053 msg_didout = FALSE; | |
8054 } | |
8055 cmd_silent = cmd_silent_save; | |
21310 } | 8056 } |
21311 | 8057 |
21312 /* | 8058 /* |
21313 * ":echo expr1 ..." print each argument separated with a space, add a | 8059 * ":echo expr1 ..." print each argument separated with a space, add a |
21314 * newline at the end. | 8060 * newline at the end. |
21511 | 8257 |
21512 if (eap->skip) | 8258 if (eap->skip) |
21513 --emsg_skip; | 8259 --emsg_skip; |
21514 | 8260 |
21515 eap->nextcmd = check_nextcmd(arg); | 8261 eap->nextcmd = check_nextcmd(arg); |
8262 } | |
8263 | |
8264 /* | |
8265 * Find window specified by "vp" in tabpage "tp". | |
8266 */ | |
8267 win_T * | |
8268 find_win_by_nr( | |
8269 typval_T *vp, | |
8270 tabpage_T *tp UNUSED) /* NULL for current tab page */ | |
8271 { | |
8272 #ifdef FEAT_WINDOWS | |
8273 win_T *wp; | |
8274 #endif | |
8275 int nr; | |
8276 | |
8277 nr = (int)get_tv_number_chk(vp, NULL); | |
8278 | |
8279 #ifdef FEAT_WINDOWS | |
8280 if (nr < 0) | |
8281 return NULL; | |
8282 if (nr == 0) | |
8283 return curwin; | |
8284 | |
8285 for (wp = (tp == NULL || tp == curtab) ? firstwin : tp->tp_firstwin; | |
8286 wp != NULL; wp = wp->w_next) | |
8287 if (nr >= LOWEST_WIN_ID) | |
8288 { | |
8289 if (wp->w_id == nr) | |
8290 return wp; | |
8291 } | |
8292 else if (--nr <= 0) | |
8293 break; | |
8294 if (nr >= LOWEST_WIN_ID) | |
8295 return NULL; | |
8296 return wp; | |
8297 #else | |
8298 if (nr == 0 || nr == 1 || nr == curwin->w_id) | |
8299 return curwin; | |
8300 return NULL; | |
8301 #endif | |
8302 } | |
8303 | |
8304 /* | |
8305 * Find window specified by "wvp" in tabpage "tvp". | |
8306 */ | |
8307 win_T * | |
8308 find_tabwin( | |
8309 typval_T *wvp, /* VAR_UNKNOWN for current window */ | |
8310 typval_T *tvp) /* VAR_UNKNOWN for current tab page */ | |
8311 { | |
8312 win_T *wp = NULL; | |
8313 tabpage_T *tp = NULL; | |
8314 long n; | |
8315 | |
8316 if (wvp->v_type != VAR_UNKNOWN) | |
8317 { | |
8318 if (tvp->v_type != VAR_UNKNOWN) | |
8319 { | |
8320 n = (long)get_tv_number(tvp); | |
8321 if (n >= 0) | |
8322 tp = find_tabpage(n); | |
8323 } | |
8324 else | |
8325 tp = curtab; | |
8326 | |
8327 if (tp != NULL) | |
8328 wp = find_win_by_nr(wvp, tp); | |
8329 } | |
8330 else | |
8331 wp = curwin; | |
8332 | |
8333 return wp; | |
8334 } | |
8335 | |
8336 /* | |
8337 * getwinvar() and gettabwinvar() | |
8338 */ | |
8339 void | |
8340 getwinvar( | |
8341 typval_T *argvars, | |
8342 typval_T *rettv, | |
8343 int off) /* 1 for gettabwinvar() */ | |
8344 { | |
8345 win_T *win; | |
8346 char_u *varname; | |
8347 dictitem_T *v; | |
8348 tabpage_T *tp = NULL; | |
8349 int done = FALSE; | |
8350 #ifdef FEAT_WINDOWS | |
8351 win_T *oldcurwin; | |
8352 tabpage_T *oldtabpage; | |
8353 int need_switch_win; | |
8354 #endif | |
8355 | |
8356 #ifdef FEAT_WINDOWS | |
8357 if (off == 1) | |
8358 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
8359 else | |
8360 tp = curtab; | |
8361 #endif | |
8362 win = find_win_by_nr(&argvars[off], tp); | |
8363 varname = get_tv_string_chk(&argvars[off + 1]); | |
8364 ++emsg_off; | |
8365 | |
8366 rettv->v_type = VAR_STRING; | |
8367 rettv->vval.v_string = NULL; | |
8368 | |
8369 if (win != NULL && varname != NULL) | |
8370 { | |
8371 #ifdef FEAT_WINDOWS | |
8372 /* Set curwin to be our win, temporarily. Also set the tabpage, | |
8373 * otherwise the window is not valid. Only do this when needed, | |
8374 * autocommands get blocked. */ | |
8375 need_switch_win = !(tp == curtab && win == curwin); | |
8376 if (!need_switch_win | |
8377 || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) | |
8378 #endif | |
8379 { | |
8380 if (*varname == '&') /* window-local-option */ | |
8381 { | |
8382 if (get_option_tv(&varname, rettv, 1) == OK) | |
8383 done = TRUE; | |
8384 } | |
8385 else | |
8386 { | |
8387 /* Look up the variable. */ | |
8388 /* Let getwinvar({nr}, "") return the "w:" dictionary. */ | |
8389 v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', | |
8390 varname, FALSE); | |
8391 if (v != NULL) | |
8392 { | |
8393 copy_tv(&v->di_tv, rettv); | |
8394 done = TRUE; | |
8395 } | |
8396 } | |
8397 } | |
8398 | |
8399 #ifdef FEAT_WINDOWS | |
8400 if (need_switch_win) | |
8401 /* restore previous notion of curwin */ | |
8402 restore_win(oldcurwin, oldtabpage, TRUE); | |
8403 #endif | |
8404 } | |
8405 | |
8406 if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) | |
8407 /* use the default return value */ | |
8408 copy_tv(&argvars[off + 2], rettv); | |
8409 | |
8410 --emsg_off; | |
8411 } | |
8412 | |
8413 /* | |
8414 * "setwinvar()" and "settabwinvar()" functions | |
8415 */ | |
8416 void | |
8417 setwinvar(typval_T *argvars, typval_T *rettv UNUSED, int off) | |
8418 { | |
8419 win_T *win; | |
8420 #ifdef FEAT_WINDOWS | |
8421 win_T *save_curwin; | |
8422 tabpage_T *save_curtab; | |
8423 int need_switch_win; | |
8424 #endif | |
8425 char_u *varname, *winvarname; | |
8426 typval_T *varp; | |
8427 char_u nbuf[NUMBUFLEN]; | |
8428 tabpage_T *tp = NULL; | |
8429 | |
8430 if (check_restricted() || check_secure()) | |
8431 return; | |
8432 | |
8433 #ifdef FEAT_WINDOWS | |
8434 if (off == 1) | |
8435 tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); | |
8436 else | |
8437 tp = curtab; | |
8438 #endif | |
8439 win = find_win_by_nr(&argvars[off], tp); | |
8440 varname = get_tv_string_chk(&argvars[off + 1]); | |
8441 varp = &argvars[off + 2]; | |
8442 | |
8443 if (win != NULL && varname != NULL && varp != NULL) | |
8444 { | |
8445 #ifdef FEAT_WINDOWS | |
8446 need_switch_win = !(tp == curtab && win == curwin); | |
8447 if (!need_switch_win | |
8448 || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) | |
8449 #endif | |
8450 { | |
8451 if (*varname == '&') | |
8452 { | |
8453 long numval; | |
8454 char_u *strval; | |
8455 int error = FALSE; | |
8456 | |
8457 ++varname; | |
8458 numval = (long)get_tv_number_chk(varp, &error); | |
8459 strval = get_tv_string_buf_chk(varp, nbuf); | |
8460 if (!error && strval != NULL) | |
8461 set_option_value(varname, numval, strval, OPT_LOCAL); | |
8462 } | |
8463 else | |
8464 { | |
8465 winvarname = alloc((unsigned)STRLEN(varname) + 3); | |
8466 if (winvarname != NULL) | |
8467 { | |
8468 STRCPY(winvarname, "w:"); | |
8469 STRCPY(winvarname + 2, varname); | |
8470 set_var(winvarname, varp, TRUE); | |
8471 vim_free(winvarname); | |
8472 } | |
8473 } | |
8474 } | |
8475 #ifdef FEAT_WINDOWS | |
8476 if (need_switch_win) | |
8477 restore_win(save_curwin, save_curtab, TRUE); | |
8478 #endif | |
8479 } | |
21516 } | 8480 } |
21517 | 8481 |
21518 /* | 8482 /* |
21519 * Skip over the name of an option: "&option", "&g:option" or "&l:option". | 8483 * Skip over the name of an option: "&option", "&g:option" or "&l:option". |
21520 * "arg" points to the "&" or '+' when called, to "option" when returning. | 8484 * "arg" points to the "&" or '+' when called, to "option" when returning. |
21928 reset_v_option_vars(void) | 8892 reset_v_option_vars(void) |
21929 { | 8893 { |
21930 set_vim_var_string(VV_OPTION_NEW, NULL, -1); | 8894 set_vim_var_string(VV_OPTION_NEW, NULL, -1); |
21931 set_vim_var_string(VV_OPTION_OLD, NULL, -1); | 8895 set_vim_var_string(VV_OPTION_OLD, NULL, -1); |
21932 set_vim_var_string(VV_OPTION_TYPE, NULL, -1); | 8896 set_vim_var_string(VV_OPTION_TYPE, NULL, -1); |
8897 } | |
8898 | |
8899 /* | |
8900 * Prepare "gap" for an assert error and add the sourcing position. | |
8901 */ | |
8902 void | |
8903 prepare_assert_error(garray_T *gap) | |
8904 { | |
8905 char buf[NUMBUFLEN]; | |
8906 | |
8907 ga_init2(gap, 1, 100); | |
8908 if (sourcing_name != NULL) | |
8909 { | |
8910 ga_concat(gap, sourcing_name); | |
8911 if (sourcing_lnum > 0) | |
8912 ga_concat(gap, (char_u *)" "); | |
8913 } | |
8914 if (sourcing_lnum > 0) | |
8915 { | |
8916 sprintf(buf, "line %ld", (long)sourcing_lnum); | |
8917 ga_concat(gap, (char_u *)buf); | |
8918 } | |
8919 if (sourcing_name != NULL || sourcing_lnum > 0) | |
8920 ga_concat(gap, (char_u *)": "); | |
8921 } | |
8922 | |
8923 /* | |
8924 * Add an assert error to v:errors. | |
8925 */ | |
8926 void | |
8927 assert_error(garray_T *gap) | |
8928 { | |
8929 struct vimvar *vp = &vimvars[VV_ERRORS]; | |
8930 | |
8931 if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL) | |
8932 /* Make sure v:errors is a list. */ | |
8933 set_vim_var_list(VV_ERRORS, list_alloc()); | |
8934 list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len); | |
8935 } | |
8936 | |
8937 void | |
8938 assert_equal_common(typval_T *argvars, assert_type_T atype) | |
8939 { | |
8940 garray_T ga; | |
8941 | |
8942 if (tv_equal(&argvars[0], &argvars[1], FALSE, FALSE) | |
8943 != (atype == ASSERT_EQUAL)) | |
8944 { | |
8945 prepare_assert_error(&ga); | |
8946 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], | |
8947 atype); | |
8948 assert_error(&ga); | |
8949 ga_clear(&ga); | |
8950 } | |
8951 } | |
8952 | |
8953 void | |
8954 assert_match_common(typval_T *argvars, assert_type_T atype) | |
8955 { | |
8956 garray_T ga; | |
8957 char_u buf1[NUMBUFLEN]; | |
8958 char_u buf2[NUMBUFLEN]; | |
8959 char_u *pat = get_tv_string_buf_chk(&argvars[0], buf1); | |
8960 char_u *text = get_tv_string_buf_chk(&argvars[1], buf2); | |
8961 | |
8962 if (pat == NULL || text == NULL) | |
8963 EMSG(_(e_invarg)); | |
8964 else if (pattern_match(pat, text, FALSE) != (atype == ASSERT_MATCH)) | |
8965 { | |
8966 prepare_assert_error(&ga); | |
8967 fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], | |
8968 atype); | |
8969 assert_error(&ga); | |
8970 ga_clear(&ga); | |
8971 } | |
8972 } | |
8973 | |
8974 /* | |
8975 * Common for assert_true() and assert_false(). | |
8976 */ | |
8977 void | |
8978 assert_bool(typval_T *argvars, int isTrue) | |
8979 { | |
8980 int error = FALSE; | |
8981 garray_T ga; | |
8982 | |
8983 if (argvars[0].v_type == VAR_SPECIAL | |
8984 && argvars[0].vval.v_number == (isTrue ? VVAL_TRUE : VVAL_FALSE)) | |
8985 return; | |
8986 if (argvars[0].v_type != VAR_NUMBER | |
8987 || (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue | |
8988 || error) | |
8989 { | |
8990 prepare_assert_error(&ga); | |
8991 fill_assert_error(&ga, &argvars[1], | |
8992 (char_u *)(isTrue ? "True" : "False"), | |
8993 NULL, &argvars[0], ASSERT_OTHER); | |
8994 assert_error(&ga); | |
8995 ga_clear(&ga); | |
8996 } | |
8997 } | |
8998 | |
8999 void | |
9000 assert_exception(typval_T *argvars) | |
9001 { | |
9002 garray_T ga; | |
9003 char_u *error = get_tv_string_chk(&argvars[0]); | |
9004 | |
9005 if (vimvars[VV_EXCEPTION].vv_str == NULL) | |
9006 { | |
9007 prepare_assert_error(&ga); | |
9008 ga_concat(&ga, (char_u *)"v:exception is not set"); | |
9009 assert_error(&ga); | |
9010 ga_clear(&ga); | |
9011 } | |
9012 else if (error != NULL | |
9013 && strstr((char *)vimvars[VV_EXCEPTION].vv_str, (char *)error) == NULL) | |
9014 { | |
9015 prepare_assert_error(&ga); | |
9016 fill_assert_error(&ga, &argvars[1], NULL, &argvars[0], | |
9017 &vimvars[VV_EXCEPTION].vv_tv, ASSERT_OTHER); | |
9018 assert_error(&ga); | |
9019 ga_clear(&ga); | |
9020 } | |
9021 } | |
9022 | |
9023 void | |
9024 assert_fails(typval_T *argvars) | |
9025 { | |
9026 char_u *cmd = get_tv_string_chk(&argvars[0]); | |
9027 garray_T ga; | |
9028 | |
9029 called_emsg = FALSE; | |
9030 suppress_errthrow = TRUE; | |
9031 emsg_silent = TRUE; | |
9032 do_cmdline_cmd(cmd); | |
9033 if (!called_emsg) | |
9034 { | |
9035 prepare_assert_error(&ga); | |
9036 ga_concat(&ga, (char_u *)"command did not fail: "); | |
9037 ga_concat(&ga, cmd); | |
9038 assert_error(&ga); | |
9039 ga_clear(&ga); | |
9040 } | |
9041 else if (argvars[1].v_type != VAR_UNKNOWN) | |
9042 { | |
9043 char_u buf[NUMBUFLEN]; | |
9044 char *error = (char *)get_tv_string_buf_chk(&argvars[1], buf); | |
9045 | |
9046 if (error == NULL | |
9047 || strstr((char *)vimvars[VV_ERRMSG].vv_str, error) == NULL) | |
9048 { | |
9049 prepare_assert_error(&ga); | |
9050 fill_assert_error(&ga, &argvars[2], NULL, &argvars[1], | |
9051 &vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER); | |
9052 assert_error(&ga); | |
9053 ga_clear(&ga); | |
9054 } | |
9055 } | |
9056 | |
9057 called_emsg = FALSE; | |
9058 suppress_errthrow = FALSE; | |
9059 emsg_silent = FALSE; | |
9060 emsg_on_display = FALSE; | |
9061 set_vim_var_string(VV_ERRMSG, NULL, 0); | |
9062 } | |
9063 | |
9064 /* | |
9065 * Append "str" to "gap", escaping unprintable characters. | |
9066 * Changes NL to \n, CR to \r, etc. | |
9067 */ | |
9068 static void | |
9069 ga_concat_esc(garray_T *gap, char_u *str) | |
9070 { | |
9071 char_u *p; | |
9072 char_u buf[NUMBUFLEN]; | |
9073 | |
9074 if (str == NULL) | |
9075 { | |
9076 ga_concat(gap, (char_u *)"NULL"); | |
9077 return; | |
9078 } | |
9079 | |
9080 for (p = str; *p != NUL; ++p) | |
9081 switch (*p) | |
9082 { | |
9083 case BS: ga_concat(gap, (char_u *)"\\b"); break; | |
9084 case ESC: ga_concat(gap, (char_u *)"\\e"); break; | |
9085 case FF: ga_concat(gap, (char_u *)"\\f"); break; | |
9086 case NL: ga_concat(gap, (char_u *)"\\n"); break; | |
9087 case TAB: ga_concat(gap, (char_u *)"\\t"); break; | |
9088 case CAR: ga_concat(gap, (char_u *)"\\r"); break; | |
9089 case '\\': ga_concat(gap, (char_u *)"\\\\"); break; | |
9090 default: | |
9091 if (*p < ' ') | |
9092 { | |
9093 vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p); | |
9094 ga_concat(gap, buf); | |
9095 } | |
9096 else | |
9097 ga_append(gap, *p); | |
9098 break; | |
9099 } | |
9100 } | |
9101 | |
9102 /* | |
9103 * Fill "gap" with information about an assert error. | |
9104 */ | |
9105 void | |
9106 fill_assert_error( | |
9107 garray_T *gap, | |
9108 typval_T *opt_msg_tv, | |
9109 char_u *exp_str, | |
9110 typval_T *exp_tv, | |
9111 typval_T *got_tv, | |
9112 assert_type_T atype) | |
9113 { | |
9114 char_u numbuf[NUMBUFLEN]; | |
9115 char_u *tofree; | |
9116 | |
9117 if (opt_msg_tv->v_type != VAR_UNKNOWN) | |
9118 { | |
9119 ga_concat(gap, tv2string(opt_msg_tv, &tofree, numbuf, 0)); | |
9120 vim_free(tofree); | |
9121 } | |
9122 else | |
9123 { | |
9124 if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) | |
9125 ga_concat(gap, (char_u *)"Pattern "); | |
9126 else | |
9127 ga_concat(gap, (char_u *)"Expected "); | |
9128 if (exp_str == NULL) | |
9129 { | |
9130 ga_concat_esc(gap, tv2string(exp_tv, &tofree, numbuf, 0)); | |
9131 vim_free(tofree); | |
9132 } | |
9133 else | |
9134 ga_concat_esc(gap, exp_str); | |
9135 if (atype == ASSERT_MATCH) | |
9136 ga_concat(gap, (char_u *)" does not match "); | |
9137 else if (atype == ASSERT_NOTMATCH) | |
9138 ga_concat(gap, (char_u *)" does match "); | |
9139 else if (atype == ASSERT_NOTEQUAL) | |
9140 ga_concat(gap, (char_u *)" differs from "); | |
9141 else | |
9142 ga_concat(gap, (char_u *)" but got "); | |
9143 ga_concat_esc(gap, tv2string(got_tv, &tofree, numbuf, 0)); | |
9144 vim_free(tofree); | |
9145 } | |
21933 } | 9146 } |
21934 | 9147 |
21935 | 9148 |
21936 #endif /* FEAT_EVAL */ | 9149 #endif /* FEAT_EVAL */ |
21937 | 9150 |
22676 free_string_option(save_cpo); | 9889 free_string_option(save_cpo); |
22677 | 9890 |
22678 return ret; | 9891 return ret; |
22679 } | 9892 } |
22680 | 9893 |
9894 static int | |
9895 filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) | |
9896 { | |
9897 typval_T rettv; | |
9898 typval_T argv[3]; | |
9899 char_u buf[NUMBUFLEN]; | |
9900 char_u *s; | |
9901 int retval = FAIL; | |
9902 int dummy; | |
9903 | |
9904 copy_tv(tv, &vimvars[VV_VAL].vv_tv); | |
9905 argv[0] = vimvars[VV_KEY].vv_tv; | |
9906 argv[1] = vimvars[VV_VAL].vv_tv; | |
9907 if (expr->v_type == VAR_FUNC) | |
9908 { | |
9909 s = expr->vval.v_string; | |
9910 if (call_func(s, (int)STRLEN(s), | |
9911 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, NULL, NULL) == FAIL) | |
9912 goto theend; | |
9913 } | |
9914 else if (expr->v_type == VAR_PARTIAL) | |
9915 { | |
9916 partial_T *partial = expr->vval.v_partial; | |
9917 | |
9918 s = partial->pt_name; | |
9919 if (call_func(s, (int)STRLEN(s), | |
9920 &rettv, 2, argv, 0L, 0L, &dummy, TRUE, partial, NULL) | |
9921 == FAIL) | |
9922 goto theend; | |
9923 } | |
9924 else | |
9925 { | |
9926 s = get_tv_string_buf_chk(expr, buf); | |
9927 if (s == NULL) | |
9928 goto theend; | |
9929 s = skipwhite(s); | |
9930 if (eval1(&s, &rettv, TRUE) == FAIL) | |
9931 goto theend; | |
9932 if (*s != NUL) /* check for trailing chars after expr */ | |
9933 { | |
9934 EMSG2(_(e_invexpr2), s); | |
9935 goto theend; | |
9936 } | |
9937 } | |
9938 if (map) | |
9939 { | |
9940 /* map(): replace the list item value */ | |
9941 clear_tv(tv); | |
9942 rettv.v_lock = 0; | |
9943 *tv = rettv; | |
9944 } | |
9945 else | |
9946 { | |
9947 int error = FALSE; | |
9948 | |
9949 /* filter(): when expr is zero remove the item */ | |
9950 *remp = (get_tv_number_chk(&rettv, &error) == 0); | |
9951 clear_tv(&rettv); | |
9952 /* On type error, nothing has been removed; return FAIL to stop the | |
9953 * loop. The error message was given by get_tv_number_chk(). */ | |
9954 if (error) | |
9955 goto theend; | |
9956 } | |
9957 retval = OK; | |
9958 theend: | |
9959 clear_tv(&vimvars[VV_VAL].vv_tv); | |
9960 return retval; | |
9961 } | |
9962 | |
9963 | |
9964 /* | |
9965 * Implementation of map() and filter(). | |
9966 */ | |
9967 void | |
9968 filter_map(typval_T *argvars, typval_T *rettv, int map) | |
9969 { | |
9970 typval_T *expr; | |
9971 listitem_T *li, *nli; | |
9972 list_T *l = NULL; | |
9973 dictitem_T *di; | |
9974 hashtab_T *ht; | |
9975 hashitem_T *hi; | |
9976 dict_T *d = NULL; | |
9977 typval_T save_val; | |
9978 typval_T save_key; | |
9979 int rem; | |
9980 int todo; | |
9981 char_u *ermsg = (char_u *)(map ? "map()" : "filter()"); | |
9982 char_u *arg_errmsg = (char_u *)(map ? N_("map() argument") | |
9983 : N_("filter() argument")); | |
9984 int save_did_emsg; | |
9985 int idx = 0; | |
9986 | |
9987 if (argvars[0].v_type == VAR_LIST) | |
9988 { | |
9989 if ((l = argvars[0].vval.v_list) == NULL | |
9990 || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TRUE))) | |
9991 return; | |
9992 } | |
9993 else if (argvars[0].v_type == VAR_DICT) | |
9994 { | |
9995 if ((d = argvars[0].vval.v_dict) == NULL | |
9996 || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TRUE))) | |
9997 return; | |
9998 } | |
9999 else | |
10000 { | |
10001 EMSG2(_(e_listdictarg), ermsg); | |
10002 return; | |
10003 } | |
10004 | |
10005 expr = &argvars[1]; | |
10006 /* On type errors, the preceding call has already displayed an error | |
10007 * message. Avoid a misleading error message for an empty string that | |
10008 * was not passed as argument. */ | |
10009 if (expr->v_type != VAR_UNKNOWN) | |
10010 { | |
10011 prepare_vimvar(VV_VAL, &save_val); | |
10012 | |
10013 /* We reset "did_emsg" to be able to detect whether an error | |
10014 * occurred during evaluation of the expression. */ | |
10015 save_did_emsg = did_emsg; | |
10016 did_emsg = FALSE; | |
10017 | |
10018 prepare_vimvar(VV_KEY, &save_key); | |
10019 if (argvars[0].v_type == VAR_DICT) | |
10020 { | |
10021 vimvars[VV_KEY].vv_type = VAR_STRING; | |
10022 | |
10023 ht = &d->dv_hashtab; | |
10024 hash_lock(ht); | |
10025 todo = (int)ht->ht_used; | |
10026 for (hi = ht->ht_array; todo > 0; ++hi) | |
10027 { | |
10028 if (!HASHITEM_EMPTY(hi)) | |
10029 { | |
10030 int r; | |
10031 | |
10032 --todo; | |
10033 di = HI2DI(hi); | |
10034 if (map && | |
10035 (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE) | |
10036 || var_check_ro(di->di_flags, arg_errmsg, TRUE))) | |
10037 break; | |
10038 vimvars[VV_KEY].vv_str = vim_strsave(di->di_key); | |
10039 r = filter_map_one(&di->di_tv, expr, map, &rem); | |
10040 clear_tv(&vimvars[VV_KEY].vv_tv); | |
10041 if (r == FAIL || did_emsg) | |
10042 break; | |
10043 if (!map && rem) | |
10044 { | |
10045 if (var_check_fixed(di->di_flags, arg_errmsg, TRUE) | |
10046 || var_check_ro(di->di_flags, arg_errmsg, TRUE)) | |
10047 break; | |
10048 dictitem_remove(d, di); | |
10049 } | |
10050 } | |
10051 } | |
10052 hash_unlock(ht); | |
10053 } | |
10054 else | |
10055 { | |
10056 vimvars[VV_KEY].vv_type = VAR_NUMBER; | |
10057 | |
10058 for (li = l->lv_first; li != NULL; li = nli) | |
10059 { | |
10060 if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) | |
10061 break; | |
10062 nli = li->li_next; | |
10063 vimvars[VV_KEY].vv_nr = idx; | |
10064 if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL | |
10065 || did_emsg) | |
10066 break; | |
10067 if (!map && rem) | |
10068 listitem_remove(l, li); | |
10069 ++idx; | |
10070 } | |
10071 } | |
10072 | |
10073 restore_vimvar(VV_KEY, &save_key); | |
10074 restore_vimvar(VV_VAL, &save_val); | |
10075 | |
10076 did_emsg |= save_did_emsg; | |
10077 } | |
10078 | |
10079 copy_tv(&argvars[0], rettv); | |
10080 } | |
10081 | |
22681 #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */ | 10082 #endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */ |