blob: b5b4b792a32a0297f8f3533c5da1f8e4cdf0cad7 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * eval.c: Expression evaluation.
12 */
13#if defined(MSDOS) || defined(MSWIN)
14# include <io.h> /* for mch_open(), must be before vim.h */
15#endif
16
17#include "vim.h"
18
19#ifdef AMIGA
20# include <time.h> /* for strftime() */
21#endif
22
23#ifdef MACOS
24# include <time.h> /* for time_t */
25#endif
26
27#ifdef HAVE_FCNTL_H
28# include <fcntl.h>
29#endif
30
31#if defined(FEAT_EVAL) || defined(PROTO)
32
33#if SIZEOF_INT <= 3 /* use long if int is smaller than 32 bits */
34typedef long varnumber_T;
35#else
36typedef int varnumber_T;
37#endif
38
39/*
40 * Structure to hold an internal variable.
41 */
42typedef struct
43{
44 char_u *var_name; /* name of variable */
45 char var_type; /* VAR_NUMBER or VAR_STRING */
46 union
47 {
48 varnumber_T var_number; /* number value */
49 char_u *var_string; /* string value (Careful: can be NULL!) */
50 } var_val;
51} var;
52
53#define VAR_UNKNOWN 0
54#define VAR_NUMBER 1
55#define VAR_STRING 2
56
57typedef var * VAR;
58
59/*
60 * All user-defined global variables are stored in "variables".
61 */
62garray_T variables = {0, 0, sizeof(var), 4, NULL};
63
64/*
65 * Array to hold an array with variables local to each sourced script.
66 */
67static garray_T ga_scripts = {0, 0, sizeof(garray_T), 4, NULL};
68#define SCRIPT_VARS(id) (((garray_T *)ga_scripts.ga_data)[(id) - 1])
69
70
71#define VAR_ENTRY(idx) (((VAR)(variables.ga_data))[idx])
72#define VAR_GAP_ENTRY(idx, gap) (((VAR)(gap->ga_data))[idx])
73#define BVAR_ENTRY(idx) (((VAR)(curbuf->b_vars.ga_data))[idx])
74#define WVAR_ENTRY(idx) (((VAR)(curwin->w_vars.ga_data))[idx])
75
76static int echo_attr = 0; /* attributes used for ":echo" */
77
78/*
79 * Structure to hold info for a user function.
80 */
81typedef struct ufunc ufunc_T;
82
83struct ufunc
84{
85 ufunc_T *next; /* next function in list */
86 char_u *name; /* name of function; can start with <SNR>123_
87 (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) */
88 int varargs; /* variable nr of arguments */
89 int flags;
90 int calls; /* nr of active calls */
91 garray_T args; /* arguments */
92 garray_T lines; /* function lines */
93 scid_T script_ID; /* ID of script where function was defined,
94 used for s: variables */
95};
96
97/* function flags */
98#define FC_ABORT 1 /* abort function on error */
99#define FC_RANGE 2 /* function accepts range */
100
101/*
102 * All user-defined functions are found in the forward-linked function list.
103 * The first function is pointed at by firstfunc.
104 */
105ufunc_T *firstfunc = NULL;
106
107#define FUNCARG(fp, j) ((char_u **)(fp->args.ga_data))[j]
108#define FUNCLINE(fp, j) ((char_u **)(fp->lines.ga_data))[j]
109
110/* structure to hold info for a function that is currently being executed. */
111struct funccall
112{
113 ufunc_T *func; /* function being called */
114 int linenr; /* next line to be executed */
115 int returned; /* ":return" used */
116 int argcount; /* nr of arguments */
117 VAR argvars; /* arguments */
118 var a0_var; /* "a:0" variable */
119 var firstline; /* "a:firstline" variable */
120 var lastline; /* "a:lastline" variable */
121 garray_T l_vars; /* local function variables */
122 VAR retvar; /* return value variable */
123 linenr_T breakpoint; /* next line with breakpoint or zero */
124 int dbg_tick; /* debug_tick when breakpoint was set */
125 int level; /* top nesting level of executed function */
126};
127
128/*
129 * Return the name of the executed function.
130 */
131 char_u *
132func_name(cookie)
133 void *cookie;
134{
135 return ((struct funccall *)cookie)->func->name;
136}
137
138/*
139 * Return the address holding the next breakpoint line for a funccall cookie.
140 */
141 linenr_T *
142func_breakpoint(cookie)
143 void *cookie;
144{
145 return &((struct funccall *)cookie)->breakpoint;
146}
147
148/*
149 * Return the address holding the debug tick for a funccall cookie.
150 */
151 int *
152func_dbg_tick(cookie)
153 void *cookie;
154{
155 return &((struct funccall *)cookie)->dbg_tick;
156}
157
158/*
159 * Return the nesting level for a funccall cookie.
160 */
161 int
162func_level(cookie)
163 void *cookie;
164{
165 return ((struct funccall *)cookie)->level;
166}
167
168/* pointer to funccal for currently active function */
169struct funccall *current_funccal = NULL;
170
171/*
172 * Return TRUE when a function was ended by a ":return" command.
173 */
174 int
175current_func_returned()
176{
177 return current_funccal->returned;
178}
179
180
181/*
182 * Array to hold the value of v: variables.
183 */
184#include "version.h"
185
186/* values for flags: */
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000187#define VV_COMPAT 1 /* compatible, also used without "v:" */
188#define VV_RO 2 /* read-only */
189#define VV_RO_SBX 4 /* read-only in the sandbox*/
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190
191struct vimvar
192{
193 char *name; /* name of variable, without v: */
194 int len; /* length of name */
195 char_u *val; /* current value (can also be a number!) */
196 char type; /* VAR_NUMBER or VAR_STRING */
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000197 char flags; /* VV_COMPAT, VV_RO, VV_RO_SBX */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198} vimvars[VV_LEN] =
199{ /* The order here must match the VV_ defines in vim.h! */
200 {"count", sizeof("count") - 1, NULL, VAR_NUMBER, VV_COMPAT+VV_RO},
201 {"count1", sizeof("count1") - 1, NULL, VAR_NUMBER, VV_RO},
202 {"prevcount", sizeof("prevcount") - 1, NULL, VAR_NUMBER, VV_RO},
203 {"errmsg", sizeof("errmsg") - 1, NULL, VAR_STRING, VV_COMPAT},
204 {"warningmsg", sizeof("warningmsg") - 1, NULL, VAR_STRING, 0},
205 {"statusmsg", sizeof("statusmsg") - 1, NULL, VAR_STRING, 0},
206 {"shell_error", sizeof("shell_error") - 1, NULL, VAR_NUMBER,
207 VV_COMPAT+VV_RO},
208 {"this_session", sizeof("this_session") - 1, NULL, VAR_STRING, VV_COMPAT},
209 {"version", sizeof("version") - 1, (char_u *)VIM_VERSION_100,
210 VAR_NUMBER, VV_COMPAT+VV_RO},
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000211 {"lnum", sizeof("lnum") - 1, NULL, VAR_NUMBER, VV_RO_SBX},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000212 {"termresponse", sizeof("termresponse") - 1, NULL, VAR_STRING, VV_RO},
213 {"fname", sizeof("fname") - 1, NULL, VAR_STRING, VV_RO},
214 {"lang", sizeof("lang") - 1, NULL, VAR_STRING, VV_RO},
215 {"lc_time", sizeof("lc_time") - 1, NULL, VAR_STRING, VV_RO},
216 {"ctype", sizeof("ctype") - 1, NULL, VAR_STRING, VV_RO},
217 {"charconvert_from", sizeof("charconvert_from") - 1, NULL, VAR_STRING, VV_RO},
218 {"charconvert_to", sizeof("charconvert_to") - 1, NULL, VAR_STRING, VV_RO},
219 {"fname_in", sizeof("fname_in") - 1, NULL, VAR_STRING, VV_RO},
220 {"fname_out", sizeof("fname_out") - 1, NULL, VAR_STRING, VV_RO},
221 {"fname_new", sizeof("fname_new") - 1, NULL, VAR_STRING, VV_RO},
222 {"fname_diff", sizeof("fname_diff") - 1, NULL, VAR_STRING, VV_RO},
223 {"cmdarg", sizeof("cmdarg") - 1, NULL, VAR_STRING, VV_RO},
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000224 {"foldstart", sizeof("foldstart") - 1, NULL, VAR_NUMBER, VV_RO_SBX},
225 {"foldend", sizeof("foldend") - 1, NULL, VAR_NUMBER, VV_RO_SBX},
226 {"folddashes", sizeof("folddashes") - 1, NULL, VAR_STRING, VV_RO_SBX},
227 {"foldlevel", sizeof("foldlevel") - 1, NULL, VAR_NUMBER, VV_RO_SBX},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228 {"progname", sizeof("progname") - 1, NULL, VAR_STRING, VV_RO},
229 {"servername", sizeof("servername") - 1, NULL, VAR_STRING, VV_RO},
230 {"dying", sizeof("dying") - 1, NULL, VAR_NUMBER, VV_RO},
231 {"exception", sizeof("exception") - 1, NULL, VAR_STRING, VV_RO},
232 {"throwpoint", sizeof("throwpoint") - 1, NULL, VAR_STRING, VV_RO},
233 {"register", sizeof("register") - 1, NULL, VAR_STRING, VV_RO},
234 {"cmdbang", sizeof("cmdbang") - 1, NULL, VAR_NUMBER, VV_RO},
Bram Moolenaar843ee412004-06-30 16:16:41 +0000235 {"insertmode", sizeof("insertmode") - 1, NULL, VAR_STRING, VV_RO},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236};
237
238static int eval0 __ARGS((char_u *arg, VAR retvar, char_u **nextcmd, int evaluate));
239static int eval1 __ARGS((char_u **arg, VAR retvar, int evaluate));
240static int eval2 __ARGS((char_u **arg, VAR retvar, int evaluate));
241static int eval3 __ARGS((char_u **arg, VAR retvar, int evaluate));
242static int eval4 __ARGS((char_u **arg, VAR retvar, int evaluate));
243static int eval5 __ARGS((char_u **arg, VAR retvar, int evaluate));
244static int eval6 __ARGS((char_u **arg, VAR retvar, int evaluate));
245static int eval7 __ARGS((char_u **arg, VAR retvar, int evaluate));
246static int get_option_var __ARGS((char_u **arg, VAR retvar, int evaluate));
247static int get_string_var __ARGS((char_u **arg, VAR retvar, int evaluate));
248static int get_lit_string_var __ARGS((char_u **arg, VAR retvar, int evaluate));
249static int get_env_var __ARGS((char_u **arg, VAR retvar, int evaluate));
250static int find_internal_func __ARGS((char_u *name));
251static int get_func_var __ARGS((char_u *name, int len, VAR retvar, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate));
252static int call_func __ARGS((char_u *name, int len, VAR retvar, int argcount, VAR argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate));
253static void f_append __ARGS((VAR argvars, VAR retvar));
254static void f_argc __ARGS((VAR argvars, VAR retvar));
255static void f_argidx __ARGS((VAR argvars, VAR retvar));
256static void f_argv __ARGS((VAR argvars, VAR retvar));
257static void f_browse __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000258static void f_browsedir __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259static buf_T *find_buffer __ARGS((VAR avar));
260static void f_bufexists __ARGS((VAR argvars, VAR retvar));
261static void f_buflisted __ARGS((VAR argvars, VAR retvar));
262static void f_bufloaded __ARGS((VAR argvars, VAR retvar));
263static buf_T *get_buf_var __ARGS((VAR avar));
264static void f_bufname __ARGS((VAR argvars, VAR retvar));
265static void f_bufnr __ARGS((VAR argvars, VAR retvar));
266static void f_bufwinnr __ARGS((VAR argvars, VAR retvar));
267static void f_byte2line __ARGS((VAR argvars, VAR retvar));
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000268static void f_byteidx __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000269static void f_char2nr __ARGS((VAR argvars, VAR retvar));
270static void f_cindent __ARGS((VAR argvars, VAR retvar));
271static void f_col __ARGS((VAR argvars, VAR retvar));
272static void f_confirm __ARGS((VAR argvars, VAR retvar));
273static void f_cscope_connection __ARGS((VAR argvars, VAR retvar));
274static void f_cursor __ARGS((VAR argsvars, VAR retvar));
275static void f_delete __ARGS((VAR argvars, VAR retvar));
276static void f_did_filetype __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar47136d72004-10-12 20:02:24 +0000277static void f_diff_filler __ARGS((VAR argvars, VAR retvar));
278static void f_diff_hlID __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279static void f_escape __ARGS((VAR argvars, VAR retvar));
280static void f_eventhandler __ARGS((VAR argvars, VAR retvar));
281static void f_executable __ARGS((VAR argvars, VAR retvar));
282static void f_exists __ARGS((VAR argvars, VAR retvar));
283static void f_expand __ARGS((VAR argvars, VAR retvar));
284static void f_filereadable __ARGS((VAR argvars, VAR retvar));
285static void f_filewritable __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar89cb5e02004-07-19 20:55:54 +0000286static void f_finddir __ARGS((VAR argvars, VAR retvar));
287static void f_findfile __ARGS((VAR argvars, VAR retvar));
288static void f_findfilendir __ARGS((VAR argvars, VAR retvar, int dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289static void f_fnamemodify __ARGS((VAR argvars, VAR retvar));
290static void f_foldclosed __ARGS((VAR argvars, VAR retvar));
291static void f_foldclosedend __ARGS((VAR argvars, VAR retvar));
292static void foldclosed_both __ARGS((VAR argvars, VAR retvar, int end));
293static void f_foldlevel __ARGS((VAR argvars, VAR retvar));
294static void f_foldtext __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar7b0294c2004-10-11 10:16:09 +0000295static void f_foldtextresult __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296static void f_foreground __ARGS((VAR argvars, VAR retvar));
297static void f_getbufvar __ARGS((VAR argvars, VAR retvar));
298static void f_getchar __ARGS((VAR argvars, VAR retvar));
299static void f_getcharmod __ARGS((VAR argvars, VAR retvar));
300static void f_getcmdline __ARGS((VAR argvars, VAR retvar));
301static void f_getcmdpos __ARGS((VAR argvars, VAR retvar));
302static void f_getcwd __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar46c9c732004-12-12 11:37:09 +0000303static void f_getfontname __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000304static void f_getfperm __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305static void f_getfsize __ARGS((VAR argvars, VAR retvar));
306static void f_getftime __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000307static void f_getftype __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308static void f_getline __ARGS((VAR argvars, VAR retvar));
309static void f_getreg __ARGS((VAR argvars, VAR retvar));
310static void f_getregtype __ARGS((VAR argvars, VAR retvar));
311static void f_getwinposx __ARGS((VAR argvars, VAR retvar));
312static void f_getwinposy __ARGS((VAR argvars, VAR retvar));
313static void f_getwinvar __ARGS((VAR argvars, VAR retvar));
314static void f_glob __ARGS((VAR argvars, VAR retvar));
315static void f_globpath __ARGS((VAR argvars, VAR retvar));
316static void f_has __ARGS((VAR argvars, VAR retvar));
317static void f_hasmapto __ARGS((VAR argvars, VAR retvar));
318static void f_histadd __ARGS((VAR argvars, VAR retvar));
319static void f_histdel __ARGS((VAR argvars, VAR retvar));
320static void f_histget __ARGS((VAR argvars, VAR retvar));
321static void f_histnr __ARGS((VAR argvars, VAR retvar));
322static void f_hlexists __ARGS((VAR argvars, VAR retvar));
323static void f_hlID __ARGS((VAR argvars, VAR retvar));
324static void f_hostname __ARGS((VAR argvars, VAR retvar));
325static void f_iconv __ARGS((VAR argvars, VAR retvar));
326static void f_indent __ARGS((VAR argvars, VAR retvar));
327static void f_isdirectory __ARGS((VAR argvars, VAR retvar));
328static void f_input __ARGS((VAR argvars, VAR retvar));
329static void f_inputdialog __ARGS((VAR argvars, VAR retvar));
330static void f_inputrestore __ARGS((VAR argvars, VAR retvar));
331static void f_inputsave __ARGS((VAR argvars, VAR retvar));
332static void f_inputsecret __ARGS((VAR argvars, VAR retvar));
333static void f_last_buffer_nr __ARGS((VAR argvars, VAR retvar));
334static void f_libcall __ARGS((VAR argvars, VAR retvar));
335static void f_libcallnr __ARGS((VAR argvars, VAR retvar));
336static void libcall_common __ARGS((VAR argvars, VAR retvar, int type));
337static void f_line __ARGS((VAR argvars, VAR retvar));
338static void f_line2byte __ARGS((VAR argvars, VAR retvar));
339static void f_lispindent __ARGS((VAR argvars, VAR retvar));
340static void f_localtime __ARGS((VAR argvars, VAR retvar));
341static void f_maparg __ARGS((VAR argvars, VAR retvar));
342static void f_mapcheck __ARGS((VAR argvars, VAR retvar));
343static void get_maparg __ARGS((VAR argvars, VAR retvar, int exact));
344static void f_match __ARGS((VAR argvars, VAR retvar));
345static void f_matchend __ARGS((VAR argvars, VAR retvar));
346static void f_matchstr __ARGS((VAR argvars, VAR retvar));
347static void f_mode __ARGS((VAR argvars, VAR retvar));
348static void f_nextnonblank __ARGS((VAR argvars, VAR retvar));
349static void f_nr2char __ARGS((VAR argvars, VAR retvar));
350static void f_prevnonblank __ARGS((VAR argvars, VAR retvar));
351static void f_setbufvar __ARGS((VAR argvars, VAR retvar));
352static void f_setcmdpos __ARGS((VAR argvars, VAR retvar));
353static void f_setwinvar __ARGS((VAR argvars, VAR retvar));
354static void f_rename __ARGS((VAR argvars, VAR retvar));
355static void f_resolve __ARGS((VAR argvars, VAR retvar));
356static void f_search __ARGS((VAR argvars, VAR retvar));
357static void f_searchpair __ARGS((VAR argvars, VAR retvar));
358static int get_search_arg __ARGS((VAR varp, int *flagsp));
359static void f_remote_expr __ARGS((VAR argvars, VAR retvar));
360static void f_remote_foreground __ARGS((VAR argvars, VAR retvar));
361static void f_remote_peek __ARGS((VAR argvars, VAR retvar));
362static void f_remote_read __ARGS((VAR argvars, VAR retvar));
363static void f_remote_send __ARGS((VAR argvars, VAR retvar));
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000364static void f_repeat __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365static void f_server2client __ARGS((VAR argvars, VAR retvar));
366static void f_serverlist __ARGS((VAR argvars, VAR retvar));
367static void f_setline __ARGS((VAR argvars, VAR retvar));
368static void f_setreg __ARGS((VAR argvars, VAR retvar));
369static void f_simplify __ARGS((VAR argvars, VAR retvar));
370static void find_some_match __ARGS((VAR argvars, VAR retvar, int start));
371static void f_strftime __ARGS((VAR argvars, VAR retvar));
372static void f_stridx __ARGS((VAR argvars, VAR retvar));
373static void f_strlen __ARGS((VAR argvars, VAR retvar));
374static void f_strpart __ARGS((VAR argvars, VAR retvar));
375static void f_strridx __ARGS((VAR argvars, VAR retvar));
376static void f_strtrans __ARGS((VAR argvars, VAR retvar));
377static void f_synID __ARGS((VAR argvars, VAR retvar));
378static void f_synIDattr __ARGS((VAR argvars, VAR retvar));
379static void f_synIDtrans __ARGS((VAR argvars, VAR retvar));
380static void f_system __ARGS((VAR argvars, VAR retvar));
381static void f_submatch __ARGS((VAR argvars, VAR retvar));
382static void f_substitute __ARGS((VAR argvars, VAR retvar));
383static void f_tempname __ARGS((VAR argvars, VAR retvar));
384static void f_tolower __ARGS((VAR argvars, VAR retvar));
385static void f_toupper __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar8299df92004-07-10 09:47:34 +0000386static void f_tr __ARGS((VAR argvars, VAR retvar));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387static void f_type __ARGS((VAR argvars, VAR retvar));
388static void f_virtcol __ARGS((VAR argvars, VAR retvar));
389static void f_visualmode __ARGS((VAR argvars, VAR retvar));
390static void f_winbufnr __ARGS((VAR argvars, VAR retvar));
391static void f_wincol __ARGS((VAR argvars, VAR retvar));
392static void f_winheight __ARGS((VAR argvars, VAR retvar));
393static void f_winline __ARGS((VAR argvars, VAR retvar));
394static void f_winnr __ARGS((VAR argvars, VAR retvar));
395static void f_winrestcmd __ARGS((VAR argvars, VAR retvar));
396static void f_winwidth __ARGS((VAR argvars, VAR retvar));
397static win_T *find_win_by_nr __ARGS((VAR vp));
398static pos_T *var2fpos __ARGS((VAR varp, int lnum));
399static int get_env_len __ARGS((char_u **arg));
400static int get_id_len __ARGS((char_u **arg));
401static int get_func_len __ARGS((char_u **arg, char_u **alias, int evaluate));
402static char_u *find_name_end __ARGS((char_u *arg, char_u **expr_start, char_u **expr_end));
403static int eval_isnamec __ARGS((int c));
404static int find_vim_var __ARGS((char_u *name, int len));
405static int get_var_var __ARGS((char_u *name, int len, VAR retvar));
406static VAR alloc_var __ARGS((void));
407static VAR alloc_string_var __ARGS((char_u *string));
408static void free_var __ARGS((VAR varp));
409static void clear_var __ARGS((VAR varp));
410static long get_var_number __ARGS((VAR varp));
411static linenr_T get_var_lnum __ARGS((VAR argvars));
412static char_u *get_var_string __ARGS((VAR varp));
413static char_u *get_var_string_buf __ARGS((VAR varp, char_u *buf));
414static VAR find_var __ARGS((char_u *name, int writing));
415static VAR find_var_in_ga __ARGS((garray_T *gap, char_u *varname));
416static garray_T *find_var_ga __ARGS((char_u *name, char_u **varname));
417static void var_free_one __ARGS((VAR v));
418static void list_one_var __ARGS((VAR v, char_u *prefix));
419static void list_vim_var __ARGS((int i));
420static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string));
421static void set_var __ARGS((char_u *name, VAR varp));
422static void copy_var __ARGS((VAR from, VAR to));
423static char_u *find_option_end __ARGS((char_u **arg, int *opt_flags));
424static char_u *trans_function_name __ARGS((char_u **pp, int skip, int internal));
425static int eval_fname_script __ARGS((char_u *p));
426static int eval_fname_sid __ARGS((char_u *p));
427static void list_func_head __ARGS((ufunc_T *fp, int indent));
428static void cat_func_name __ARGS((char_u *buf, ufunc_T *fp));
429static ufunc_T *find_func __ARGS((char_u *name));
430static void call_user_func __ARGS((ufunc_T *fp, int argcount, VAR argvars, VAR retvar, linenr_T firstline, linenr_T lastline));
431
432/* Magic braces are always enabled, otherwise Vim scripts would not be
433 * portable. */
434#define FEAT_MAGIC_BRACES
435
436#ifdef FEAT_MAGIC_BRACES
437static char_u * make_expanded_name __ARGS((char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end));
438#endif
439
440/*
441 * Set an internal variable to a string value. Creates the variable if it does
442 * not already exist.
443 */
444 void
445set_internal_string_var(name, value)
446 char_u *name;
447 char_u *value;
448{
449 char_u *val;
450 VAR varp;
451
452 val = vim_strsave(value);
453 if (val != NULL)
454 {
455 varp = alloc_string_var(val);
456 if (varp != NULL)
457 {
458 set_var(name, varp);
459 free_var(varp);
460 }
461 }
462}
463
464# if defined(FEAT_MBYTE) || defined(PROTO)
465 int
466eval_charconvert(enc_from, enc_to, fname_from, fname_to)
467 char_u *enc_from;
468 char_u *enc_to;
469 char_u *fname_from;
470 char_u *fname_to;
471{
472 int err = FALSE;
473
474 set_vim_var_string(VV_CC_FROM, enc_from, -1);
475 set_vim_var_string(VV_CC_TO, enc_to, -1);
476 set_vim_var_string(VV_FNAME_IN, fname_from, -1);
477 set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
478 if (eval_to_bool(p_ccv, &err, NULL, FALSE))
479 err = TRUE;
480 set_vim_var_string(VV_CC_FROM, NULL, -1);
481 set_vim_var_string(VV_CC_TO, NULL, -1);
482 set_vim_var_string(VV_FNAME_IN, NULL, -1);
483 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
484
485 if (err)
486 return FAIL;
487 return OK;
488}
489# endif
490
491# if defined(FEAT_POSTSCRIPT) || defined(PROTO)
492 int
493eval_printexpr(fname, args)
494 char_u *fname;
495 char_u *args;
496{
497 int err = FALSE;
498
499 set_vim_var_string(VV_FNAME_IN, fname, -1);
500 set_vim_var_string(VV_CMDARG, args, -1);
501 if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
502 err = TRUE;
503 set_vim_var_string(VV_FNAME_IN, NULL, -1);
504 set_vim_var_string(VV_CMDARG, NULL, -1);
505
506 if (err)
507 {
508 mch_remove(fname);
509 return FAIL;
510 }
511 return OK;
512}
513# endif
514
515# if defined(FEAT_DIFF) || defined(PROTO)
516 void
517eval_diff(origfile, newfile, outfile)
518 char_u *origfile;
519 char_u *newfile;
520 char_u *outfile;
521{
522 int err = FALSE;
523
524 set_vim_var_string(VV_FNAME_IN, origfile, -1);
525 set_vim_var_string(VV_FNAME_NEW, newfile, -1);
526 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
527 (void)eval_to_bool(p_dex, &err, NULL, FALSE);
528 set_vim_var_string(VV_FNAME_IN, NULL, -1);
529 set_vim_var_string(VV_FNAME_NEW, NULL, -1);
530 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
531}
532
533 void
534eval_patch(origfile, difffile, outfile)
535 char_u *origfile;
536 char_u *difffile;
537 char_u *outfile;
538{
539 int err;
540
541 set_vim_var_string(VV_FNAME_IN, origfile, -1);
542 set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
543 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
544 (void)eval_to_bool(p_pex, &err, NULL, FALSE);
545 set_vim_var_string(VV_FNAME_IN, NULL, -1);
546 set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
547 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
548}
549# endif
550
551/*
552 * Top level evaluation function, returning a boolean.
553 * Sets "error" to TRUE if there was an error.
554 * Return TRUE or FALSE.
555 */
556 int
557eval_to_bool(arg, error, nextcmd, skip)
558 char_u *arg;
559 int *error;
560 char_u **nextcmd;
561 int skip; /* only parse, don't execute */
562{
563 var retvar;
564 int retval = FALSE;
565
566 if (skip)
567 ++emsg_skip;
568 if (eval0(arg, &retvar, nextcmd, !skip) == FAIL)
569 {
570 *error = TRUE;
571 }
572 else
573 {
574 *error = FALSE;
575 if (!skip)
576 {
577 retval = (get_var_number(&retvar) != 0);
578 clear_var(&retvar);
579 }
580 }
581 if (skip)
582 --emsg_skip;
583
584 return retval;
585}
586
587/*
588 * Top level evaluation function, returning a string. If "skip" is TRUE,
589 * only parsing to "nextcmd" is done, without reporting errors. Return
590 * pointer to allocated memory, or NULL for failure or when "skip" is TRUE.
591 */
592 char_u *
593eval_to_string_skip(arg, nextcmd, skip)
594 char_u *arg;
595 char_u **nextcmd;
596 int skip; /* only parse, don't execute */
597{
598 var retvar;
599 char_u *retval;
600
601 if (skip)
602 ++emsg_skip;
603 if (eval0(arg, &retvar, nextcmd, !skip) == FAIL || skip)
604 retval = NULL;
605 else
606 {
607 retval = vim_strsave(get_var_string(&retvar));
608 clear_var(&retvar);
609 }
610 if (skip)
611 --emsg_skip;
612
613 return retval;
614}
615
616/*
Bram Moolenaar69a7cb42004-06-20 12:51:53 +0000617 * Skip over an expression at "*pp".
618 * Return FAIL for an error, OK otherwise.
619 */
620 int
621skip_expr(pp)
622 char_u **pp;
623{
624 var retvar;
625
626 *pp = skipwhite(*pp);
627 return eval1(pp, &retvar, FALSE);
628}
629
630/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 * Top level evaluation function, returning a string.
632 * Return pointer to allocated memory, or NULL for failure.
633 */
634 char_u *
635eval_to_string(arg, nextcmd)
636 char_u *arg;
637 char_u **nextcmd;
638{
639 var retvar;
640 char_u *retval;
641
642 if (eval0(arg, &retvar, nextcmd, TRUE) == FAIL)
643 retval = NULL;
644 else
645 {
646 retval = vim_strsave(get_var_string(&retvar));
647 clear_var(&retvar);
648 }
649
650 return retval;
651}
652
653/*
654 * Call eval_to_string() with "sandbox" set and not using local variables.
655 */
656 char_u *
657eval_to_string_safe(arg, nextcmd)
658 char_u *arg;
659 char_u **nextcmd;
660{
661 char_u *retval;
662 void *save_funccalp;
663
664 save_funccalp = save_funccal();
665 ++sandbox;
666 retval = eval_to_string(arg, nextcmd);
667 --sandbox;
668 restore_funccal(save_funccalp);
669 return retval;
670}
671
672#if 0 /* not used */
673/*
674 * Top level evaluation function, returning a string.
675 * Advances "arg" to the first non-blank after the evaluated expression.
676 * Return pointer to allocated memory, or NULL for failure.
677 * Doesn't give error messages.
678 */
679 char_u *
680eval_arg_to_string(arg)
681 char_u **arg;
682{
683 var retvar;
684 char_u *retval;
685 int ret;
686
687 ++emsg_off;
688
689 ret = eval1(arg, &retvar, TRUE);
690 if (ret == FAIL)
691 retval = NULL;
692 else
693 {
694 retval = vim_strsave(get_var_string(&retvar));
695 clear_var(&retvar);
696 }
697
698 --emsg_off;
699
700 return retval;
701}
702#endif
703
704/*
705 * Top level evaluation function, returning a number.
706 * Evaluates "expr" silently.
707 * Returns -1 for an error.
708 */
709 int
710eval_to_number(expr)
711 char_u *expr;
712{
713 var retvar;
714 int retval;
715 char_u *p = expr;
716
717 ++emsg_off;
718
719 if (eval1(&p, &retvar, TRUE) == FAIL)
720 retval = -1;
721 else
722 {
723 retval = get_var_number(&retvar);
724 clear_var(&retvar);
725 }
726 --emsg_off;
727
728 return retval;
729}
730
731#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO)
732/*
733 * Call some vimL function and return the result as a string
734 * Uses argv[argc] for the function arguments.
735 */
736 char_u *
737call_vim_function(func, argc, argv, safe)
738 char_u *func;
739 int argc;
740 char_u **argv;
741 int safe; /* use the sandbox */
742{
743 char_u *retval = NULL;
744 var retvar;
745 VAR argvars;
746 long n;
747 int len;
748 int i;
749 int doesrange;
750 void *save_funccalp = NULL;
751
752 argvars = (VAR)alloc((unsigned)(argc * sizeof(var)));
753 if (argvars == NULL)
754 return NULL;
755
756 for (i = 0; i < argc; i++)
757 {
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +0000758 /* Pass a NULL or empty argument as an empty string */
759 if (argv[i] == NULL || *argv[i] == NUL)
760 {
761 argvars[i].var_type = VAR_STRING;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000762 argvars[i].var_val.var_string = (char_u *)"";
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +0000763 continue;
764 }
765
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 /* Recognize a number argument, the others must be strings. */
767 vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL);
768 if (len != 0 && len == (int)STRLEN(argv[i]))
769 {
770 argvars[i].var_type = VAR_NUMBER;
771 argvars[i].var_val.var_number = n;
772 }
773 else
774 {
775 argvars[i].var_type = VAR_STRING;
776 argvars[i].var_val.var_string = argv[i];
777 }
778 }
779
780 if (safe)
781 {
782 save_funccalp = save_funccal();
783 ++sandbox;
784 }
785
786 retvar.var_type = VAR_UNKNOWN; /* clear_var() uses this */
787 if (call_func(func, (int)STRLEN(func), &retvar, argc, argvars,
788 curwin->w_cursor.lnum, curwin->w_cursor.lnum,
789 &doesrange, TRUE) == OK)
790 retval = vim_strsave(get_var_string(&retvar));
791
792 clear_var(&retvar);
793 vim_free(argvars);
794
795 if (safe)
796 {
797 --sandbox;
798 restore_funccal(save_funccalp);
799 }
800 return retval;
801}
802#endif
803
804/*
805 * Save the current function call pointer, and set it to NULL.
806 * Used when executing autocommands and for ":source".
807 */
808 void *
809save_funccal()
810{
811 struct funccall *fc;
812
813 fc = current_funccal;
814 current_funccal = NULL;
815 return (void *)fc;
816}
817
818 void
819restore_funccal(fc)
820 void *fc;
821{
822 current_funccal = (struct funccall *)fc;
823}
824
825#ifdef FEAT_FOLDING
826/*
827 * Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding
828 * it in "*cp". Doesn't give error messages.
829 */
830 int
831eval_foldexpr(arg, cp)
832 char_u *arg;
833 int *cp;
834{
835 var retvar;
836 int retval;
837 char_u *s;
838
839 ++emsg_off;
840 ++sandbox;
841 *cp = NUL;
842 if (eval0(arg, &retvar, NULL, TRUE) == FAIL)
843 retval = 0;
844 else
845 {
846 /* If the result is a number, just return the number. */
847 if (retvar.var_type == VAR_NUMBER)
848 retval = retvar.var_val.var_number;
849 else if (retvar.var_type == VAR_UNKNOWN
850 || retvar.var_val.var_string == NULL)
851 retval = 0;
852 else
853 {
854 /* If the result is a string, check if there is a non-digit before
855 * the number. */
856 s = retvar.var_val.var_string;
857 if (!VIM_ISDIGIT(*s) && *s != '-')
858 *cp = *s++;
859 retval = atol((char *)s);
860 }
861 clear_var(&retvar);
862 }
863 --emsg_off;
864 --sandbox;
865
866 return retval;
867}
868#endif
869
870#ifdef FEAT_MAGIC_BRACES
871/*
872 * Expands out the 'magic' {}'s in a variable/function name.
873 * Note that this can call itself recursively, to deal with
874 * constructs like foo{bar}{baz}{bam}
875 * The four pointer arguments point to "foo{expre}ss{ion}bar"
876 * "in_start" ^
877 * "expr_start" ^
878 * "expr_end" ^
879 * "in_end" ^
880 *
881 * Returns a new allocated string, which the caller must free.
882 * Returns NULL for failure.
883 */
884 static char_u *
885make_expanded_name(in_start, expr_start, expr_end, in_end)
886 char_u *in_start;
887 char_u *expr_start;
888 char_u *expr_end;
889 char_u *in_end;
890{
891 char_u c1;
892 char_u *retval = NULL;
893 char_u *temp_result;
894 char_u *nextcmd = NULL;
895
896 if (expr_end == NULL || in_end == NULL)
897 return NULL;
898 *expr_start = NUL;
899 *expr_end = NUL;
900 c1 = *in_end;
901 *in_end = NUL;
902
903 temp_result = eval_to_string(expr_start + 1, &nextcmd);
904 if (temp_result != NULL && nextcmd == NULL)
905 {
906 retval = alloc((unsigned)(STRLEN(temp_result) + (expr_start - in_start)
907 + (in_end - expr_end) + 1));
908
909 if (retval != NULL)
910 {
911 STRCPY(retval, in_start);
912 STRCAT(retval, temp_result);
913 STRCAT(retval, expr_end + 1);
914 }
915 }
916 vim_free(temp_result);
917
918 *in_end = c1; /* put char back for error messages */
919 *expr_start = '{';
920 *expr_end = '}';
921
922 if (retval != NULL)
923 {
924 temp_result = find_name_end(retval, &expr_start, &expr_end);
925 if (expr_start != NULL)
926 {
927 /* Further expansion! */
928 temp_result = make_expanded_name(retval, expr_start,
929 expr_end, temp_result);
930 vim_free(retval);
931 retval = temp_result;
932 }
933 }
934
935 return retval;
936
937}
938#endif /* FEAT_MAGIC_BRACES */
939
940/*
941 * ":let var = expr" assignment command.
942 * ":let var" list one variable value
943 * ":let" list all variable values
944 */
945 void
946ex_let(eap)
947 exarg_T *eap;
948{
949 char_u *arg = eap->arg;
950 char_u *expr;
951 char_u *name;
952 VAR varp;
953 var retvar;
954 char_u *p;
955 int c1 = 0, c2;
956 int i;
957 char_u *expr_start;
958 char_u *expr_end;
959 char_u *name_end;
960
961 name_end = find_name_end(arg, &expr_start, &expr_end);
962 expr = vim_strchr(name_end, '=');
963 if (expr == NULL)
964 {
965 if (ends_excmd(*arg))
966 {
967 if (!eap->skip)
968 {
969 /*
970 * List all variables.
971 */
972 for (i = 0; i < variables.ga_len && !got_int; ++i)
973 if (VAR_ENTRY(i).var_name != NULL)
974 list_one_var(&VAR_ENTRY(i), (char_u *)"");
975 for (i = 0; i < curbuf->b_vars.ga_len && !got_int; ++i)
976 if (BVAR_ENTRY(i).var_name != NULL)
977 list_one_var(&BVAR_ENTRY(i), (char_u *)"b:");
978 for (i = 0; i < curwin->w_vars.ga_len && !got_int; ++i)
979 if (WVAR_ENTRY(i).var_name != NULL)
980 list_one_var(&WVAR_ENTRY(i), (char_u *)"w:");
981 for (i = 0; i < VV_LEN && !got_int; ++i)
982 if (vimvars[i].type == VAR_NUMBER || vimvars[i].val != NULL)
983 list_vim_var(i);
984 }
985 }
986 else
987 {
988 int error = FALSE;
989
990 /*
991 * List variables.
992 */
993 while (!ends_excmd(*arg) && !got_int)
994 {
995 char_u *temp_string = NULL;
996 int arg_len;
997
998 /* Find the end of the name. */
999 name_end = find_name_end(arg, &expr_start, &expr_end);
1000
1001 if (!vim_iswhite(*name_end) && !ends_excmd(*name_end))
1002 {
1003 emsg_severe = TRUE;
1004 EMSG(_(e_trailing));
1005 break;
1006 }
1007 if (!error && !eap->skip)
1008 {
1009#ifdef FEAT_MAGIC_BRACES
1010 if (expr_start != NULL)
1011 {
1012 temp_string = make_expanded_name(arg, expr_start,
1013 expr_end, name_end);
1014 if (temp_string == NULL)
1015 {
1016 /*
1017 * Report an invalid expression in braces, unless
1018 * the expression evaluation has been cancelled due
1019 * to an aborting error, an interrupt, or an
1020 * exception.
1021 */
1022 if (!aborting())
1023 {
1024 emsg_severe = TRUE;
1025 EMSG2(_(e_invarg2), arg);
1026 break;
1027 }
1028 error = TRUE;
1029 arg = skipwhite(name_end);
1030 continue;
1031 }
1032 arg = temp_string;
1033 arg_len = STRLEN(temp_string);
1034 }
1035 else
1036#endif
1037 {
1038 c1 = *name_end;
1039 *name_end = NUL;
1040 arg_len = (int)(name_end - arg);
1041 }
1042 i = find_vim_var(arg, arg_len);
1043 if (i >= 0)
1044 list_vim_var(i);
1045 else if (STRCMP("b:changedtick", arg) == 0)
1046 {
1047 char_u numbuf[NUMBUFLEN];
1048
1049 sprintf((char *)numbuf, "%ld",
1050 (long)curbuf->b_changedtick);
1051 list_one_var_a((char_u *)"b:", (char_u *)"changedtick",
1052 VAR_NUMBER, numbuf);
1053 }
1054 else
1055 {
1056 varp = find_var(arg, FALSE);
1057 if (varp == NULL)
1058 {
1059 /* Skip further arguments but do continue to
1060 * search for a trailing command. */
1061 EMSG2(_("E106: Unknown variable: \"%s\""), arg);
1062 error = TRUE;
1063 }
1064 else
1065 {
1066 name = vim_strchr(arg, ':');
1067 if (name != NULL)
1068 {
1069 /* "a:" vars have no name stored, use whole
1070 * arg */
1071 if (arg[0] == 'a' && arg[1] == ':')
1072 c2 = NUL;
1073 else
1074 {
1075 c2 = *++name;
1076 *name = NUL;
1077 }
1078 list_one_var(varp, arg);
1079 if (c2 != NUL)
1080 *name = c2;
1081 }
1082 else
1083 list_one_var(varp, (char_u *)"");
1084 }
1085 }
1086#ifdef FEAT_MAGIC_BRACES
1087 if (expr_start != NULL)
1088 vim_free(temp_string);
1089 else
1090#endif
1091 *name_end = c1;
1092 }
1093 arg = skipwhite(name_end);
1094 }
1095 }
1096 eap->nextcmd = check_nextcmd(arg);
1097 }
1098 else
1099 {
1100 if (eap->skip)
1101 ++emsg_skip;
1102 i = eval0(expr + 1, &retvar, &eap->nextcmd, !eap->skip);
1103 if (eap->skip)
1104 {
1105 if (i != FAIL)
1106 clear_var(&retvar);
1107 --emsg_skip;
1108 }
1109 else if (i != FAIL)
1110 {
1111 /*
1112 * ":let $VAR = expr": Set environment variable.
1113 */
1114 if (*arg == '$')
1115 {
1116 int len;
1117 int cc;
1118
1119 /* Find the end of the name. */
1120 ++arg;
1121 name = arg;
1122 len = get_env_len(&arg);
1123 if (len == 0)
1124 EMSG2(_(e_invarg2), name - 1);
1125 else
1126 {
1127 if (*skipwhite(arg) != '=')
1128 EMSG(_(e_letunexp));
1129 else
1130 {
1131 cc = name[len];
1132 name[len] = NUL;
1133 p = get_var_string(&retvar);
1134 vim_setenv(name, p);
1135 if (STRICMP(name, "HOME") == 0)
1136 init_homedir();
1137 else if (didset_vim && STRICMP(name, "VIM") == 0)
1138 didset_vim = FALSE;
1139 else if (didset_vimruntime
1140 && STRICMP(name, "VIMRUNTIME") == 0)
1141 didset_vimruntime = FALSE;
1142 name[len] = cc;
1143 }
1144 }
1145 }
1146
1147 /*
1148 * ":let &option = expr": Set option value.
1149 * ":let &l:option = expr": Set local option value.
1150 * ":let &g:option = expr": Set global option value.
1151 */
1152 else if (*arg == '&')
1153 {
1154 int opt_flags;
1155
1156 /*
1157 * Find the end of the name;
1158 */
1159 p = find_option_end(&arg, &opt_flags);
1160 if (p == NULL || *skipwhite(p) != '=')
1161 EMSG(_(e_letunexp));
1162 else
1163 {
1164 c1 = *p;
1165 *p = NUL;
1166 set_option_value(arg, get_var_number(&retvar),
1167 get_var_string(&retvar), opt_flags);
1168 *p = c1; /* put back for error messages */
1169 }
1170 }
1171
1172 /*
1173 * ":let @r = expr": Set register contents.
1174 */
1175 else if (*arg == '@')
1176 {
1177 ++arg;
1178 if (*skipwhite(arg + 1) != '=')
1179 EMSG(_(e_letunexp));
1180 else
1181 write_reg_contents(*arg == '@' ? '"' : *arg,
1182 get_var_string(&retvar), -1, FALSE);
1183 }
1184
1185 /*
1186 * ":let var = expr": Set internal variable.
1187 */
1188 else if (eval_isnamec(*arg) && !VIM_ISDIGIT(*arg))
1189 {
1190 /* Find the end of the name. */
1191 p = find_name_end(arg, &expr_start, &expr_end);
1192
1193 if (*skipwhite(p) != '=')
1194 EMSG(_(e_letunexp));
1195 else if (p - arg == 13
1196 && STRNCMP(arg, "b:changedtick", 13) == 0)
1197 EMSG2(_(e_readonlyvar), arg);
1198#ifdef FEAT_MAGIC_BRACES
1199 else if (expr_start != NULL)
1200 {
1201 char_u *temp_string;
1202
1203 temp_string = make_expanded_name(arg, expr_start,
1204 expr_end, p);
1205 if (temp_string == NULL)
1206 {
1207 /*
1208 * Report an invalid expression in braces, unless the
1209 * expression evaluation has been cancelled due to an
1210 * aborting error, an interrupt, or an exception.
1211 */
1212 if (!aborting())
1213 EMSG2(_(e_invarg2), arg);
1214 }
1215 else
1216 {
1217 set_var(temp_string, &retvar);
1218 vim_free(temp_string);
1219 }
1220 }
1221#endif
1222 else
1223 {
1224 c1 = *p;
1225 *p = NUL;
1226 set_var(arg, &retvar);
1227 *p = c1; /* put char back for error messages */
1228 }
1229 }
1230
1231 else
1232 {
1233 EMSG2(_(e_invarg2), arg);
1234 }
1235
1236 clear_var(&retvar);
1237 }
1238 }
1239}
1240
1241#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1242
1243 void
1244set_context_for_expression(xp, arg, cmdidx)
1245 expand_T *xp;
1246 char_u *arg;
1247 cmdidx_T cmdidx;
1248{
1249 int got_eq = FALSE;
1250 int c;
1251
1252 xp->xp_context = cmdidx == CMD_let ? EXPAND_USER_VARS
1253 : cmdidx == CMD_call ? EXPAND_FUNCTIONS
1254 : EXPAND_EXPRESSION;
1255 while ((xp->xp_pattern = vim_strpbrk(arg,
1256 (char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL)
1257 {
1258 c = *xp->xp_pattern;
1259 if (c == '&')
1260 {
1261 c = xp->xp_pattern[1];
1262 if (c == '&')
1263 {
1264 ++xp->xp_pattern;
1265 xp->xp_context = cmdidx != CMD_let || got_eq
1266 ? EXPAND_EXPRESSION : EXPAND_NOTHING;
1267 }
1268 else if (c != ' ')
1269 xp->xp_context = EXPAND_SETTINGS;
1270 }
1271 else if (c == '$')
1272 {
1273 /* environment variable */
1274 xp->xp_context = EXPAND_ENV_VARS;
1275 }
1276 else if (c == '=')
1277 {
1278 got_eq = TRUE;
1279 xp->xp_context = EXPAND_EXPRESSION;
1280 }
1281 else if (c == '<'
1282 && xp->xp_context == EXPAND_FUNCTIONS
1283 && vim_strchr(xp->xp_pattern, '(') == NULL)
1284 {
1285 /* Function name can start with "<SNR>" */
1286 break;
1287 }
1288 else if (cmdidx != CMD_let || got_eq)
1289 {
1290 if (c == '"') /* string */
1291 {
1292 while ((c = *++xp->xp_pattern) != NUL && c != '"')
1293 if (c == '\\' && xp->xp_pattern[1] != NUL)
1294 ++xp->xp_pattern;
1295 xp->xp_context = EXPAND_NOTHING;
1296 }
1297 else if (c == '\'') /* literal string */
1298 {
1299 while ((c = *++xp->xp_pattern) != NUL && c != '\'')
1300 /* skip */ ;
1301 xp->xp_context = EXPAND_NOTHING;
1302 }
1303 else if (c == '|')
1304 {
1305 if (xp->xp_pattern[1] == '|')
1306 {
1307 ++xp->xp_pattern;
1308 xp->xp_context = EXPAND_EXPRESSION;
1309 }
1310 else
1311 xp->xp_context = EXPAND_COMMANDS;
1312 }
1313 else
1314 xp->xp_context = EXPAND_EXPRESSION;
1315 }
1316 else
1317 xp->xp_context = EXPAND_NOTHING;
1318 arg = xp->xp_pattern;
1319 if (*arg != NUL)
1320 while ((c = *++arg) != NUL && (c == ' ' || c == '\t'))
1321 /* skip */ ;
1322 }
1323 xp->xp_pattern = arg;
1324}
1325
1326#endif /* FEAT_CMDL_COMPL */
1327
1328/*
1329 * ":1,25call func(arg1, arg2)" function call.
1330 */
1331 void
1332ex_call(eap)
1333 exarg_T *eap;
1334{
1335 char_u *arg = eap->arg;
1336 char_u *startarg;
1337 char_u *alias;
1338 char_u *name;
1339 var retvar;
1340 int len;
1341 linenr_T lnum;
1342 int doesrange;
1343 int failed = FALSE;
1344
1345 name = arg;
1346 len = get_func_len(&arg, &alias, !eap->skip);
1347 if (len == 0)
1348 goto end;
1349 if (alias != NULL)
1350 name = alias;
1351
1352 startarg = arg;
1353 retvar.var_type = VAR_UNKNOWN; /* clear_var() uses this */
1354
1355 if (*startarg != '(')
1356 {
1357 EMSG2(_("E107: Missing braces: %s"), name);
1358 goto end;
1359 }
1360
1361 /*
1362 * When skipping, evaluate the function once, to find the end of the
1363 * arguments.
1364 * When the function takes a range, this is discovered after the first
1365 * call, and the loop is broken.
1366 */
1367 if (eap->skip)
1368 {
1369 ++emsg_skip;
1370 lnum = eap->line2; /* do it once, also with an invalid range */
1371 }
1372 else
1373 lnum = eap->line1;
1374 for ( ; lnum <= eap->line2; ++lnum)
1375 {
1376 if (!eap->skip && eap->addr_count > 0)
1377 {
1378 curwin->w_cursor.lnum = lnum;
1379 curwin->w_cursor.col = 0;
1380 }
1381 arg = startarg;
1382 if (get_func_var(name, len, &retvar, &arg,
1383 eap->line1, eap->line2, &doesrange, !eap->skip) == FAIL)
1384 {
1385 failed = TRUE;
1386 break;
1387 }
1388 clear_var(&retvar);
1389 if (doesrange || eap->skip)
1390 break;
1391 /* Stop when immediately aborting on error, or when an interrupt
1392 * occurred or an exception was thrown but not caught. get_func_var()
1393 * returned OK, so that the check for trailing characters below is
1394 * executed. */
1395 if (aborting())
1396 break;
1397 }
1398 if (eap->skip)
1399 --emsg_skip;
1400
1401 if (!failed)
1402 {
1403 /* Check for trailing illegal characters and a following command. */
1404 if (!ends_excmd(*arg))
1405 {
1406 emsg_severe = TRUE;
1407 EMSG(_(e_trailing));
1408 }
1409 else
1410 eap->nextcmd = check_nextcmd(arg);
1411 }
1412
1413end:
1414 if (alias != NULL)
1415 vim_free(alias);
1416}
1417
1418/*
1419 * ":unlet[!] var1 ... " command.
1420 */
1421 void
1422ex_unlet(eap)
1423 exarg_T *eap;
1424{
1425 char_u *arg = eap->arg;
1426 char_u *name_end;
1427 char_u cc;
1428 char_u *expr_start;
1429 char_u *expr_end;
1430 int error = FALSE;
1431
1432 do
1433 {
1434 /* Find the end of the name. */
1435 name_end = find_name_end(arg, &expr_start, &expr_end);
1436
1437 if (!vim_iswhite(*name_end) && !ends_excmd(*name_end))
1438 {
1439 emsg_severe = TRUE;
1440 EMSG(_(e_trailing));
1441 break;
1442 }
1443
1444 if (!error && !eap->skip)
1445 {
1446#ifdef FEAT_MAGIC_BRACES
1447 if (expr_start != NULL)
1448 {
1449 char_u *temp_string;
1450
1451 temp_string = make_expanded_name(arg, expr_start,
1452 expr_end, name_end);
1453 if (temp_string == NULL)
1454 {
1455 /*
1456 * Report an invalid expression in braces, unless the
1457 * expression evaluation has been cancelled due to an
1458 * aborting error, an interrupt, or an exception.
1459 */
1460 if (!aborting())
1461 {
1462 emsg_severe = TRUE;
1463 EMSG2(_(e_invarg2), arg);
1464 break;
1465 }
1466 error = TRUE;
1467 }
1468 else
1469 {
1470 if (do_unlet(temp_string) == FAIL && !eap->forceit)
1471 {
1472 EMSG2(_("E108: No such variable: \"%s\""), temp_string);
1473 error = TRUE;
1474 }
1475 vim_free(temp_string);
1476 }
1477 }
1478 else
1479#endif
1480 {
1481 cc = *name_end;
1482 *name_end = NUL;
1483
1484 if (do_unlet(arg) == FAIL && !eap->forceit)
1485 {
1486 EMSG2(_("E108: No such variable: \"%s\""), arg);
1487 error = TRUE;
1488 }
1489
1490 *name_end = cc;
1491 }
1492 }
1493 arg = skipwhite(name_end);
1494 } while (!ends_excmd(*arg));
1495
1496 eap->nextcmd = check_nextcmd(arg);
1497}
1498
1499/*
1500 * "unlet" a variable. Return OK if it existed, FAIL if not.
1501 */
1502 int
1503do_unlet(name)
1504 char_u *name;
1505{
1506 VAR v;
1507
1508 v = find_var(name, TRUE);
1509 if (v != NULL)
1510 {
1511 var_free_one(v);
1512 return OK;
1513 }
1514 return FAIL;
1515}
1516
1517#if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
1518/*
1519 * Delete all "menutrans_" variables.
1520 */
1521 void
1522del_menutrans_vars()
1523{
1524 int i;
1525
1526 for (i = 0; i < variables.ga_len; ++i)
1527 if (VAR_ENTRY(i).var_name != NULL
1528 && STRNCMP(VAR_ENTRY(i).var_name, "menutrans_", 10) == 0)
1529 var_free_one(&VAR_ENTRY(i));
1530}
1531#endif
1532
1533#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1534
1535/*
1536 * Local string buffer for the next two functions to store a variable name
1537 * with its prefix. Allocated in cat_prefix_varname(), freed later in
1538 * get_user_var_name().
1539 */
1540
1541static char_u *cat_prefix_varname __ARGS((int prefix, char_u *name));
1542
1543static char_u *varnamebuf = NULL;
1544static int varnamebuflen = 0;
1545
1546/*
1547 * Function to concatenate a prefix and a variable name.
1548 */
1549 static char_u *
1550cat_prefix_varname(prefix, name)
1551 int prefix;
1552 char_u *name;
1553{
1554 int len;
1555
1556 len = (int)STRLEN(name) + 3;
1557 if (len > varnamebuflen)
1558 {
1559 vim_free(varnamebuf);
1560 len += 10; /* some additional space */
1561 varnamebuf = alloc(len);
1562 if (varnamebuf == NULL)
1563 {
1564 varnamebuflen = 0;
1565 return NULL;
1566 }
1567 varnamebuflen = len;
1568 }
1569 *varnamebuf = prefix;
1570 varnamebuf[1] = ':';
1571 STRCPY(varnamebuf + 2, name);
1572 return varnamebuf;
1573}
1574
1575/*
1576 * Function given to ExpandGeneric() to obtain the list of user defined
1577 * (global/buffer/window/built-in) variable names.
1578 */
1579/*ARGSUSED*/
1580 char_u *
1581get_user_var_name(xp, idx)
1582 expand_T *xp;
1583 int idx;
1584{
1585 static int gidx;
1586 static int bidx;
1587 static int widx;
1588 static int vidx;
1589 char_u *name;
1590
1591 if (idx == 0)
1592 gidx = bidx = widx = vidx = 0;
1593 if (gidx < variables.ga_len) /* Global variables */
1594 {
1595 while ((name = VAR_ENTRY(gidx++).var_name) == NULL
1596 && gidx < variables.ga_len)
1597 /* skip */;
1598 if (name != NULL)
1599 {
1600 if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
1601 return cat_prefix_varname('g', name);
1602 else
1603 return name;
1604 }
1605 }
1606 if (bidx < curbuf->b_vars.ga_len) /* Current buffer variables */
1607 {
1608 while ((name = BVAR_ENTRY(bidx++).var_name) == NULL
1609 && bidx < curbuf->b_vars.ga_len)
1610 /* skip */;
1611 if (name != NULL)
1612 return cat_prefix_varname('b', name);
1613 }
1614 if (bidx == curbuf->b_vars.ga_len)
1615 {
1616 ++bidx;
1617 return (char_u *)"b:changedtick";
1618 }
1619 if (widx < curwin->w_vars.ga_len) /* Current window variables */
1620 {
1621 while ((name = WVAR_ENTRY(widx++).var_name) == NULL
1622 && widx < curwin->w_vars.ga_len)
1623 /* skip */;
1624 if (name != NULL)
1625 return cat_prefix_varname('w', name);
1626 }
1627 if (vidx < VV_LEN) /* Built-in variables */
1628 return cat_prefix_varname('v', (char_u *)vimvars[vidx++].name);
1629
1630 vim_free(varnamebuf);
1631 varnamebuf = NULL;
1632 varnamebuflen = 0;
1633 return NULL;
1634}
1635
1636#endif /* FEAT_CMDL_COMPL */
1637
1638/*
1639 * types for expressions.
1640 */
1641typedef enum
1642{
1643 TYPE_UNKNOWN = 0
1644 , TYPE_EQUAL /* == */
1645 , TYPE_NEQUAL /* != */
1646 , TYPE_GREATER /* > */
1647 , TYPE_GEQUAL /* >= */
1648 , TYPE_SMALLER /* < */
1649 , TYPE_SEQUAL /* <= */
1650 , TYPE_MATCH /* =~ */
1651 , TYPE_NOMATCH /* !~ */
1652} exptype_T;
1653
1654/*
1655 * The "evaluate" argument: When FALSE, the argument is only parsed but not
1656 * executed. The function may return OK, but the retvar will be of type
1657 * VAR_UNKNOWN. The function still returns FAIL for a syntax error.
1658 */
1659
1660/*
1661 * Handle zero level expression.
1662 * This calls eval1() and handles error message and nextcmd.
1663 * Return OK or FAIL.
1664 */
1665 static int
1666eval0(arg, retvar, nextcmd, evaluate)
1667 char_u *arg;
1668 VAR retvar;
1669 char_u **nextcmd;
1670 int evaluate;
1671{
1672 int ret;
1673 char_u *p;
1674
1675 p = skipwhite(arg);
1676 ret = eval1(&p, retvar, evaluate);
1677 if (ret == FAIL || !ends_excmd(*p))
1678 {
1679 if (ret != FAIL)
1680 clear_var(retvar);
1681 /*
1682 * Report the invalid expression unless the expression evaluation has
1683 * been cancelled due to an aborting error, an interrupt, or an
1684 * exception.
1685 */
1686 if (!aborting())
1687 EMSG2(_(e_invexpr2), arg);
1688 ret = FAIL;
1689 }
1690 if (nextcmd != NULL)
1691 *nextcmd = check_nextcmd(p);
1692
1693 return ret;
1694}
1695
1696/*
1697 * Handle top level expression:
1698 * expr1 ? expr0 : expr0
1699 *
1700 * "arg" must point to the first non-white of the expression.
1701 * "arg" is advanced to the next non-white after the recognized expression.
1702 *
1703 * Return OK or FAIL.
1704 */
1705 static int
1706eval1(arg, retvar, evaluate)
1707 char_u **arg;
1708 VAR retvar;
1709 int evaluate;
1710{
1711 int result;
1712 var var2;
1713
1714 /*
1715 * Get the first variable.
1716 */
1717 if (eval2(arg, retvar, evaluate) == FAIL)
1718 return FAIL;
1719
1720 if ((*arg)[0] == '?')
1721 {
1722 result = FALSE;
1723 if (evaluate)
1724 {
1725 if (get_var_number(retvar) != 0)
1726 result = TRUE;
1727 clear_var(retvar);
1728 }
1729
1730 /*
1731 * Get the second variable.
1732 */
1733 *arg = skipwhite(*arg + 1);
1734 if (eval1(arg, retvar, evaluate && result) == FAIL) /* recursive! */
1735 return FAIL;
1736
1737 /*
1738 * Check for the ":".
1739 */
1740 if ((*arg)[0] != ':')
1741 {
1742 EMSG(_("E109: Missing ':' after '?'"));
1743 if (evaluate && result)
1744 clear_var(retvar);
1745 return FAIL;
1746 }
1747
1748 /*
1749 * Get the third variable.
1750 */
1751 *arg = skipwhite(*arg + 1);
1752 if (eval1(arg, &var2, evaluate && !result) == FAIL) /* recursive! */
1753 {
1754 if (evaluate && result)
1755 clear_var(retvar);
1756 return FAIL;
1757 }
1758 if (evaluate && !result)
1759 *retvar = var2;
1760 }
1761
1762 return OK;
1763}
1764
1765/*
1766 * Handle first level expression:
1767 * expr2 || expr2 || expr2 logical OR
1768 *
1769 * "arg" must point to the first non-white of the expression.
1770 * "arg" is advanced to the next non-white after the recognized expression.
1771 *
1772 * Return OK or FAIL.
1773 */
1774 static int
1775eval2(arg, retvar, evaluate)
1776 char_u **arg;
1777 VAR retvar;
1778 int evaluate;
1779{
1780 var var2;
1781 long result;
1782 int first;
1783
1784 /*
1785 * Get the first variable.
1786 */
1787 if (eval3(arg, retvar, evaluate) == FAIL)
1788 return FAIL;
1789
1790 /*
1791 * Repeat until there is no following "||".
1792 */
1793 first = TRUE;
1794 result = FALSE;
1795 while ((*arg)[0] == '|' && (*arg)[1] == '|')
1796 {
1797 if (evaluate && first)
1798 {
1799 if (get_var_number(retvar) != 0)
1800 result = TRUE;
1801 clear_var(retvar);
1802 first = FALSE;
1803 }
1804
1805 /*
1806 * Get the second variable.
1807 */
1808 *arg = skipwhite(*arg + 2);
1809 if (eval3(arg, &var2, evaluate && !result) == FAIL)
1810 return FAIL;
1811
1812 /*
1813 * Compute the result.
1814 */
1815 if (evaluate && !result)
1816 {
1817 if (get_var_number(&var2) != 0)
1818 result = TRUE;
1819 clear_var(&var2);
1820 }
1821 if (evaluate)
1822 {
1823 retvar->var_type = VAR_NUMBER;
1824 retvar->var_val.var_number = result;
1825 }
1826 }
1827
1828 return OK;
1829}
1830
1831/*
1832 * Handle second level expression:
1833 * expr3 && expr3 && expr3 logical AND
1834 *
1835 * "arg" must point to the first non-white of the expression.
1836 * "arg" is advanced to the next non-white after the recognized expression.
1837 *
1838 * Return OK or FAIL.
1839 */
1840 static int
1841eval3(arg, retvar, evaluate)
1842 char_u **arg;
1843 VAR retvar;
1844 int evaluate;
1845{
1846 var var2;
1847 long result;
1848 int first;
1849
1850 /*
1851 * Get the first variable.
1852 */
1853 if (eval4(arg, retvar, evaluate) == FAIL)
1854 return FAIL;
1855
1856 /*
1857 * Repeat until there is no following "&&".
1858 */
1859 first = TRUE;
1860 result = TRUE;
1861 while ((*arg)[0] == '&' && (*arg)[1] == '&')
1862 {
1863 if (evaluate && first)
1864 {
1865 if (get_var_number(retvar) == 0)
1866 result = FALSE;
1867 clear_var(retvar);
1868 first = FALSE;
1869 }
1870
1871 /*
1872 * Get the second variable.
1873 */
1874 *arg = skipwhite(*arg + 2);
1875 if (eval4(arg, &var2, evaluate && result) == FAIL)
1876 return FAIL;
1877
1878 /*
1879 * Compute the result.
1880 */
1881 if (evaluate && result)
1882 {
1883 if (get_var_number(&var2) == 0)
1884 result = FALSE;
1885 clear_var(&var2);
1886 }
1887 if (evaluate)
1888 {
1889 retvar->var_type = VAR_NUMBER;
1890 retvar->var_val.var_number = result;
1891 }
1892 }
1893
1894 return OK;
1895}
1896
1897/*
1898 * Handle third level expression:
1899 * var1 == var2
1900 * var1 =~ var2
1901 * var1 != var2
1902 * var1 !~ var2
1903 * var1 > var2
1904 * var1 >= var2
1905 * var1 < var2
1906 * var1 <= var2
1907 *
1908 * "arg" must point to the first non-white of the expression.
1909 * "arg" is advanced to the next non-white after the recognized expression.
1910 *
1911 * Return OK or FAIL.
1912 */
1913 static int
1914eval4(arg, retvar, evaluate)
1915 char_u **arg;
1916 VAR retvar;
1917 int evaluate;
1918{
1919 var var2;
1920 char_u *p;
1921 int i;
1922 exptype_T type = TYPE_UNKNOWN;
1923 int len = 2;
1924 long n1, n2;
1925 char_u *s1, *s2;
1926 char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
1927 regmatch_T regmatch;
1928 int ic;
1929 char_u *save_cpo;
1930
1931 /*
1932 * Get the first variable.
1933 */
1934 if (eval5(arg, retvar, evaluate) == FAIL)
1935 return FAIL;
1936
1937 p = *arg;
1938 switch (p[0])
1939 {
1940 case '=': if (p[1] == '=')
1941 type = TYPE_EQUAL;
1942 else if (p[1] == '~')
1943 type = TYPE_MATCH;
1944 break;
1945 case '!': if (p[1] == '=')
1946 type = TYPE_NEQUAL;
1947 else if (p[1] == '~')
1948 type = TYPE_NOMATCH;
1949 break;
1950 case '>': if (p[1] != '=')
1951 {
1952 type = TYPE_GREATER;
1953 len = 1;
1954 }
1955 else
1956 type = TYPE_GEQUAL;
1957 break;
1958 case '<': if (p[1] != '=')
1959 {
1960 type = TYPE_SMALLER;
1961 len = 1;
1962 }
1963 else
1964 type = TYPE_SEQUAL;
1965 break;
1966 }
1967
1968 /*
1969 * If there is a comparitive operator, use it.
1970 */
1971 if (type != TYPE_UNKNOWN)
1972 {
1973 /* extra question mark appended: ignore case */
1974 if (p[len] == '?')
1975 {
1976 ic = TRUE;
1977 ++len;
1978 }
1979 /* extra '#' appended: match case */
1980 else if (p[len] == '#')
1981 {
1982 ic = FALSE;
1983 ++len;
1984 }
1985 /* nothing appened: use 'ignorecase' */
1986 else
1987 ic = p_ic;
1988
1989 /*
1990 * Get the second variable.
1991 */
1992 *arg = skipwhite(p + len);
1993 if (eval5(arg, &var2, evaluate) == FAIL)
1994 {
1995 clear_var(retvar);
1996 return FAIL;
1997 }
1998
1999 if (evaluate)
2000 {
2001 /*
2002 * If one of the two variables is a number, compare as a number.
2003 * When using "=~" or "!~", always compare as string.
2004 */
2005 if ((retvar->var_type == VAR_NUMBER || var2.var_type == VAR_NUMBER)
2006 && type != TYPE_MATCH && type != TYPE_NOMATCH)
2007 {
2008 n1 = get_var_number(retvar);
2009 n2 = get_var_number(&var2);
2010 switch (type)
2011 {
2012 case TYPE_EQUAL: n1 = (n1 == n2); break;
2013 case TYPE_NEQUAL: n1 = (n1 != n2); break;
2014 case TYPE_GREATER: n1 = (n1 > n2); break;
2015 case TYPE_GEQUAL: n1 = (n1 >= n2); break;
2016 case TYPE_SMALLER: n1 = (n1 < n2); break;
2017 case TYPE_SEQUAL: n1 = (n1 <= n2); break;
2018 case TYPE_UNKNOWN:
2019 case TYPE_MATCH:
2020 case TYPE_NOMATCH: break; /* avoid gcc warning */
2021 }
2022 }
2023 else
2024 {
2025 s1 = get_var_string_buf(retvar, buf1);
2026 s2 = get_var_string_buf(&var2, buf2);
2027 if (type != TYPE_MATCH && type != TYPE_NOMATCH)
2028 i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
2029 else
2030 i = 0;
2031 n1 = FALSE;
2032 switch (type)
2033 {
2034 case TYPE_EQUAL: n1 = (i == 0); break;
2035 case TYPE_NEQUAL: n1 = (i != 0); break;
2036 case TYPE_GREATER: n1 = (i > 0); break;
2037 case TYPE_GEQUAL: n1 = (i >= 0); break;
2038 case TYPE_SMALLER: n1 = (i < 0); break;
2039 case TYPE_SEQUAL: n1 = (i <= 0); break;
2040
2041 case TYPE_MATCH:
2042 case TYPE_NOMATCH:
2043 /* avoid 'l' flag in 'cpoptions' */
2044 save_cpo = p_cpo;
2045 p_cpo = (char_u *)"";
2046 regmatch.regprog = vim_regcomp(s2,
2047 RE_MAGIC + RE_STRING);
2048 regmatch.rm_ic = ic;
2049 if (regmatch.regprog != NULL)
2050 {
2051 n1 = vim_regexec_nl(&regmatch, s1, (colnr_T)0);
2052 vim_free(regmatch.regprog);
2053 if (type == TYPE_NOMATCH)
2054 n1 = !n1;
2055 }
2056 p_cpo = save_cpo;
2057 break;
2058
2059 case TYPE_UNKNOWN: break; /* avoid gcc warning */
2060 }
2061 }
2062 clear_var(retvar);
2063 clear_var(&var2);
2064 retvar->var_type = VAR_NUMBER;
2065 retvar->var_val.var_number = n1;
2066 }
2067 }
2068
2069 return OK;
2070}
2071
2072/*
2073 * Handle fourth level expression:
2074 * + number addition
2075 * - number subtraction
2076 * . string concatenation
2077 *
2078 * "arg" must point to the first non-white of the expression.
2079 * "arg" is advanced to the next non-white after the recognized expression.
2080 *
2081 * Return OK or FAIL.
2082 */
2083 static int
2084eval5(arg, retvar, evaluate)
2085 char_u **arg;
2086 VAR retvar;
2087 int evaluate;
2088{
2089 var var2;
2090 int op;
2091 long n1, n2;
2092 char_u *s1, *s2;
2093 char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
2094 char_u *p;
2095
2096 /*
2097 * Get the first variable.
2098 */
2099 if (eval6(arg, retvar, evaluate) == FAIL)
2100 return FAIL;
2101
2102 /*
2103 * Repeat computing, until no '+', '-' or '.' is following.
2104 */
2105 for (;;)
2106 {
2107 op = **arg;
2108 if (op != '+' && op != '-' && op != '.')
2109 break;
2110
2111 /*
2112 * Get the second variable.
2113 */
2114 *arg = skipwhite(*arg + 1);
2115 if (eval6(arg, &var2, evaluate) == FAIL)
2116 {
2117 clear_var(retvar);
2118 return FAIL;
2119 }
2120
2121 if (evaluate)
2122 {
2123 /*
2124 * Compute the result.
2125 */
2126 if (op == '.')
2127 {
2128 s1 = get_var_string_buf(retvar, buf1);
2129 s2 = get_var_string_buf(&var2, buf2);
2130 op = (int)STRLEN(s1);
2131 p = alloc((unsigned)(op + STRLEN(s2) + 1));
2132 if (p != NULL)
2133 {
2134 STRCPY(p, s1);
2135 STRCPY(p + op, s2);
2136 }
2137 clear_var(retvar);
2138 retvar->var_type = VAR_STRING;
2139 retvar->var_val.var_string = p;
2140 }
2141 else
2142 {
2143 n1 = get_var_number(retvar);
2144 n2 = get_var_number(&var2);
2145 clear_var(retvar);
2146 if (op == '+')
2147 n1 = n1 + n2;
2148 else
2149 n1 = n1 - n2;
2150 retvar->var_type = VAR_NUMBER;
2151 retvar->var_val.var_number = n1;
2152 }
2153 clear_var(&var2);
2154 }
2155 }
2156 return OK;
2157}
2158
2159/*
2160 * Handle fifth level expression:
2161 * * number multiplication
2162 * / number division
2163 * % number modulo
2164 *
2165 * "arg" must point to the first non-white of the expression.
2166 * "arg" is advanced to the next non-white after the recognized expression.
2167 *
2168 * Return OK or FAIL.
2169 */
2170 static int
2171eval6(arg, retvar, evaluate)
2172 char_u **arg;
2173 VAR retvar;
2174 int evaluate;
2175{
2176 var var2;
2177 int op;
2178 long n1, n2;
2179
2180 /*
2181 * Get the first variable.
2182 */
2183 if (eval7(arg, retvar, evaluate) == FAIL)
2184 return FAIL;
2185
2186 /*
2187 * Repeat computing, until no '*', '/' or '%' is following.
2188 */
2189 for (;;)
2190 {
2191 op = **arg;
2192 if (op != '*' && op != '/' && op != '%')
2193 break;
2194
2195 if (evaluate)
2196 {
2197 n1 = get_var_number(retvar);
2198 clear_var(retvar);
2199 }
2200 else
2201 n1 = 0;
2202
2203 /*
2204 * Get the second variable.
2205 */
2206 *arg = skipwhite(*arg + 1);
2207 if (eval7(arg, &var2, evaluate) == FAIL)
2208 return FAIL;
2209
2210 if (evaluate)
2211 {
2212 n2 = get_var_number(&var2);
2213 clear_var(&var2);
2214
2215 /*
2216 * Compute the result.
2217 */
2218 if (op == '*')
2219 n1 = n1 * n2;
2220 else if (op == '/')
2221 {
2222 if (n2 == 0) /* give an error message? */
2223 n1 = 0x7fffffffL;
2224 else
2225 n1 = n1 / n2;
2226 }
2227 else
2228 {
2229 if (n2 == 0) /* give an error message? */
2230 n1 = 0;
2231 else
2232 n1 = n1 % n2;
2233 }
2234 retvar->var_type = VAR_NUMBER;
2235 retvar->var_val.var_number = n1;
2236 }
2237 }
2238
2239 return OK;
2240}
2241
2242/*
2243 * Handle sixth level expression:
2244 * number number constant
2245 * "string" string contstant
2246 * 'string' literal string contstant
2247 * &option-name option value
2248 * @r register contents
2249 * identifier variable value
2250 * function() function call
2251 * $VAR environment variable
2252 * (expression) nested expression
2253 *
2254 * Also handle:
2255 * ! in front logical NOT
2256 * - in front unary minus
2257 * + in front unary plus (ignored)
2258 * trailing [] subscript in String
2259 *
2260 * "arg" must point to the first non-white of the expression.
2261 * "arg" is advanced to the next non-white after the recognized expression.
2262 *
2263 * Return OK or FAIL.
2264 */
2265 static int
2266eval7(arg, retvar, evaluate)
2267 char_u **arg;
2268 VAR retvar;
2269 int evaluate;
2270{
2271 var var2;
2272 long n;
2273 int len;
2274 char_u *s;
2275 int val;
2276 char_u *start_leader, *end_leader;
2277 int ret = OK;
2278 char_u *alias;
2279
2280 /*
2281 * Initialise variable so that clear_var() can't mistake this for a string
2282 * and free a string that isn't there.
2283 */
2284 retvar->var_type = VAR_UNKNOWN;
2285
2286 /*
2287 * Skip '!' and '-' characters. They are handled later.
2288 */
2289 start_leader = *arg;
2290 while (**arg == '!' || **arg == '-' || **arg == '+')
2291 *arg = skipwhite(*arg + 1);
2292 end_leader = *arg;
2293
2294 switch (**arg)
2295 {
2296 /*
2297 * Number constant.
2298 */
2299 case '0':
2300 case '1':
2301 case '2':
2302 case '3':
2303 case '4':
2304 case '5':
2305 case '6':
2306 case '7':
2307 case '8':
2308 case '9':
2309 vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL);
2310 *arg += len;
2311 if (evaluate)
2312 {
2313 retvar->var_type = VAR_NUMBER;
2314 retvar->var_val.var_number = n;
2315 }
2316 break;
2317
2318 /*
2319 * String constant: "string".
2320 */
2321 case '"': ret = get_string_var(arg, retvar, evaluate);
2322 break;
2323
2324 /*
2325 * Literal string constant: 'string'.
2326 */
2327 case '\'': ret = get_lit_string_var(arg, retvar, evaluate);
2328 break;
2329
2330 /*
2331 * Option value: &name
2332 */
2333 case '&': ret = get_option_var(arg, retvar, evaluate);
2334 break;
2335
2336 /*
2337 * Environment variable: $VAR.
2338 */
2339 case '$': ret = get_env_var(arg, retvar, evaluate);
2340 break;
2341
2342 /*
2343 * Register contents: @r.
2344 */
2345 case '@': ++*arg;
2346 if (evaluate)
2347 {
2348 retvar->var_type = VAR_STRING;
2349 retvar->var_val.var_string = get_reg_contents(**arg, FALSE);
2350 }
2351 if (**arg != NUL)
2352 ++*arg;
2353 break;
2354
2355 /*
2356 * nested expression: (expression).
2357 */
2358 case '(': *arg = skipwhite(*arg + 1);
2359 ret = eval1(arg, retvar, evaluate); /* recursive! */
2360 if (**arg == ')')
2361 ++*arg;
2362 else if (ret == OK)
2363 {
2364 EMSG(_("E110: Missing ')'"));
2365 clear_var(retvar);
2366 ret = FAIL;
2367 }
2368 break;
2369
2370 /*
2371 * Must be a variable or function name then.
2372 */
2373 default: s = *arg;
2374 len = get_func_len(arg, &alias, evaluate);
2375 if (alias != NULL)
2376 s = alias;
2377
2378 if (len == 0)
2379 ret = FAIL;
2380 else
2381 {
2382 if (**arg == '(') /* recursive! */
2383 {
2384 ret = get_func_var(s, len, retvar, arg,
2385 curwin->w_cursor.lnum, curwin->w_cursor.lnum,
2386 &len, evaluate);
2387 /* Stop the expression evaluation when immediately
2388 * aborting on error, or when an interrupt occurred or
2389 * an exception was thrown but not caught. */
2390 if (aborting())
2391 {
2392 if (ret == OK)
2393 clear_var(retvar);
2394 ret = FAIL;
2395 }
2396 }
2397 else if (evaluate)
2398 ret = get_var_var(s, len, retvar);
2399 }
2400
2401 if (alias != NULL)
2402 vim_free(alias);
2403
2404 break;
2405 }
2406 *arg = skipwhite(*arg);
2407
2408 /*
2409 * Handle expr[expr] subscript.
2410 */
2411 if (**arg == '[' && ret == OK)
2412 {
2413 /*
2414 * Get the variable from inside the [].
2415 */
2416 *arg = skipwhite(*arg + 1);
2417 if (eval1(arg, &var2, evaluate) == FAIL) /* recursive! */
2418 {
2419 clear_var(retvar);
2420 return FAIL;
2421 }
2422
2423 /* Check for the ']'. */
2424 if (**arg != ']')
2425 {
2426 EMSG(_("E111: Missing ']'"));
2427 clear_var(retvar);
2428 clear_var(&var2);
2429 return FAIL;
2430 }
2431
2432 if (evaluate)
2433 {
2434 n = get_var_number(&var2);
2435 clear_var(&var2);
2436
2437 /*
2438 * The resulting variable is a string of a single character.
2439 * If the index is too big or negative, the result is empty.
2440 */
2441 s = get_var_string(retvar);
2442 if (n >= (long)STRLEN(s) || n < 0)
2443 s = NULL;
2444 else
2445 s = vim_strnsave(s + n, 1);
2446 clear_var(retvar);
2447 retvar->var_type = VAR_STRING;
2448 retvar->var_val.var_string = s;
2449 }
2450 *arg = skipwhite(*arg + 1); /* skip the ']' */
2451 }
2452
2453 /*
2454 * Apply logical NOT and unary '-', from right to left, ignore '+'.
2455 */
2456 if (ret == OK && evaluate && end_leader > start_leader)
2457 {
2458 val = get_var_number(retvar);
2459 while (end_leader > start_leader)
2460 {
2461 --end_leader;
2462 if (*end_leader == '!')
2463 val = !val;
2464 else if (*end_leader == '-')
2465 val = -val;
2466 }
2467 clear_var(retvar);
2468 retvar->var_type = VAR_NUMBER;
2469 retvar->var_val.var_number = val;
2470 }
2471
2472 return ret;
2473}
2474
2475/*
2476 * Get an option value.
2477 * "arg" points to the '&' or '+' before the option name.
2478 * "arg" is advanced to character after the option name.
2479 * Return OK or FAIL.
2480 */
2481 static int
2482get_option_var(arg, retvar, evaluate)
2483 char_u **arg;
2484 VAR retvar; /* when NULL, only check if option exists */
2485 int evaluate;
2486{
2487 char_u *option_end;
2488 long numval;
2489 char_u *stringval;
2490 int opt_type;
2491 int c;
2492 int working = (**arg == '+'); /* has("+option") */
2493 int ret = OK;
2494 int opt_flags;
2495
2496 /*
2497 * Isolate the option name and find its value.
2498 */
2499 option_end = find_option_end(arg, &opt_flags);
2500 if (option_end == NULL)
2501 {
2502 if (retvar != NULL)
2503 EMSG2(_("E112: Option name missing: %s"), *arg);
2504 return FAIL;
2505 }
2506
2507 if (!evaluate)
2508 {
2509 *arg = option_end;
2510 return OK;
2511 }
2512
2513 c = *option_end;
2514 *option_end = NUL;
2515 opt_type = get_option_value(*arg, &numval,
2516 retvar == NULL ? NULL : &stringval, opt_flags);
2517
2518 if (opt_type == -3) /* invalid name */
2519 {
2520 if (retvar != NULL)
2521 EMSG2(_("E113: Unknown option: %s"), *arg);
2522 ret = FAIL;
2523 }
2524 else if (retvar != NULL)
2525 {
2526 if (opt_type == -2) /* hidden string option */
2527 {
2528 retvar->var_type = VAR_STRING;
2529 retvar->var_val.var_string = NULL;
2530 }
2531 else if (opt_type == -1) /* hidden number option */
2532 {
2533 retvar->var_type = VAR_NUMBER;
2534 retvar->var_val.var_number = 0;
2535 }
2536 else if (opt_type == 1) /* number option */
2537 {
2538 retvar->var_type = VAR_NUMBER;
2539 retvar->var_val.var_number = numval;
2540 }
2541 else /* string option */
2542 {
2543 retvar->var_type = VAR_STRING;
2544 retvar->var_val.var_string = stringval;
2545 }
2546 }
2547 else if (working && (opt_type == -2 || opt_type == -1))
2548 ret = FAIL;
2549
2550 *option_end = c; /* put back for error messages */
2551 *arg = option_end;
2552
2553 return ret;
2554}
2555
2556/*
2557 * Allocate a variable for a string constant.
2558 * Return OK or FAIL.
2559 */
2560 static int
2561get_string_var(arg, retvar, evaluate)
2562 char_u **arg;
2563 VAR retvar;
2564 int evaluate;
2565{
2566 char_u *p;
2567 char_u *name;
2568 int i;
2569 int extra = 0;
2570
2571 /*
2572 * Find the end of the string, skipping backslashed characters.
2573 */
2574 for (p = *arg + 1; *p && *p != '"'; ++p)
2575 {
2576 if (*p == '\\' && p[1] != NUL)
2577 {
2578 ++p;
2579 /* A "\<x>" form occupies at least 4 characters, and produces up
2580 * to 6 characters: reserve space for 2 extra */
2581 if (*p == '<')
2582 extra += 2;
2583 }
2584#ifdef FEAT_MBYTE
2585 if (has_mbyte)
2586 p += (*mb_ptr2len_check)(p) - 1;
2587#endif
2588 }
2589
2590 if (*p != '"')
2591 {
2592 EMSG2(_("E114: Missing quote: %s"), *arg);
2593 return FAIL;
2594 }
2595
2596 /* If only parsing, set *arg and return here */
2597 if (!evaluate)
2598 {
2599 *arg = p + 1;
2600 return OK;
2601 }
2602
2603 /*
2604 * Copy the string into allocated memory, handling backslashed
2605 * characters.
2606 */
2607 name = alloc((unsigned)(p - *arg + extra));
2608 if (name == NULL)
2609 return FAIL;
2610
2611 i = 0;
2612 for (p = *arg + 1; *p && *p != '"'; ++p)
2613 {
2614 if (*p == '\\')
2615 {
2616 switch (*++p)
2617 {
2618 case 'b': name[i++] = BS; break;
2619 case 'e': name[i++] = ESC; break;
2620 case 'f': name[i++] = FF; break;
2621 case 'n': name[i++] = NL; break;
2622 case 'r': name[i++] = CAR; break;
2623 case 't': name[i++] = TAB; break;
2624
2625 case 'X': /* hex: "\x1", "\x12" */
2626 case 'x':
2627 case 'u': /* Unicode: "\u0023" */
2628 case 'U':
2629 if (vim_isxdigit(p[1]))
2630 {
2631 int n, nr;
2632 int c = toupper(*p);
2633
2634 if (c == 'X')
2635 n = 2;
2636 else
2637 n = 4;
2638 nr = 0;
2639 while (--n >= 0 && vim_isxdigit(p[1]))
2640 {
2641 ++p;
2642 nr = (nr << 4) + hex2nr(*p);
2643 }
2644#ifdef FEAT_MBYTE
2645 /* For "\u" store the number according to
2646 * 'encoding'. */
2647 if (c != 'X')
2648 i += (*mb_char2bytes)(nr, name + i);
2649 else
2650#endif
2651 name[i++] = nr;
2652 }
2653 else
2654 name[i++] = *p;
2655 break;
2656
2657 /* octal: "\1", "\12", "\123" */
2658 case '0':
2659 case '1':
2660 case '2':
2661 case '3':
2662 case '4':
2663 case '5':
2664 case '6':
2665 case '7': name[i] = *p - '0';
2666 if (p[1] >= '0' && p[1] <= '7')
2667 {
2668 ++p;
2669 name[i] = (name[i] << 3) + *p - '0';
2670 if (p[1] >= '0' && p[1] <= '7')
2671 {
2672 ++p;
2673 name[i] = (name[i] << 3) + *p - '0';
2674 }
2675 }
2676 ++i;
2677 break;
2678
2679 /* Special key, e.g.: "\<C-W>" */
2680 case '<': extra = trans_special(&p, name + i, TRUE);
2681 if (extra != 0)
2682 {
2683 i += extra;
2684 --p;
2685 break;
2686 }
2687 /* FALLTHROUGH */
2688
2689 default: name[i++] = *p;
2690 break;
2691 }
2692 }
2693 else
2694 name[i++] = *p;
2695
2696#ifdef FEAT_MBYTE
2697 /* For a multi-byte character copy the bytes after the first one. */
2698 if (has_mbyte)
2699 {
2700 int l = (*mb_ptr2len_check)(p);
2701
2702 while (--l > 0)
2703 name[i++] = *++p;
2704 }
2705#endif
2706 }
2707 name[i] = NUL;
2708 *arg = p + 1;
2709
2710 retvar->var_type = VAR_STRING;
2711 retvar->var_val.var_string = name;
2712
2713 return OK;
2714}
2715
2716/*
2717 * Allocate a variable for an backtick-string constant.
2718 * Return OK or FAIL.
2719 */
2720 static int
2721get_lit_string_var(arg, retvar, evaluate)
2722 char_u **arg;
2723 VAR retvar;
2724 int evaluate;
2725{
2726 char_u *p;
2727 char_u *name;
2728
2729 /*
2730 * Find the end of the string.
2731 */
2732 p = vim_strchr(*arg + 1, '\'');
2733 if (p == NULL)
2734 {
2735 EMSG2(_("E115: Missing quote: %s"), *arg);
2736 return FAIL;
2737 }
2738
2739 if (evaluate)
2740 {
2741 /*
2742 * Copy the string into allocated memory.
2743 */
2744 name = vim_strnsave(*arg + 1, (int)(p - (*arg + 1)));
2745 if (name == NULL)
2746 return FAIL;
2747
2748 retvar->var_type = VAR_STRING;
2749 retvar->var_val.var_string = name;
2750 }
2751
2752 *arg = p + 1;
2753
2754 return OK;
2755}
2756
2757/*
2758 * Get the value of an environment variable.
2759 * "arg" is pointing to the '$'. It is advanced to after the name.
2760 * If the environment variable was not set, silently assume it is empty.
2761 * Always return OK.
2762 */
2763 static int
2764get_env_var(arg, retvar, evaluate)
2765 char_u **arg;
2766 VAR retvar;
2767 int evaluate;
2768{
2769 char_u *string = NULL;
2770 int len;
2771 int cc;
2772 char_u *name;
2773
2774 ++*arg;
2775 name = *arg;
2776 len = get_env_len(arg);
2777 if (evaluate)
2778 {
2779 if (len != 0)
2780 {
2781 cc = name[len];
2782 name[len] = NUL;
2783 /* first try mch_getenv(), fast for normal environment vars */
2784 string = mch_getenv(name);
2785 if (string != NULL && *string != NUL)
2786 string = vim_strsave(string);
2787 else
2788 {
2789 /* next try expanding things like $VIM and ${HOME} */
2790 string = expand_env_save(name - 1);
2791 if (string != NULL && *string == '$')
2792 {
2793 vim_free(string);
2794 string = NULL;
2795 }
2796 }
2797 name[len] = cc;
2798 }
2799 retvar->var_type = VAR_STRING;
2800 retvar->var_val.var_string = string;
2801 }
2802
2803 return OK;
2804}
2805
2806/*
2807 * Array with names and number of arguments of all internal functions
2808 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
2809 */
2810static struct fst
2811{
2812 char *f_name; /* function name */
2813 char f_min_argc; /* minimal number of arguments */
2814 char f_max_argc; /* maximal number of arguments */
2815 void (*f_func) __ARGS((VAR args, VAR rvar)); /* impl. function */
2816} functions[] =
2817{
2818 {"append", 2, 2, f_append},
2819 {"argc", 0, 0, f_argc},
2820 {"argidx", 0, 0, f_argidx},
2821 {"argv", 1, 1, f_argv},
2822 {"browse", 4, 4, f_browse},
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002823 {"browsedir", 2, 2, f_browsedir},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 {"bufexists", 1, 1, f_bufexists},
2825 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
2826 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
2827 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
2828 {"buflisted", 1, 1, f_buflisted},
2829 {"bufloaded", 1, 1, f_bufloaded},
2830 {"bufname", 1, 1, f_bufname},
2831 {"bufnr", 1, 1, f_bufnr},
2832 {"bufwinnr", 1, 1, f_bufwinnr},
2833 {"byte2line", 1, 1, f_byte2line},
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00002834 {"byteidx", 2, 2, f_byteidx},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 {"char2nr", 1, 1, f_char2nr},
2836 {"cindent", 1, 1, f_cindent},
2837 {"col", 1, 1, f_col},
2838 {"confirm", 1, 4, f_confirm},
2839 {"cscope_connection",0,3, f_cscope_connection},
2840 {"cursor", 2, 2, f_cursor},
2841 {"delete", 1, 1, f_delete},
2842 {"did_filetype", 0, 0, f_did_filetype},
Bram Moolenaar47136d72004-10-12 20:02:24 +00002843 {"diff_filler", 1, 1, f_diff_filler},
2844 {"diff_hlID", 2, 2, f_diff_hlID},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 {"escape", 2, 2, f_escape},
2846 {"eventhandler", 0, 0, f_eventhandler},
2847 {"executable", 1, 1, f_executable},
2848 {"exists", 1, 1, f_exists},
2849 {"expand", 1, 2, f_expand},
2850 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
2851 {"filereadable", 1, 1, f_filereadable},
2852 {"filewritable", 1, 1, f_filewritable},
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00002853 {"finddir", 1, 3, f_finddir},
2854 {"findfile", 1, 3, f_findfile},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855 {"fnamemodify", 2, 2, f_fnamemodify},
2856 {"foldclosed", 1, 1, f_foldclosed},
2857 {"foldclosedend", 1, 1, f_foldclosedend},
2858 {"foldlevel", 1, 1, f_foldlevel},
2859 {"foldtext", 0, 0, f_foldtext},
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002860 {"foldtextresult", 1, 1, f_foldtextresult},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 {"foreground", 0, 0, f_foreground},
2862 {"getbufvar", 2, 2, f_getbufvar},
2863 {"getchar", 0, 1, f_getchar},
2864 {"getcharmod", 0, 0, f_getcharmod},
2865 {"getcmdline", 0, 0, f_getcmdline},
2866 {"getcmdpos", 0, 0, f_getcmdpos},
2867 {"getcwd", 0, 0, f_getcwd},
Bram Moolenaar46c9c732004-12-12 11:37:09 +00002868 {"getfontname", 0, 1, f_getfontname},
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00002869 {"getfperm", 1, 1, f_getfperm},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870 {"getfsize", 1, 1, f_getfsize},
2871 {"getftime", 1, 1, f_getftime},
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00002872 {"getftype", 1, 1, f_getftype},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002873 {"getline", 1, 1, f_getline},
2874 {"getreg", 0, 1, f_getreg},
2875 {"getregtype", 0, 1, f_getregtype},
2876 {"getwinposx", 0, 0, f_getwinposx},
2877 {"getwinposy", 0, 0, f_getwinposy},
2878 {"getwinvar", 2, 2, f_getwinvar},
2879 {"glob", 1, 1, f_glob},
2880 {"globpath", 2, 2, f_globpath},
2881 {"has", 1, 1, f_has},
2882 {"hasmapto", 1, 2, f_hasmapto},
2883 {"highlightID", 1, 1, f_hlID}, /* obsolete */
2884 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
2885 {"histadd", 2, 2, f_histadd},
2886 {"histdel", 1, 2, f_histdel},
2887 {"histget", 1, 2, f_histget},
2888 {"histnr", 1, 1, f_histnr},
2889 {"hlID", 1, 1, f_hlID},
2890 {"hlexists", 1, 1, f_hlexists},
2891 {"hostname", 0, 0, f_hostname},
2892 {"iconv", 3, 3, f_iconv},
2893 {"indent", 1, 1, f_indent},
2894 {"input", 1, 2, f_input},
2895 {"inputdialog", 1, 3, f_inputdialog},
2896 {"inputrestore", 0, 0, f_inputrestore},
2897 {"inputsave", 0, 0, f_inputsave},
2898 {"inputsecret", 1, 2, f_inputsecret},
2899 {"isdirectory", 1, 1, f_isdirectory},
2900 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
2901 {"libcall", 3, 3, f_libcall},
2902 {"libcallnr", 3, 3, f_libcallnr},
2903 {"line", 1, 1, f_line},
2904 {"line2byte", 1, 1, f_line2byte},
2905 {"lispindent", 1, 1, f_lispindent},
2906 {"localtime", 0, 0, f_localtime},
2907 {"maparg", 1, 2, f_maparg},
2908 {"mapcheck", 1, 2, f_mapcheck},
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00002909 {"match", 2, 4, f_match},
2910 {"matchend", 2, 4, f_matchend},
2911 {"matchstr", 2, 4, f_matchstr},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 {"mode", 0, 0, f_mode},
2913 {"nextnonblank", 1, 1, f_nextnonblank},
2914 {"nr2char", 1, 1, f_nr2char},
2915 {"prevnonblank", 1, 1, f_prevnonblank},
2916 {"remote_expr", 2, 3, f_remote_expr},
2917 {"remote_foreground", 1, 1, f_remote_foreground},
2918 {"remote_peek", 1, 2, f_remote_peek},
2919 {"remote_read", 1, 1, f_remote_read},
2920 {"remote_send", 2, 3, f_remote_send},
2921 {"rename", 2, 2, f_rename},
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00002922 {"repeat", 2, 2, f_repeat},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002923 {"resolve", 1, 1, f_resolve},
2924 {"search", 1, 2, f_search},
2925 {"searchpair", 3, 5, f_searchpair},
2926 {"server2client", 2, 2, f_server2client},
2927 {"serverlist", 0, 0, f_serverlist},
2928 {"setbufvar", 3, 3, f_setbufvar},
2929 {"setcmdpos", 1, 1, f_setcmdpos},
2930 {"setline", 2, 2, f_setline},
2931 {"setreg", 2, 3, f_setreg},
2932 {"setwinvar", 3, 3, f_setwinvar},
2933 {"simplify", 1, 1, f_simplify},
2934#ifdef HAVE_STRFTIME
2935 {"strftime", 1, 2, f_strftime},
2936#endif
2937 {"stridx", 2, 2, f_stridx},
2938 {"strlen", 1, 1, f_strlen},
2939 {"strpart", 2, 3, f_strpart},
2940 {"strridx", 2, 2, f_strridx},
2941 {"strtrans", 1, 1, f_strtrans},
2942 {"submatch", 1, 1, f_submatch},
2943 {"substitute", 4, 4, f_substitute},
2944 {"synID", 3, 3, f_synID},
2945 {"synIDattr", 2, 3, f_synIDattr},
2946 {"synIDtrans", 1, 1, f_synIDtrans},
Bram Moolenaarc0197e22004-09-13 20:26:32 +00002947 {"system", 1, 2, f_system},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948 {"tempname", 0, 0, f_tempname},
2949 {"tolower", 1, 1, f_tolower},
2950 {"toupper", 1, 1, f_toupper},
Bram Moolenaar8299df92004-07-10 09:47:34 +00002951 {"tr", 3, 3, f_tr},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952 {"type", 1, 1, f_type},
2953 {"virtcol", 1, 1, f_virtcol},
2954 {"visualmode", 0, 1, f_visualmode},
2955 {"winbufnr", 1, 1, f_winbufnr},
2956 {"wincol", 0, 0, f_wincol},
2957 {"winheight", 1, 1, f_winheight},
2958 {"winline", 0, 0, f_winline},
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00002959 {"winnr", 0, 1, f_winnr},
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960 {"winrestcmd", 0, 0, f_winrestcmd},
2961 {"winwidth", 1, 1, f_winwidth},
2962};
2963
2964#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2965
2966/*
2967 * Function given to ExpandGeneric() to obtain the list of internal
2968 * or user defined function names.
2969 */
2970 char_u *
2971get_function_name(xp, idx)
2972 expand_T *xp;
2973 int idx;
2974{
2975 static int intidx = -1;
2976 char_u *name;
2977
2978 if (idx == 0)
2979 intidx = -1;
2980 if (intidx < 0)
2981 {
2982 name = get_user_func_name(xp, idx);
2983 if (name != NULL)
2984 return name;
2985 }
2986 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
2987 {
2988 STRCPY(IObuff, functions[intidx].f_name);
2989 STRCAT(IObuff, "(");
2990 if (functions[intidx].f_max_argc == 0)
2991 STRCAT(IObuff, ")");
2992 return IObuff;
2993 }
2994
2995 return NULL;
2996}
2997
2998/*
2999 * Function given to ExpandGeneric() to obtain the list of internal or
3000 * user defined variable or function names.
3001 */
3002/*ARGSUSED*/
3003 char_u *
3004get_expr_name(xp, idx)
3005 expand_T *xp;
3006 int idx;
3007{
3008 static int intidx = -1;
3009 char_u *name;
3010
3011 if (idx == 0)
3012 intidx = -1;
3013 if (intidx < 0)
3014 {
3015 name = get_function_name(xp, idx);
3016 if (name != NULL)
3017 return name;
3018 }
3019 return get_user_var_name(xp, ++intidx);
3020}
3021
3022#endif /* FEAT_CMDL_COMPL */
3023
3024/*
3025 * Find internal function in table above.
3026 * Return index, or -1 if not found
3027 */
3028 static int
3029find_internal_func(name)
3030 char_u *name; /* name of the function */
3031{
3032 int first = 0;
3033 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
3034 int cmp;
3035 int x;
3036
3037 /*
3038 * Find the function name in the table. Binary search.
3039 */
3040 while (first <= last)
3041 {
3042 x = first + ((unsigned)(last - first) >> 1);
3043 cmp = STRCMP(name, functions[x].f_name);
3044 if (cmp < 0)
3045 last = x - 1;
3046 else if (cmp > 0)
3047 first = x + 1;
3048 else
3049 return x;
3050 }
3051 return -1;
3052}
3053
3054/*
3055 * Allocate a variable for the result of a function.
3056 * Return OK or FAIL.
3057 */
3058 static int
3059get_func_var(name, len, retvar, arg, firstline, lastline, doesrange, evaluate)
3060 char_u *name; /* name of the function */
3061 int len; /* length of "name" */
3062 VAR retvar;
3063 char_u **arg; /* argument, pointing to the '(' */
3064 linenr_T firstline; /* first line of range */
3065 linenr_T lastline; /* last line of range */
3066 int *doesrange; /* return: function handled range */
3067 int evaluate;
3068{
3069 char_u *argp;
3070 int ret = OK;
3071#define MAX_FUNC_ARGS 20
3072 var argvars[MAX_FUNC_ARGS]; /* vars for arguments */
3073 int argcount = 0; /* number of arguments found */
3074
3075 /*
3076 * Get the arguments.
3077 */
3078 argp = *arg;
3079 while (argcount < MAX_FUNC_ARGS)
3080 {
3081 argp = skipwhite(argp + 1); /* skip the '(' or ',' */
3082 if (*argp == ')' || *argp == ',' || *argp == NUL)
3083 break;
3084 argvars[argcount].var_name = NULL; /* the name is not stored */
3085 if (eval1(&argp, &argvars[argcount], evaluate) == FAIL)
3086 {
3087 ret = FAIL;
3088 break;
3089 }
3090 ++argcount;
3091 if (*argp != ',')
3092 break;
3093 }
3094 if (*argp == ')')
3095 ++argp;
3096 else
3097 ret = FAIL;
3098
3099 if (ret == OK)
3100 ret = call_func(name, len, retvar, argcount, argvars,
3101 firstline, lastline, doesrange, evaluate);
3102 else if (!aborting())
3103 EMSG2(_("E116: Invalid arguments for function %s"), name);
3104
3105 while (--argcount >= 0)
3106 clear_var(&argvars[argcount]);
3107
3108 *arg = skipwhite(argp);
3109 return ret;
3110}
3111
3112
3113/*
3114 * Call a function with its resolved parameters
3115 * Return OK or FAIL.
3116 */
3117 static int
3118call_func(name, len, retvar, argcount, argvars, firstline, lastline,
3119 doesrange, evaluate)
3120 char_u *name; /* name of the function */
3121 int len; /* length of "name" */
3122 VAR retvar; /* return value goes here */
3123 int argcount; /* number of "argvars" */
3124 VAR argvars; /* vars for arguments */
3125 linenr_T firstline; /* first line of range */
3126 linenr_T lastline; /* last line of range */
3127 int *doesrange; /* return: function handled range */
3128 int evaluate;
3129{
3130 int ret = FAIL;
3131 static char *errors[] =
3132 {N_("E117: Unknown function: %s"),
3133 N_("E118: Too many arguments for function: %s"),
3134 N_("E119: Not enough arguments for function: %s"),
3135 N_("E120: Using <SID> not in a script context: %s"),
3136 };
3137#define ERROR_UNKNOWN 0
3138#define ERROR_TOOMANY 1
3139#define ERROR_TOOFEW 2
3140#define ERROR_SCRIPT 3
3141#define ERROR_NONE 4
3142#define ERROR_OTHER 5
3143 int error = ERROR_NONE;
3144 int i;
3145 int llen;
3146 ufunc_T *fp;
3147 int cc;
3148#define FLEN_FIXED 40
3149 char_u fname_buf[FLEN_FIXED + 1];
3150 char_u *fname;
3151
3152 /*
3153 * In a script change <SID>name() and s:name() to K_SNR 123_name().
3154 * Change <SNR>123_name() to K_SNR 123_name().
3155 * Use fname_buf[] when it fits, otherwise allocate memory (slow).
3156 */
3157 cc = name[len];
3158 name[len] = NUL;
3159 llen = eval_fname_script(name);
3160 if (llen > 0)
3161 {
3162 fname_buf[0] = K_SPECIAL;
3163 fname_buf[1] = KS_EXTRA;
3164 fname_buf[2] = (int)KE_SNR;
3165 i = 3;
3166 if (eval_fname_sid(name)) /* "<SID>" or "s:" */
3167 {
3168 if (current_SID <= 0)
3169 error = ERROR_SCRIPT;
3170 else
3171 {
3172 sprintf((char *)fname_buf + 3, "%ld_", (long)current_SID);
3173 i = (int)STRLEN(fname_buf);
3174 }
3175 }
3176 if (i + STRLEN(name + llen) < FLEN_FIXED)
3177 {
3178 STRCPY(fname_buf + i, name + llen);
3179 fname = fname_buf;
3180 }
3181 else
3182 {
3183 fname = alloc((unsigned)(i + STRLEN(name + llen) + 1));
3184 if (fname == NULL)
3185 error = ERROR_OTHER;
3186 else
3187 {
3188 mch_memmove(fname, fname_buf, (size_t)i);
3189 STRCPY(fname + i, name + llen);
3190 }
3191 }
3192 }
3193 else
3194 fname = name;
3195
3196 *doesrange = FALSE;
3197
3198
3199 /* execute the function if no errors detected and executing */
3200 if (evaluate && error == ERROR_NONE)
3201 {
3202 retvar->var_type = VAR_NUMBER; /* default is number retvar */
3203 error = ERROR_UNKNOWN;
3204
3205 if (!ASCII_ISLOWER(fname[0]))
3206 {
3207 /*
3208 * User defined function.
3209 */
3210 fp = find_func(fname);
3211#ifdef FEAT_AUTOCMD
3212 if (fp == NULL && apply_autocmds(EVENT_FUNCUNDEFINED,
3213 fname, fname, TRUE, NULL)
3214#ifdef FEAT_EVAL
3215 && !aborting()
3216#endif
3217 )
3218 {
3219 /* executed an autocommand, search for function again */
3220 fp = find_func(fname);
3221 }
3222#endif
3223 if (fp != NULL)
3224 {
3225 if (fp->flags & FC_RANGE)
3226 *doesrange = TRUE;
3227 if (argcount < fp->args.ga_len)
3228 error = ERROR_TOOFEW;
3229 else if (!fp->varargs && argcount > fp->args.ga_len)
3230 error = ERROR_TOOMANY;
3231 else
3232 {
3233 /*
3234 * Call the user function.
3235 * Save and restore search patterns, script variables and
3236 * redo buffer.
3237 */
3238 save_search_patterns();
3239 saveRedobuff();
3240 ++fp->calls;
3241 call_user_func(fp, argcount, argvars, retvar,
3242 firstline, lastline);
3243 --fp->calls;
3244 restoreRedobuff();
3245 restore_search_patterns();
3246 error = ERROR_NONE;
3247 }
3248 }
3249 }
3250 else
3251 {
3252 /*
3253 * Find the function name in the table, call its implementation.
3254 */
3255 i = find_internal_func(fname);
3256 if (i >= 0)
3257 {
3258 if (argcount < functions[i].f_min_argc)
3259 error = ERROR_TOOFEW;
3260 else if (argcount > functions[i].f_max_argc)
3261 error = ERROR_TOOMANY;
3262 else
3263 {
3264 argvars[argcount].var_type = VAR_UNKNOWN;
3265 functions[i].f_func(argvars, retvar);
3266 error = ERROR_NONE;
3267 }
3268 }
3269 }
3270 /*
3271 * The function call (or "FuncUndefined" autocommand sequence) might
3272 * have been aborted by an error, an interrupt, or an explicitly thrown
3273 * exception that has not been caught so far. This situation can be
3274 * tested for by calling aborting(). For an error in an internal
3275 * function or for the "E132" error in call_user_func(), however, the
3276 * throw point at which the "force_abort" flag (temporarily reset by
3277 * emsg()) is normally updated has not been reached yet. We need to
3278 * update that flag first to make aborting() reliable.
3279 */
3280 update_force_abort();
3281 }
3282 if (error == ERROR_NONE)
3283 ret = OK;
3284
3285 /*
3286 * Report an error unless the argument evaluation or function call has been
3287 * cancelled due to an aborting error, an interrupt, or an exception.
3288 */
3289 if (error < ERROR_NONE && !aborting())
3290 EMSG2((char_u *)_(errors[error]), name);
3291
3292 name[len] = cc;
3293 if (fname != name && fname != fname_buf)
3294 vim_free(fname);
3295
3296 return ret;
3297}
3298
3299/*********************************************
3300 * Implementation of the built-in functions
3301 */
3302
3303/*
3304 * "append(lnum, string)" function
3305 */
3306 static void
3307f_append(argvars, retvar)
3308 VAR argvars;
3309 VAR retvar;
3310{
3311 long lnum;
3312
3313 lnum = get_var_lnum(argvars);
3314 retvar->var_val.var_number = 1; /* Default: Failed */
3315
3316 if (lnum >= 0
3317 && lnum <= curbuf->b_ml.ml_line_count
3318 && u_save(lnum, lnum + 1) == OK)
3319 {
3320 ml_append(lnum, get_var_string(&argvars[1]), (colnr_T)0, FALSE);
3321 if (curwin->w_cursor.lnum > lnum)
3322 ++curwin->w_cursor.lnum;
3323 appended_lines_mark(lnum, 1L);
3324 retvar->var_val.var_number = 0;
3325 }
3326}
3327
3328/*
3329 * "argc()" function
3330 */
3331/* ARGSUSED */
3332 static void
3333f_argc(argvars, retvar)
3334 VAR argvars;
3335 VAR retvar;
3336{
3337 retvar->var_val.var_number = ARGCOUNT;
3338}
3339
3340/*
3341 * "argidx()" function
3342 */
3343/* ARGSUSED */
3344 static void
3345f_argidx(argvars, retvar)
3346 VAR argvars;
3347 VAR retvar;
3348{
3349 retvar->var_val.var_number = curwin->w_arg_idx;
3350}
3351
3352/*
3353 * "argv(nr)" function
3354 */
3355 static void
3356f_argv(argvars, retvar)
3357 VAR argvars;
3358 VAR retvar;
3359{
3360 int idx;
3361
3362 idx = get_var_number(&argvars[0]);
3363 if (idx >= 0 && idx < ARGCOUNT)
3364 retvar->var_val.var_string = vim_strsave(alist_name(&ARGLIST[idx]));
3365 else
3366 retvar->var_val.var_string = NULL;
3367 retvar->var_type = VAR_STRING;
3368}
3369
3370/*
3371 * "browse(save, title, initdir, default)" function
3372 */
3373/* ARGSUSED */
3374 static void
3375f_browse(argvars, retvar)
3376 VAR argvars;
3377 VAR retvar;
3378{
3379#ifdef FEAT_BROWSE
3380 int save;
3381 char_u *title;
3382 char_u *initdir;
3383 char_u *defname;
3384 char_u buf[NUMBUFLEN];
3385 char_u buf2[NUMBUFLEN];
3386
3387 save = get_var_number(&argvars[0]);
3388 title = get_var_string(&argvars[1]);
3389 initdir = get_var_string_buf(&argvars[2], buf);
3390 defname = get_var_string_buf(&argvars[3], buf2);
3391
3392 retvar->var_val.var_string =
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003393 do_browse(save ? BROWSE_SAVE : 0,
3394 title, defname, NULL, initdir, NULL, curbuf);
3395#else
3396 retvar->var_val.var_string = NULL;
3397#endif
3398 retvar->var_type = VAR_STRING;
3399}
3400
3401/*
3402 * "browsedir(title, initdir)" function
3403 */
3404/* ARGSUSED */
3405 static void
3406f_browsedir(argvars, retvar)
3407 VAR argvars;
3408 VAR retvar;
3409{
3410#ifdef FEAT_BROWSE
3411 char_u *title;
3412 char_u *initdir;
3413 char_u buf[NUMBUFLEN];
3414
3415 title = get_var_string(&argvars[0]);
3416 initdir = get_var_string_buf(&argvars[1], buf);
3417
3418 retvar->var_val.var_string = do_browse(BROWSE_DIR,
3419 title, NULL, NULL, initdir, NULL, curbuf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420#else
3421 retvar->var_val.var_string = NULL;
3422#endif
3423 retvar->var_type = VAR_STRING;
3424}
3425
3426/*
3427 * Find a buffer by number or exact name.
3428 */
3429 static buf_T *
3430find_buffer(avar)
3431 VAR avar;
3432{
3433 buf_T *buf = NULL;
3434 char_u *name;
3435
3436 if (avar->var_type == VAR_NUMBER)
3437 buf = buflist_findnr((int)avar->var_val.var_number);
3438 else if (avar->var_val.var_string != NULL)
3439 {
3440 /* First make the name into a full path name */
3441 name = FullName_save(avar->var_val.var_string,
3442#ifdef UNIX
3443 TRUE /* force expansion, get rid of symbolic links */
3444#else
3445 FALSE
3446#endif
3447 );
3448 if (name != NULL)
3449 {
3450 buf = buflist_findname(name);
3451 vim_free(name);
3452 }
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00003453 if (buf == NULL)
3454 {
3455 /* No full path name match, try a match with a URL or a "nofile"
3456 * buffer, these don't use the full path. */
3457 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
3458 if (buf->b_fname != NULL
3459 && (path_with_url(buf->b_fname)
3460#ifdef FEAT_QUICKFIX
3461 || bt_nofile(buf)
3462#endif
3463 )
3464 && STRCMP(buf->b_fname, avar->var_val.var_string) == 0)
3465 break;
3466 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 }
3468 return buf;
3469}
3470
3471/*
3472 * "bufexists(expr)" function
3473 */
3474 static void
3475f_bufexists(argvars, retvar)
3476 VAR argvars;
3477 VAR retvar;
3478{
3479 retvar->var_val.var_number = (find_buffer(&argvars[0]) != NULL);
3480}
3481
3482/*
3483 * "buflisted(expr)" function
3484 */
3485 static void
3486f_buflisted(argvars, retvar)
3487 VAR argvars;
3488 VAR retvar;
3489{
3490 buf_T *buf;
3491
3492 buf = find_buffer(&argvars[0]);
3493 retvar->var_val.var_number = (buf != NULL && buf->b_p_bl);
3494}
3495
3496/*
3497 * "bufloaded(expr)" function
3498 */
3499 static void
3500f_bufloaded(argvars, retvar)
3501 VAR argvars;
3502 VAR retvar;
3503{
3504 buf_T *buf;
3505
3506 buf = find_buffer(&argvars[0]);
3507 retvar->var_val.var_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
3508}
3509
3510/*
3511 * Get buffer by number or pattern.
3512 */
3513 static buf_T *
3514get_buf_var(avar)
3515 VAR avar;
3516{
3517 char_u *name = avar->var_val.var_string;
3518 int save_magic;
3519 char_u *save_cpo;
3520 buf_T *buf;
3521
3522 if (avar->var_type == VAR_NUMBER)
3523 return buflist_findnr((int)avar->var_val.var_number);
3524 if (name == NULL || *name == NUL)
3525 return curbuf;
3526 if (name[0] == '$' && name[1] == NUL)
3527 return lastbuf;
3528
3529 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
3530 save_magic = p_magic;
3531 p_magic = TRUE;
3532 save_cpo = p_cpo;
3533 p_cpo = (char_u *)"";
3534
3535 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
3536 TRUE, FALSE));
3537
3538 p_magic = save_magic;
3539 p_cpo = save_cpo;
3540
3541 /* If not found, try expanding the name, like done for bufexists(). */
3542 if (buf == NULL)
3543 buf = find_buffer(avar);
3544
3545 return buf;
3546}
3547
3548/*
3549 * "bufname(expr)" function
3550 */
3551 static void
3552f_bufname(argvars, retvar)
3553 VAR argvars;
3554 VAR retvar;
3555{
3556 buf_T *buf;
3557
3558 ++emsg_off;
3559 buf = get_buf_var(&argvars[0]);
3560 retvar->var_type = VAR_STRING;
3561 if (buf != NULL && buf->b_fname != NULL)
3562 retvar->var_val.var_string = vim_strsave(buf->b_fname);
3563 else
3564 retvar->var_val.var_string = NULL;
3565 --emsg_off;
3566}
3567
3568/*
3569 * "bufnr(expr)" function
3570 */
3571 static void
3572f_bufnr(argvars, retvar)
3573 VAR argvars;
3574 VAR retvar;
3575{
3576 buf_T *buf;
3577
3578 ++emsg_off;
3579 buf = get_buf_var(&argvars[0]);
3580 if (buf != NULL)
3581 retvar->var_val.var_number = buf->b_fnum;
3582 else
3583 retvar->var_val.var_number = -1;
3584 --emsg_off;
3585}
3586
3587/*
3588 * "bufwinnr(nr)" function
3589 */
3590 static void
3591f_bufwinnr(argvars, retvar)
3592 VAR argvars;
3593 VAR retvar;
3594{
3595#ifdef FEAT_WINDOWS
3596 win_T *wp;
3597 int winnr = 0;
3598#endif
3599 buf_T *buf;
3600
3601 ++emsg_off;
3602 buf = get_buf_var(&argvars[0]);
3603#ifdef FEAT_WINDOWS
3604 for (wp = firstwin; wp; wp = wp->w_next)
3605 {
3606 ++winnr;
3607 if (wp->w_buffer == buf)
3608 break;
3609 }
3610 retvar->var_val.var_number = (wp != NULL ? winnr : -1);
3611#else
3612 retvar->var_val.var_number = (curwin->w_buffer == buf ? 1 : -1);
3613#endif
3614 --emsg_off;
3615}
3616
3617/*
3618 * "byte2line(byte)" function
3619 */
3620/*ARGSUSED*/
3621 static void
3622f_byte2line(argvars, retvar)
3623 VAR argvars;
3624 VAR retvar;
3625{
3626#ifndef FEAT_BYTEOFF
3627 retvar->var_val.var_number = -1;
3628#else
3629 long boff = 0;
3630
3631 boff = get_var_number(&argvars[0]) - 1;
3632 if (boff < 0)
3633 retvar->var_val.var_number = -1;
3634 else
3635 retvar->var_val.var_number = ml_find_line_or_offset(curbuf,
3636 (linenr_T)0, &boff);
3637#endif
3638}
3639
3640/*
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00003641 * "byteidx()" function
3642 */
3643/*ARGSUSED*/
3644 static void
3645f_byteidx(argvars, retvar)
3646 VAR argvars;
3647 VAR retvar;
3648{
3649#ifdef FEAT_MBYTE
3650 char_u *t;
3651#endif
3652 char_u *str;
3653 long idx;
3654
3655 str = get_var_string(&argvars[0]);
3656 idx = get_var_number(&argvars[1]);
3657 retvar->var_val.var_number = -1;
3658 if (idx < 0)
3659 return;
3660
3661#ifdef FEAT_MBYTE
3662 t = str;
3663 for ( ; idx > 0; idx--)
3664 {
3665 if (*t == NUL) /* EOL reached */
3666 return;
3667 t += mb_ptr2len_check(t);
3668 }
3669 retvar->var_val.var_number = t - str;
3670#else
3671 if (idx <= STRLEN(str))
3672 retvar->var_val.var_number = idx;
3673#endif
3674}
3675
3676/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 * "char2nr(string)" function
3678 */
3679 static void
3680f_char2nr(argvars, retvar)
3681 VAR argvars;
3682 VAR retvar;
3683{
3684#ifdef FEAT_MBYTE
3685 if (has_mbyte)
3686 retvar->var_val.var_number =
3687 (*mb_ptr2char)(get_var_string(&argvars[0]));
3688 else
3689#endif
3690 retvar->var_val.var_number = get_var_string(&argvars[0])[0];
3691}
3692
3693/*
3694 * "cindent(lnum)" function
3695 */
3696 static void
3697f_cindent(argvars, retvar)
3698 VAR argvars;
3699 VAR retvar;
3700{
3701#ifdef FEAT_CINDENT
3702 pos_T pos;
3703 linenr_T lnum;
3704
3705 pos = curwin->w_cursor;
3706 lnum = get_var_lnum(argvars);
3707 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3708 {
3709 curwin->w_cursor.lnum = lnum;
3710 retvar->var_val.var_number = get_c_indent();
3711 curwin->w_cursor = pos;
3712 }
3713 else
3714#endif
3715 retvar->var_val.var_number = -1;
3716}
3717
3718/*
3719 * "col(string)" function
3720 */
3721 static void
3722f_col(argvars, retvar)
3723 VAR argvars;
3724 VAR retvar;
3725{
3726 colnr_T col = 0;
3727 pos_T *fp;
3728
3729 fp = var2fpos(&argvars[0], FALSE);
3730 if (fp != NULL)
3731 {
3732 if (fp->col == MAXCOL)
3733 {
3734 /* '> can be MAXCOL, get the length of the line then */
3735 if (fp->lnum <= curbuf->b_ml.ml_line_count)
3736 col = STRLEN(ml_get(fp->lnum)) + 1;
3737 else
3738 col = MAXCOL;
3739 }
3740 else
3741 {
3742 col = fp->col + 1;
3743#ifdef FEAT_VIRTUALEDIT
3744 /* col(".") when the cursor is on the NUL at the end of the line
3745 * because of "coladd" can be seen as an extra column. */
3746 if (virtual_active() && fp == &curwin->w_cursor)
3747 {
3748 char_u *p = ml_get_cursor();
3749
3750 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
3751 curwin->w_virtcol - curwin->w_cursor.coladd))
3752 {
3753# ifdef FEAT_MBYTE
3754 int l;
3755
3756 if (*p != NUL && p[(l = (*mb_ptr2len_check)(p))] == NUL)
3757 col += l;
3758# else
3759 if (*p != NUL && p[1] == NUL)
3760 ++col;
3761# endif
3762 }
3763 }
3764#endif
3765 }
3766 }
3767 retvar->var_val.var_number = col;
3768}
3769
3770/*
3771 * "confirm(message, buttons[, default [, type]])" function
3772 */
3773/*ARGSUSED*/
3774 static void
3775f_confirm(argvars, retvar)
3776 VAR argvars;
3777 VAR retvar;
3778{
3779#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
3780 char_u *message;
3781 char_u *buttons = NULL;
3782 char_u buf[NUMBUFLEN];
3783 char_u buf2[NUMBUFLEN];
3784 int def = 1;
3785 int type = VIM_GENERIC;
3786 int c;
3787
3788 message = get_var_string(&argvars[0]);
3789 if (argvars[1].var_type != VAR_UNKNOWN)
3790 {
3791 buttons = get_var_string_buf(&argvars[1], buf);
3792 if (argvars[2].var_type != VAR_UNKNOWN)
3793 {
3794 def = get_var_number(&argvars[2]);
3795 if (argvars[3].var_type != VAR_UNKNOWN)
3796 {
3797 /* avoid that TOUPPER_ASC calls get_var_string_buf() twice */
3798 c = *get_var_string_buf(&argvars[3], buf2);
3799 switch (TOUPPER_ASC(c))
3800 {
3801 case 'E': type = VIM_ERROR; break;
3802 case 'Q': type = VIM_QUESTION; break;
3803 case 'I': type = VIM_INFO; break;
3804 case 'W': type = VIM_WARNING; break;
3805 case 'G': type = VIM_GENERIC; break;
3806 }
3807 }
3808 }
3809 }
3810
3811 if (buttons == NULL || *buttons == NUL)
3812 buttons = (char_u *)_("&Ok");
3813
3814 retvar->var_val.var_number = do_dialog(type, NULL, message, buttons,
3815 def, NULL);
3816#else
3817 retvar->var_val.var_number = 0;
3818#endif
3819}
3820
3821
3822/*
3823 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
3824 *
3825 * Checks the existence of a cscope connection.
3826 */
3827/*ARGSUSED*/
3828 static void
3829f_cscope_connection(argvars, retvar)
3830 VAR argvars;
3831 VAR retvar;
3832{
3833#ifdef FEAT_CSCOPE
3834 int num = 0;
3835 char_u *dbpath = NULL;
3836 char_u *prepend = NULL;
3837 char_u buf[NUMBUFLEN];
3838
3839 if (argvars[0].var_type != VAR_UNKNOWN
3840 && argvars[1].var_type != VAR_UNKNOWN)
3841 {
3842 num = (int)get_var_number(&argvars[0]);
3843 dbpath = get_var_string(&argvars[1]);
3844 if (argvars[2].var_type != VAR_UNKNOWN)
3845 prepend = get_var_string_buf(&argvars[2], buf);
3846 }
3847
3848 retvar->var_val.var_number = cs_connection(num, dbpath, prepend);
3849#else
3850 retvar->var_val.var_number = 0;
3851#endif
3852}
3853
3854/*
3855 * "cursor(lnum, col)" function
3856 *
3857 * Moves the cursor to the specified line and column
3858 */
3859/*ARGSUSED*/
3860 static void
3861f_cursor(argvars, retvar)
3862 VAR argvars;
3863 VAR retvar;
3864{
3865 long line, col;
3866
3867 line = get_var_lnum(argvars);
3868 if (line > 0)
3869 curwin->w_cursor.lnum = line;
3870 col = get_var_number(&argvars[1]);
3871 if (col > 0)
3872 curwin->w_cursor.col = col - 1;
3873#ifdef FEAT_VIRTUALEDIT
3874 curwin->w_cursor.coladd = 0;
3875#endif
3876
3877 /* Make sure the cursor is in a valid position. */
3878 check_cursor();
3879#ifdef FEAT_MBYTE
3880 /* Correct cursor for multi-byte character. */
3881 if (has_mbyte)
3882 mb_adjust_cursor();
3883#endif
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003884
3885 curwin->w_set_curswant = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886}
3887
3888/*
3889 * "libcall()" function
3890 */
3891 static void
3892f_libcall(argvars, retvar)
3893 VAR argvars;
3894 VAR retvar;
3895{
3896 libcall_common(argvars, retvar, VAR_STRING);
3897}
3898
3899/*
3900 * "libcallnr()" function
3901 */
3902 static void
3903f_libcallnr(argvars, retvar)
3904 VAR argvars;
3905 VAR retvar;
3906{
3907 libcall_common(argvars, retvar, VAR_NUMBER);
3908}
3909
3910 static void
3911libcall_common(argvars, retvar, type)
3912 VAR argvars;
3913 VAR retvar;
3914 int type;
3915{
3916#ifdef FEAT_LIBCALL
3917 char_u *string_in;
3918 char_u **string_result;
3919 int nr_result;
3920#endif
3921
3922 retvar->var_type = type;
3923 if (type == VAR_NUMBER)
3924 retvar->var_val.var_number = 0;
3925 else
3926 retvar->var_val.var_string = NULL;
3927
3928 if (check_restricted() || check_secure())
3929 return;
3930
3931#ifdef FEAT_LIBCALL
3932 /* The first two args must be strings, otherwise its meaningless */
3933 if (argvars[0].var_type == VAR_STRING && argvars[1].var_type == VAR_STRING)
3934 {
3935 if (argvars[2].var_type == VAR_NUMBER)
3936 string_in = NULL;
3937 else
3938 string_in = argvars[2].var_val.var_string;
3939 if (type == VAR_NUMBER)
3940 string_result = NULL;
3941 else
3942 string_result = &retvar->var_val.var_string;
3943 if (mch_libcall(argvars[0].var_val.var_string,
3944 argvars[1].var_val.var_string,
3945 string_in,
3946 argvars[2].var_val.var_number,
3947 string_result,
3948 &nr_result) == OK
3949 && type == VAR_NUMBER)
3950 retvar->var_val.var_number = nr_result;
3951 }
3952#endif
3953}
3954
3955/*
3956 * "delete()" function
3957 */
3958 static void
3959f_delete(argvars, retvar)
3960 VAR argvars;
3961 VAR retvar;
3962{
3963 if (check_restricted() || check_secure())
3964 retvar->var_val.var_number = -1;
3965 else
3966 retvar->var_val.var_number = mch_remove(get_var_string(&argvars[0]));
3967}
3968
3969/*
3970 * "did_filetype()" function
3971 */
3972/*ARGSUSED*/
3973 static void
3974f_did_filetype(argvars, retvar)
3975 VAR argvars;
3976 VAR retvar;
3977{
3978#ifdef FEAT_AUTOCMD
3979 retvar->var_val.var_number = did_filetype;
3980#else
3981 retvar->var_val.var_number = 0;
3982#endif
3983}
3984
3985/*
Bram Moolenaar47136d72004-10-12 20:02:24 +00003986 * "diff_filler()" function
3987 */
3988/*ARGSUSED*/
3989 static void
3990f_diff_filler(argvars, retvar)
3991 VAR argvars;
3992 VAR retvar;
3993{
3994#ifdef FEAT_DIFF
3995 retvar->var_val.var_number = diff_check_fill(curwin, get_var_lnum(argvars));
3996#endif
3997}
3998
3999/*
4000 * "diff_hlID()" function
4001 */
4002/*ARGSUSED*/
4003 static void
4004f_diff_hlID(argvars, retvar)
4005 VAR argvars;
4006 VAR retvar;
4007{
4008#ifdef FEAT_DIFF
4009 linenr_T lnum = get_var_lnum(argvars);
4010 static linenr_T prev_lnum = 0;
4011 static int changedtick = 0;
4012 static int fnum = 0;
4013 static int change_start = 0;
4014 static int change_end = 0;
4015 static enum hlf_value hlID = 0;
4016 int filler_lines;
4017 int col;
4018
4019 if (lnum != prev_lnum
4020 || changedtick != curbuf->b_changedtick
4021 || fnum != curbuf->b_fnum)
4022 {
4023 /* New line, buffer, change: need to get the values. */
4024 filler_lines = diff_check(curwin, lnum);
4025 if (filler_lines < 0)
4026 {
4027 if (filler_lines == -1)
4028 {
4029 change_start = MAXCOL;
4030 change_end = -1;
4031 if (diff_find_change(curwin, lnum, &change_start, &change_end))
4032 hlID = HLF_ADD; /* added line */
4033 else
4034 hlID = HLF_CHD; /* changed line */
4035 }
4036 else
4037 hlID = HLF_ADD; /* added line */
4038 }
4039 else
4040 hlID = (enum hlf_value)0;
4041 prev_lnum = lnum;
4042 changedtick = curbuf->b_changedtick;
4043 fnum = curbuf->b_fnum;
4044 }
4045
4046 if (hlID == HLF_CHD || hlID == HLF_TXD)
4047 {
4048 col = get_var_number(&argvars[1]) - 1;
4049 if (col >= change_start && col <= change_end)
4050 hlID = HLF_TXD; /* changed text */
4051 else
4052 hlID = HLF_CHD; /* changed line */
4053 }
4054 retvar->var_val.var_number = hlID == (enum hlf_value)0 ? 0 : (int)hlID;
4055#endif
4056}
4057
4058/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 * "escape({string}, {chars})" function
4060 */
4061 static void
4062f_escape(argvars, retvar)
4063 VAR argvars;
4064 VAR retvar;
4065{
4066 char_u buf[NUMBUFLEN];
4067
4068 retvar->var_val.var_string =
4069 vim_strsave_escaped(get_var_string(&argvars[0]),
4070 get_var_string_buf(&argvars[1], buf));
4071 retvar->var_type = VAR_STRING;
4072}
4073
4074/*
4075 * "eventhandler()" function
4076 */
4077/*ARGSUSED*/
4078 static void
4079f_eventhandler(argvars, retvar)
4080 VAR argvars;
4081 VAR retvar;
4082{
4083 retvar->var_val.var_number = vgetc_busy;
4084}
4085
4086/*
4087 * "executable()" function
4088 */
4089 static void
4090f_executable(argvars, retvar)
4091 VAR argvars;
4092 VAR retvar;
4093{
4094 retvar->var_val.var_number = mch_can_exe(get_var_string(&argvars[0]));
4095}
4096
4097/*
4098 * "exists()" function
4099 */
4100 static void
4101f_exists(argvars, retvar)
4102 VAR argvars;
4103 VAR retvar;
4104{
4105 char_u *p;
4106 char_u *name;
4107 int n = FALSE;
4108 int len = 0;
4109
4110 p = get_var_string(&argvars[0]);
4111 if (*p == '$') /* environment variable */
4112 {
4113 /* first try "normal" environment variables (fast) */
4114 if (mch_getenv(p + 1) != NULL)
4115 n = TRUE;
4116 else
4117 {
4118 /* try expanding things like $VIM and ${HOME} */
4119 p = expand_env_save(p);
4120 if (p != NULL && *p != '$')
4121 n = TRUE;
4122 vim_free(p);
4123 }
4124 }
4125 else if (*p == '&' || *p == '+') /* option */
4126 n = (get_option_var(&p, NULL, TRUE) == OK);
4127 else if (*p == '*') /* internal or user defined function */
4128 {
4129 ++p;
4130 p = trans_function_name(&p, FALSE, TRUE);
4131 if (p != NULL)
4132 {
4133 if (ASCII_ISUPPER(*p) || p[0] == K_SPECIAL)
4134 n = (find_func(p) != NULL);
4135 else if (ASCII_ISLOWER(*p))
4136 n = (find_internal_func(p) >= 0);
4137 vim_free(p);
4138 }
4139 }
4140 else if (*p == ':')
4141 {
4142 n = cmd_exists(p + 1);
4143 }
4144 else if (*p == '#')
4145 {
4146#ifdef FEAT_AUTOCMD
4147 name = p + 1;
4148 p = vim_strchr(name, '#');
4149 if (p != NULL)
4150 n = au_exists(name, p, p + 1);
4151 else
4152 n = au_exists(name, name + STRLEN(name), NULL);
4153#endif
4154 }
4155 else /* internal variable */
4156 {
4157#ifdef FEAT_MAGIC_BRACES
4158 char_u *expr_start;
4159 char_u *expr_end;
4160 char_u *temp_string = NULL;
4161 char_u *s;
4162#endif
4163 name = p;
4164
4165#ifdef FEAT_MAGIC_BRACES
4166 /* Find the end of the name. */
4167 s = find_name_end(name, &expr_start, &expr_end);
4168 if (expr_start != NULL)
4169 {
4170 temp_string = make_expanded_name(name, expr_start, expr_end, s);
4171 if (temp_string != NULL)
4172 {
4173 len = STRLEN(temp_string);
4174 name = temp_string;
4175 }
4176 }
4177#endif
4178 if (len == 0)
4179 len = get_id_len(&p);
4180 if (len != 0)
4181 n = (get_var_var(name, len, NULL) == OK);
4182
4183#ifdef FEAT_MAGIC_BRACES
4184 vim_free(temp_string);
4185#endif
4186 }
4187
4188 retvar->var_val.var_number = n;
4189}
4190
4191/*
4192 * "expand()" function
4193 */
4194 static void
4195f_expand(argvars, retvar)
4196 VAR argvars;
4197 VAR retvar;
4198{
4199 char_u *s;
4200 int len;
4201 char_u *errormsg;
4202 int flags = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
4203 expand_T xpc;
4204
4205 retvar->var_type = VAR_STRING;
4206 s = get_var_string(&argvars[0]);
4207 if (*s == '%' || *s == '#' || *s == '<')
4208 {
4209 ++emsg_off;
4210 retvar->var_val.var_string = eval_vars(s, &len, NULL, &errormsg, s);
4211 --emsg_off;
4212 }
4213 else
4214 {
4215 /* When the optional second argument is non-zero, don't remove matches
4216 * for 'suffixes' and 'wildignore' */
4217 if (argvars[1].var_type != VAR_UNKNOWN && get_var_number(&argvars[1]))
4218 flags |= WILD_KEEP_ALL;
4219 ExpandInit(&xpc);
4220 xpc.xp_context = EXPAND_FILES;
4221 retvar->var_val.var_string = ExpandOne(&xpc, s, NULL, flags, WILD_ALL);
4222 ExpandCleanup(&xpc);
4223 }
4224}
4225
4226/*
4227 * "filereadable()" function
4228 */
4229 static void
4230f_filereadable(argvars, retvar)
4231 VAR argvars;
4232 VAR retvar;
4233{
4234 FILE *fd;
4235 char_u *p;
4236 int n;
4237
4238 p = get_var_string(&argvars[0]);
4239 if (*p && !mch_isdir(p) && (fd = mch_fopen((char *)p, "r")) != NULL)
4240 {
4241 n = TRUE;
4242 fclose(fd);
4243 }
4244 else
4245 n = FALSE;
4246
4247 retvar->var_val.var_number = n;
4248}
4249
4250/*
4251 * return 0 for not writable, 1 for writable file, 2 for a dir which we have
4252 * rights to write into.
4253 */
4254 static void
4255f_filewritable(argvars, retvar)
4256 VAR argvars;
4257 VAR retvar;
4258{
4259 char_u *p;
4260 int retval = 0;
4261#if defined(UNIX) || defined(VMS)
4262 int perm = 0;
4263#endif
4264
4265 p = get_var_string(&argvars[0]);
4266#if defined(UNIX) || defined(VMS)
4267 perm = mch_getperm(p);
4268#endif
4269#ifndef MACOS_CLASSIC /* TODO: get either mch_writable or mch_access */
4270 if (
4271# ifdef WIN3264
4272 mch_writable(p) &&
4273# else
4274# if defined(UNIX) || defined(VMS)
4275 (perm & 0222) &&
4276# endif
4277# endif
4278 mch_access((char *)p, W_OK) == 0
4279 )
4280#endif
4281 {
4282 ++retval;
4283 if (mch_isdir(p))
4284 ++retval;
4285 }
4286 retvar->var_val.var_number = retval;
4287}
4288
4289/*
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00004290 * "finddir({fname}[, {path}[, {count}]])" function
4291 */
4292 static void
4293f_finddir(argvars, retvar)
4294 VAR argvars;
4295 VAR retvar;
4296{
4297 f_findfilendir(argvars, retvar, TRUE);
4298}
4299
4300/*
4301 * "findfile({fname}[, {path}[, {count}]])" function
4302 */
4303 static void
4304f_findfile(argvars, retvar)
4305 VAR argvars;
4306 VAR retvar;
4307{
4308 f_findfilendir(argvars, retvar, FALSE);
4309}
4310
4311 static void
4312f_findfilendir(argvars, retvar, dir)
4313 VAR argvars;
4314 VAR retvar;
4315 int dir;
4316{
4317#ifdef FEAT_SEARCHPATH
4318 char_u *fname;
4319 char_u *fresult = NULL;
4320 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
4321 char_u *p;
4322 char_u pathbuf[NUMBUFLEN];
4323 int count = 1;
4324 int first = TRUE;
4325
4326 fname = get_var_string(&argvars[0]);
4327
4328 if (argvars[1].var_type != VAR_UNKNOWN)
4329 {
4330 p = get_var_string_buf(&argvars[1], pathbuf);
4331 if (*p != NUL)
4332 path = p;
4333
4334 if (argvars[2].var_type != VAR_UNKNOWN)
4335 count = get_var_number(&argvars[2]);
4336 }
4337
4338 do
4339 {
4340 vim_free(fresult);
4341 fresult = find_file_in_path_option(first ? fname : NULL,
4342 first ? (int)STRLEN(fname) : 0,
4343 0, first, path, dir, NULL);
4344 first = FALSE;
4345 } while (--count > 0 && fresult != NULL);
4346
4347 retvar->var_val.var_string = fresult;
4348#else
4349 retvar->var_val.var_string = NULL;
4350#endif
4351 retvar->var_type = VAR_STRING;
4352}
4353
4354/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355 * "fnamemodify({fname}, {mods})" function
4356 */
4357 static void
4358f_fnamemodify(argvars, retvar)
4359 VAR argvars;
4360 VAR retvar;
4361{
4362 char_u *fname;
4363 char_u *mods;
4364 int usedlen = 0;
4365 int len;
4366 char_u *fbuf = NULL;
4367 char_u buf[NUMBUFLEN];
4368
4369 fname = get_var_string(&argvars[0]);
4370 mods = get_var_string_buf(&argvars[1], buf);
4371 len = (int)STRLEN(fname);
4372
4373 (void)modify_fname(mods, &usedlen, &fname, &fbuf, &len);
4374
4375 retvar->var_type = VAR_STRING;
4376 if (fname == NULL)
4377 retvar->var_val.var_string = NULL;
4378 else
4379 retvar->var_val.var_string = vim_strnsave(fname, len);
4380 vim_free(fbuf);
4381}
4382
4383/*
4384 * "foldclosed()" function
4385 */
4386 static void
4387f_foldclosed(argvars, retvar)
4388 VAR argvars;
4389 VAR retvar;
4390{
4391 foldclosed_both(argvars, retvar, FALSE);
4392}
4393
4394/*
4395 * "foldclosedend()" function
4396 */
4397 static void
4398f_foldclosedend(argvars, retvar)
4399 VAR argvars;
4400 VAR retvar;
4401{
4402 foldclosed_both(argvars, retvar, TRUE);
4403}
4404
4405/*
4406 * "foldclosed()" function
4407 */
4408 static void
4409foldclosed_both(argvars, retvar, end)
4410 VAR argvars;
4411 VAR retvar;
4412 int end;
4413{
4414#ifdef FEAT_FOLDING
4415 linenr_T lnum;
4416 linenr_T first, last;
4417
4418 lnum = get_var_lnum(argvars);
4419 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4420 {
4421 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4422 {
4423 if (end)
4424 retvar->var_val.var_number = (varnumber_T)last;
4425 else
4426 retvar->var_val.var_number = (varnumber_T)first;
4427 return;
4428 }
4429 }
4430#endif
4431 retvar->var_val.var_number = -1;
4432}
4433
4434/*
4435 * "foldlevel()" function
4436 */
4437 static void
4438f_foldlevel(argvars, retvar)
4439 VAR argvars;
4440 VAR retvar;
4441{
4442#ifdef FEAT_FOLDING
4443 linenr_T lnum;
4444
4445 lnum = get_var_lnum(argvars);
4446 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4447 retvar->var_val.var_number = foldLevel(lnum);
4448 else
4449#endif
4450 retvar->var_val.var_number = 0;
4451}
4452
4453/*
4454 * "foldtext()" function
4455 */
4456/*ARGSUSED*/
4457 static void
4458f_foldtext(argvars, retvar)
4459 VAR argvars;
4460 VAR retvar;
4461{
4462#ifdef FEAT_FOLDING
4463 linenr_T lnum;
4464 char_u *s;
4465 char_u *r;
4466 int len;
4467 char *txt;
4468#endif
4469
4470 retvar->var_type = VAR_STRING;
4471 retvar->var_val.var_string = NULL;
4472#ifdef FEAT_FOLDING
4473 if ((linenr_T)vimvars[VV_FOLDSTART].val > 0
4474 && (linenr_T)vimvars[VV_FOLDEND].val <= curbuf->b_ml.ml_line_count
4475 && vimvars[VV_FOLDDASHES].val != NULL)
4476 {
4477 /* Find first non-empty line in the fold. */
4478 lnum = (linenr_T)vimvars[VV_FOLDSTART].val;
4479 while (lnum < (linenr_T)vimvars[VV_FOLDEND].val)
4480 {
4481 if (!linewhite(lnum))
4482 break;
4483 ++lnum;
4484 }
4485
4486 /* Find interesting text in this line. */
4487 s = skipwhite(ml_get(lnum));
4488 /* skip C comment-start */
4489 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004490 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 s = skipwhite(s + 2);
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00004492 if (*skipwhite(s) == NUL
4493 && lnum + 1 < (linenr_T)vimvars[VV_FOLDEND].val)
4494 {
4495 s = skipwhite(ml_get(lnum + 1));
4496 if (*s == '*')
4497 s = skipwhite(s + 1);
4498 }
4499 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500 txt = _("+-%s%3ld lines: ");
4501 r = alloc((unsigned)(STRLEN(txt)
4502 + STRLEN(vimvars[VV_FOLDDASHES].val) /* for %s */
4503 + 20 /* for %3ld */
4504 + STRLEN(s))); /* concatenated */
4505 if (r != NULL)
4506 {
4507 sprintf((char *)r, txt, vimvars[VV_FOLDDASHES].val,
4508 (long)((linenr_T)vimvars[VV_FOLDEND].val
4509 - (linenr_T)vimvars[VV_FOLDSTART].val + 1));
4510 len = (int)STRLEN(r);
4511 STRCAT(r, s);
4512 /* remove 'foldmarker' and 'commentstring' */
4513 foldtext_cleanup(r + len);
4514 retvar->var_val.var_string = r;
4515 }
4516 }
4517#endif
4518}
4519
4520/*
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00004521 * "foldtextresult(lnum)" function
4522 */
4523/*ARGSUSED*/
4524 static void
4525f_foldtextresult(argvars, retvar)
4526 VAR argvars;
4527 VAR retvar;
4528{
4529#ifdef FEAT_FOLDING
4530 linenr_T lnum;
4531 char_u *text;
4532 char_u buf[51];
4533 foldinfo_T foldinfo;
4534 int fold_count;
4535#endif
4536
4537 retvar->var_type = VAR_STRING;
4538 retvar->var_val.var_string = NULL;
4539#ifdef FEAT_FOLDING
4540 lnum = get_var_lnum(argvars);
4541 fold_count = foldedCount(curwin, lnum, &foldinfo);
4542 if (fold_count > 0)
4543 {
4544 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4545 &foldinfo, buf);
4546 if (text == buf)
4547 text = vim_strsave(text);
4548 retvar->var_val.var_string = text;
4549 }
4550#endif
4551}
4552
4553/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 * "foreground()" function
4555 */
4556/*ARGSUSED*/
4557 static void
4558f_foreground(argvars, retvar)
4559 VAR argvars;
4560 VAR retvar;
4561{
4562 retvar->var_val.var_number = 0;
4563#ifdef FEAT_GUI
4564 if (gui.in_use)
4565 gui_mch_set_foreground();
4566#else
4567# ifdef WIN32
4568 win32_set_foreground();
4569# endif
4570#endif
4571}
4572
4573/*
4574 * "getchar()" function
4575 */
4576 static void
4577f_getchar(argvars, retvar)
4578 VAR argvars;
4579 VAR retvar;
4580{
4581 varnumber_T n;
4582
4583 ++no_mapping;
4584 ++allow_keys;
4585 if (argvars[0].var_type == VAR_UNKNOWN)
4586 /* getchar(): blocking wait. */
4587 n = safe_vgetc();
4588 else if (get_var_number(&argvars[0]) == 1)
4589 /* getchar(1): only check if char avail */
4590 n = vpeekc();
4591 else if (vpeekc() == NUL)
4592 /* getchar(0) and no char avail: return zero */
4593 n = 0;
4594 else
4595 /* getchar(0) and char avail: return char */
4596 n = safe_vgetc();
4597 --no_mapping;
4598 --allow_keys;
4599
4600 retvar->var_val.var_number = n;
4601 if (IS_SPECIAL(n) || mod_mask != 0)
4602 {
4603 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4604 int i = 0;
4605
4606 /* Turn a special key into three bytes, plus modifier. */
4607 if (mod_mask != 0)
4608 {
4609 temp[i++] = K_SPECIAL;
4610 temp[i++] = KS_MODIFIER;
4611 temp[i++] = mod_mask;
4612 }
4613 if (IS_SPECIAL(n))
4614 {
4615 temp[i++] = K_SPECIAL;
4616 temp[i++] = K_SECOND(n);
4617 temp[i++] = K_THIRD(n);
4618 }
4619#ifdef FEAT_MBYTE
4620 else if (has_mbyte)
4621 i += (*mb_char2bytes)(n, temp + i);
4622#endif
4623 else
4624 temp[i++] = n;
4625 temp[i++] = NUL;
4626 retvar->var_type = VAR_STRING;
4627 retvar->var_val.var_string = vim_strsave(temp);
4628 }
4629}
4630
4631/*
4632 * "getcharmod()" function
4633 */
4634/*ARGSUSED*/
4635 static void
4636f_getcharmod(argvars, retvar)
4637 VAR argvars;
4638 VAR retvar;
4639{
4640 retvar->var_val.var_number = mod_mask;
4641}
4642
4643/*
4644 * "getcmdline()" function
4645 */
4646/*ARGSUSED*/
4647 static void
4648f_getcmdline(argvars, retvar)
4649 VAR argvars;
4650 VAR retvar;
4651{
4652 retvar->var_type = VAR_STRING;
4653 retvar->var_val.var_string = get_cmdline_str();
4654}
4655
4656/*
4657 * "getcmdpos()" function
4658 */
4659/*ARGSUSED*/
4660 static void
4661f_getcmdpos(argvars, retvar)
4662 VAR argvars;
4663 VAR retvar;
4664{
4665 retvar->var_val.var_number = get_cmdline_pos() + 1;
4666}
4667
4668/*
4669 * "getbufvar()" function
4670 */
4671 static void
4672f_getbufvar(argvars, retvar)
4673 VAR argvars;
4674 VAR retvar;
4675{
4676 buf_T *buf;
4677 buf_T *save_curbuf;
4678 char_u *varname;
4679 VAR v;
4680
4681 ++emsg_off;
4682 buf = get_buf_var(&argvars[0]);
4683 varname = get_var_string(&argvars[1]);
4684
4685 retvar->var_type = VAR_STRING;
4686 retvar->var_val.var_string = NULL;
4687
4688 if (buf != NULL && varname != NULL)
4689 {
4690 if (*varname == '&') /* buffer-local-option */
4691 {
4692 /* set curbuf to be our buf, temporarily */
4693 save_curbuf = curbuf;
4694 curbuf = buf;
4695
4696 get_option_var(&varname, retvar, TRUE);
4697
4698 /* restore previous notion of curbuf */
4699 curbuf = save_curbuf;
4700 }
4701 else
4702 {
4703 /* look up the variable */
4704 v = find_var_in_ga(&buf->b_vars, varname);
4705 if (v != NULL)
4706 copy_var(v, retvar);
4707 }
4708 }
4709
4710 --emsg_off;
4711}
4712
4713/*
4714 * "getcwd()" function
4715 */
4716/*ARGSUSED*/
4717 static void
4718f_getcwd(argvars, retvar)
4719 VAR argvars;
4720 VAR retvar;
4721{
4722 char_u cwd[MAXPATHL];
4723
4724 retvar->var_type = VAR_STRING;
4725 if (mch_dirname(cwd, MAXPATHL) == FAIL)
4726 retvar->var_val.var_string = NULL;
4727 else
4728 {
4729 retvar->var_val.var_string = vim_strsave(cwd);
4730#ifdef BACKSLASH_IN_FILENAME
4731 slash_adjust(retvar->var_val.var_string);
4732#endif
4733 }
4734}
4735
4736/*
Bram Moolenaar46c9c732004-12-12 11:37:09 +00004737 * "getfontname()" function
4738 */
4739 static void
4740f_getfontname(argvars, retvar)
4741 VAR argvars;
4742 VAR retvar;
4743{
4744 retvar->var_type = VAR_STRING;
4745 retvar->var_val.var_string = NULL;
4746#ifdef FEAT_GUI
4747 if (gui.in_use)
4748 {
4749 GuiFont font;
4750 char_u *name = NULL;
4751
4752 if (argvars[0].var_type == VAR_UNKNOWN)
4753 {
4754 /* Get the "Normal" font. Either the name saved by
4755 * hl_set_font_name() or from the font ID. */
4756 font = gui.norm_font;
4757 name = hl_get_font_name();
4758 }
4759 else
4760 {
4761 name = get_var_string(&argvars[0]);
4762 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4763 return;
4764 font = gui_mch_get_font(name, FALSE);
4765 if (font == NOFONT)
4766 return; /* Invalid font name, return empty string. */
4767 }
4768 retvar->var_val.var_string = gui_mch_get_fontname(font, name);
4769 if (argvars[0].var_type != VAR_UNKNOWN)
4770 gui_mch_free_font(font);
4771 }
4772#endif
4773}
4774
4775/*
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00004776 * "getfperm({fname})" function
4777 */
4778 static void
4779f_getfperm(argvars, retvar)
4780 VAR argvars;
4781 VAR retvar;
4782{
4783 char_u *fname;
4784 struct stat st;
4785 char_u *perm = NULL;
4786 char_u flags[] = "rwx";
4787 int i;
4788
4789 fname = get_var_string(&argvars[0]);
4790
4791 retvar->var_type = VAR_STRING;
4792 if (mch_stat((char *)fname, &st) >= 0)
4793 {
4794 perm = vim_strsave((char_u *)"---------");
4795 if (perm != NULL)
4796 {
4797 for (i = 0; i < 9; i++)
4798 {
4799 if (st.st_mode & (1 << (8 - i)))
4800 perm[i] = flags[i % 3];
4801 }
4802 }
4803 }
4804 retvar->var_val.var_string = perm;
4805}
4806
4807/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 * "getfsize({fname})" function
4809 */
4810 static void
4811f_getfsize(argvars, retvar)
4812 VAR argvars;
4813 VAR retvar;
4814{
4815 char_u *fname;
4816 struct stat st;
4817
4818 fname = get_var_string(&argvars[0]);
4819
4820 retvar->var_type = VAR_NUMBER;
4821
4822 if (mch_stat((char *)fname, &st) >= 0)
4823 {
4824 if (mch_isdir(fname))
4825 retvar->var_val.var_number = 0;
4826 else
4827 retvar->var_val.var_number = (varnumber_T)st.st_size;
4828 }
4829 else
4830 retvar->var_val.var_number = -1;
4831}
4832
4833/*
4834 * "getftime({fname})" function
4835 */
4836 static void
4837f_getftime(argvars, retvar)
4838 VAR argvars;
4839 VAR retvar;
4840{
4841 char_u *fname;
4842 struct stat st;
4843
4844 fname = get_var_string(&argvars[0]);
4845
4846 if (mch_stat((char *)fname, &st) >= 0)
4847 retvar->var_val.var_number = (varnumber_T)st.st_mtime;
4848 else
4849 retvar->var_val.var_number = -1;
4850}
4851
4852/*
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00004853 * "getftype({fname})" function
4854 */
4855 static void
4856f_getftype(argvars, retvar)
4857 VAR argvars;
4858 VAR retvar;
4859{
4860 char_u *fname;
4861 struct stat st;
4862 char_u *type = NULL;
4863 char *t;
4864
4865 fname = get_var_string(&argvars[0]);
4866
4867 retvar->var_type = VAR_STRING;
4868 if (mch_lstat((char *)fname, &st) >= 0)
4869 {
4870#ifdef S_ISREG
4871 if (S_ISREG(st.st_mode))
4872 t = "file";
4873 else if (S_ISDIR(st.st_mode))
4874 t = "dir";
4875# ifdef S_ISLNK
4876 else if (S_ISLNK(st.st_mode))
4877 t = "link";
4878# endif
4879# ifdef S_ISBLK
4880 else if (S_ISBLK(st.st_mode))
4881 t = "bdev";
4882# endif
4883# ifdef S_ISCHR
4884 else if (S_ISCHR(st.st_mode))
4885 t = "cdev";
4886# endif
4887# ifdef S_ISFIFO
4888 else if (S_ISFIFO(st.st_mode))
4889 t = "fifo";
4890# endif
4891# ifdef S_ISSOCK
4892 else if (S_ISSOCK(st.st_mode))
4893 t = "fifo";
4894# endif
4895 else
4896 t = "other";
4897#else
4898# ifdef S_IFMT
4899 switch (st.st_mode & S_IFMT)
4900 {
4901 case S_IFREG: t = "file"; break;
4902 case S_IFDIR: t = "dir"; break;
4903# ifdef S_IFLNK
4904 case S_IFLNK: t = "link"; break;
4905# endif
4906# ifdef S_IFBLK
4907 case S_IFBLK: t = "bdev"; break;
4908# endif
4909# ifdef S_IFCHR
4910 case S_IFCHR: t = "cdev"; break;
4911# endif
4912# ifdef S_IFIFO
4913 case S_IFIFO: t = "fifo"; break;
4914# endif
4915# ifdef S_IFSOCK
4916 case S_IFSOCK: t = "socket"; break;
4917# endif
4918 default: t = "other";
4919 }
4920# else
4921 if (mch_isdir(fname))
4922 t = "dir";
4923 else
4924 t = "file";
4925# endif
4926#endif
4927 type = vim_strsave((char_u *)t);
4928 }
4929 retvar->var_val.var_string = type;
4930}
4931
4932/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 * "getreg()" function
4934 */
4935 static void
4936f_getreg(argvars, retvar)
4937 VAR argvars;
4938 VAR retvar;
4939{
4940 char_u *strregname;
4941 int regname;
4942
4943 if (argvars[0].var_type != VAR_UNKNOWN)
4944 strregname = get_var_string(&argvars[0]);
4945 else
4946 strregname = vimvars[VV_REG].val;
4947 regname = (strregname == NULL ? '"' : *strregname);
4948 if (regname == 0)
4949 regname = '"';
4950
4951 retvar->var_type = VAR_STRING;
4952 retvar->var_val.var_string = get_reg_contents(regname, TRUE);
4953}
4954
4955/*
4956 * "getregtype()" function
4957 */
4958 static void
4959f_getregtype(argvars, retvar)
4960 VAR argvars;
4961 VAR retvar;
4962{
4963 char_u *strregname;
4964 int regname;
4965 char_u buf[NUMBUFLEN + 2];
4966 long reglen = 0;
4967
4968 if (argvars[0].var_type != VAR_UNKNOWN)
4969 strregname = get_var_string(&argvars[0]);
4970 else
4971 /* Default to v:register */
4972 strregname = vimvars[VV_REG].val;
4973
4974 regname = (strregname == NULL ? '"' : *strregname);
4975 if (regname == 0)
4976 regname = '"';
4977
4978 buf[0] = NUL;
4979 buf[1] = NUL;
4980 switch (get_reg_type(regname, &reglen))
4981 {
4982 case MLINE: buf[0] = 'V'; break;
4983 case MCHAR: buf[0] = 'v'; break;
4984#ifdef FEAT_VISUAL
4985 case MBLOCK:
4986 buf[0] = Ctrl_V;
4987 sprintf((char *)buf + 1, "%ld", reglen + 1);
4988 break;
4989#endif
4990 }
4991 retvar->var_type = VAR_STRING;
4992 retvar->var_val.var_string = vim_strsave(buf);
4993}
4994
4995/*
4996 * "getline(lnum)" function
4997 */
4998 static void
4999f_getline(argvars, retvar)
5000 VAR argvars;
5001 VAR retvar;
5002{
5003 linenr_T lnum;
5004 char_u *p;
5005
5006 lnum = get_var_lnum(argvars);
5007
5008 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5009 p = ml_get(lnum);
5010 else
5011 p = (char_u *)"";
5012
5013 retvar->var_type = VAR_STRING;
5014 retvar->var_val.var_string = vim_strsave(p);
5015}
5016
5017/*
5018 * "getwinposx()" function
5019 */
5020/*ARGSUSED*/
5021 static void
5022f_getwinposx(argvars, retvar)
5023 VAR argvars;
5024 VAR retvar;
5025{
5026 retvar->var_val.var_number = -1;
5027#ifdef FEAT_GUI
5028 if (gui.in_use)
5029 {
5030 int x, y;
5031
5032 if (gui_mch_get_winpos(&x, &y) == OK)
5033 retvar->var_val.var_number = x;
5034 }
5035#endif
5036}
5037
5038/*
5039 * "getwinposy()" function
5040 */
5041/*ARGSUSED*/
5042 static void
5043f_getwinposy(argvars, retvar)
5044 VAR argvars;
5045 VAR retvar;
5046{
5047 retvar->var_val.var_number = -1;
5048#ifdef FEAT_GUI
5049 if (gui.in_use)
5050 {
5051 int x, y;
5052
5053 if (gui_mch_get_winpos(&x, &y) == OK)
5054 retvar->var_val.var_number = y;
5055 }
5056#endif
5057}
5058
5059/*
5060 * "getwinvar()" function
5061 */
5062 static void
5063f_getwinvar(argvars, retvar)
5064 VAR argvars;
5065 VAR retvar;
5066{
5067 win_T *win, *oldcurwin;
5068 char_u *varname;
5069 VAR v;
5070
5071 ++emsg_off;
5072 win = find_win_by_nr(&argvars[0]);
5073 varname = get_var_string(&argvars[1]);
5074
5075 retvar->var_type = VAR_STRING;
5076 retvar->var_val.var_string = NULL;
5077
5078 if (win != NULL && varname != NULL)
5079 {
5080 if (*varname == '&') /* window-local-option */
5081 {
5082 /* set curwin to be our win, temporarily */
5083 oldcurwin = curwin;
5084 curwin = win;
5085
5086 get_option_var(&varname, retvar , 1);
5087
5088 /* restore previous notion of curwin */
5089 curwin = oldcurwin;
5090 }
5091 else
5092 {
5093 /* look up the variable */
5094 v = find_var_in_ga(&win->w_vars, varname);
5095 if (v != NULL)
5096 copy_var(v, retvar);
5097 }
5098 }
5099
5100 --emsg_off;
5101}
5102
5103/*
5104 * "glob()" function
5105 */
5106 static void
5107f_glob(argvars, retvar)
5108 VAR argvars;
5109 VAR retvar;
5110{
5111 expand_T xpc;
5112
5113 ExpandInit(&xpc);
5114 xpc.xp_context = EXPAND_FILES;
5115 retvar->var_type = VAR_STRING;
5116 retvar->var_val.var_string = ExpandOne(&xpc, get_var_string(&argvars[0]),
5117 NULL, WILD_USE_NL|WILD_SILENT, WILD_ALL);
5118 ExpandCleanup(&xpc);
5119}
5120
5121/*
5122 * "globpath()" function
5123 */
5124 static void
5125f_globpath(argvars, retvar)
5126 VAR argvars;
5127 VAR retvar;
5128{
5129 char_u buf1[NUMBUFLEN];
5130
5131 retvar->var_type = VAR_STRING;
5132 retvar->var_val.var_string = globpath(get_var_string(&argvars[0]),
5133 get_var_string_buf(&argvars[1], buf1));
5134}
5135
5136/*
5137 * "has()" function
5138 */
5139 static void
5140f_has(argvars, retvar)
5141 VAR argvars;
5142 VAR retvar;
5143{
5144 int i;
5145 char_u *name;
5146 int n = FALSE;
5147 static char *(has_list[]) =
5148 {
5149#ifdef AMIGA
5150 "amiga",
5151# ifdef FEAT_ARP
5152 "arp",
5153# endif
5154#endif
5155#ifdef __BEOS__
5156 "beos",
5157#endif
5158#ifdef MSDOS
5159# ifdef DJGPP
5160 "dos32",
5161# else
5162 "dos16",
5163# endif
5164#endif
5165#ifdef MACOS /* TODO: Should we add MACOS_CLASSIC, MACOS_X? (Dany) */
5166 "mac",
5167#endif
5168#if defined(MACOS_X_UNIX)
5169 "macunix",
5170#endif
5171#ifdef OS2
5172 "os2",
5173#endif
5174#ifdef __QNX__
5175 "qnx",
5176#endif
5177#ifdef RISCOS
5178 "riscos",
5179#endif
5180#ifdef UNIX
5181 "unix",
5182#endif
5183#ifdef VMS
5184 "vms",
5185#endif
5186#ifdef WIN16
5187 "win16",
5188#endif
5189#ifdef WIN32
5190 "win32",
5191#endif
5192#if defined(UNIX) && (defined(__CYGWIN32__) || defined(__CYGWIN__))
5193 "win32unix",
5194#endif
5195#ifdef WIN64
5196 "win64",
5197#endif
5198#ifdef EBCDIC
5199 "ebcdic",
5200#endif
5201#ifndef CASE_INSENSITIVE_FILENAME
5202 "fname_case",
5203#endif
5204#ifdef FEAT_ARABIC
5205 "arabic",
5206#endif
5207#ifdef FEAT_AUTOCMD
5208 "autocmd",
5209#endif
5210#ifdef FEAT_BEVAL
5211 "balloon_eval",
5212#endif
5213#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5214 "builtin_terms",
5215# ifdef ALL_BUILTIN_TCAPS
5216 "all_builtin_terms",
5217# endif
5218#endif
5219#ifdef FEAT_BYTEOFF
5220 "byte_offset",
5221#endif
5222#ifdef FEAT_CINDENT
5223 "cindent",
5224#endif
5225#ifdef FEAT_CLIENTSERVER
5226 "clientserver",
5227#endif
5228#ifdef FEAT_CLIPBOARD
5229 "clipboard",
5230#endif
5231#ifdef FEAT_CMDL_COMPL
5232 "cmdline_compl",
5233#endif
5234#ifdef FEAT_CMDHIST
5235 "cmdline_hist",
5236#endif
5237#ifdef FEAT_COMMENTS
5238 "comments",
5239#endif
5240#ifdef FEAT_CRYPT
5241 "cryptv",
5242#endif
5243#ifdef FEAT_CSCOPE
5244 "cscope",
5245#endif
5246#ifdef DEBUG
5247 "debug",
5248#endif
5249#ifdef FEAT_CON_DIALOG
5250 "dialog_con",
5251#endif
5252#ifdef FEAT_GUI_DIALOG
5253 "dialog_gui",
5254#endif
5255#ifdef FEAT_DIFF
5256 "diff",
5257#endif
5258#ifdef FEAT_DIGRAPHS
5259 "digraphs",
5260#endif
5261#ifdef FEAT_DND
5262 "dnd",
5263#endif
5264#ifdef FEAT_EMACS_TAGS
5265 "emacs_tags",
5266#endif
5267 "eval", /* always present, of course! */
5268#ifdef FEAT_EX_EXTRA
5269 "ex_extra",
5270#endif
5271#ifdef FEAT_SEARCH_EXTRA
5272 "extra_search",
5273#endif
5274#ifdef FEAT_FKMAP
5275 "farsi",
5276#endif
5277#ifdef FEAT_SEARCHPATH
5278 "file_in_path",
5279#endif
5280#ifdef FEAT_FIND_ID
5281 "find_in_path",
5282#endif
5283#ifdef FEAT_FOLDING
5284 "folding",
5285#endif
5286#ifdef FEAT_FOOTER
5287 "footer",
5288#endif
5289#if !defined(USE_SYSTEM) && defined(UNIX)
5290 "fork",
5291#endif
5292#ifdef FEAT_GETTEXT
5293 "gettext",
5294#endif
5295#ifdef FEAT_GUI
5296 "gui",
5297#endif
5298#ifdef FEAT_GUI_ATHENA
5299# ifdef FEAT_GUI_NEXTAW
5300 "gui_neXtaw",
5301# else
5302 "gui_athena",
5303# endif
5304#endif
5305#ifdef FEAT_GUI_BEOS
5306 "gui_beos",
5307#endif
Bram Moolenaar843ee412004-06-30 16:16:41 +00005308#ifdef FEAT_GUI_KDE
5309 "gui_kde",
5310#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005311#ifdef FEAT_GUI_GTK
5312 "gui_gtk",
5313# ifdef HAVE_GTK2
5314 "gui_gtk2",
5315# endif
5316#endif
5317#ifdef FEAT_GUI_MAC
5318 "gui_mac",
5319#endif
5320#ifdef FEAT_GUI_MOTIF
5321 "gui_motif",
5322#endif
5323#ifdef FEAT_GUI_PHOTON
5324 "gui_photon",
5325#endif
5326#ifdef FEAT_GUI_W16
5327 "gui_win16",
5328#endif
5329#ifdef FEAT_GUI_W32
5330 "gui_win32",
5331#endif
5332#ifdef FEAT_HANGULIN
5333 "hangul_input",
5334#endif
5335#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5336 "iconv",
5337#endif
5338#ifdef FEAT_INS_EXPAND
5339 "insert_expand",
5340#endif
5341#ifdef FEAT_JUMPLIST
5342 "jumplist",
5343#endif
5344#ifdef FEAT_KEYMAP
5345 "keymap",
5346#endif
5347#ifdef FEAT_LANGMAP
5348 "langmap",
5349#endif
5350#ifdef FEAT_LIBCALL
5351 "libcall",
5352#endif
5353#ifdef FEAT_LINEBREAK
5354 "linebreak",
5355#endif
5356#ifdef FEAT_LISP
5357 "lispindent",
5358#endif
5359#ifdef FEAT_LISTCMDS
5360 "listcmds",
5361#endif
5362#ifdef FEAT_LOCALMAP
5363 "localmap",
5364#endif
5365#ifdef FEAT_MENU
5366 "menu",
5367#endif
5368#ifdef FEAT_SESSION
5369 "mksession",
5370#endif
5371#ifdef FEAT_MODIFY_FNAME
5372 "modify_fname",
5373#endif
5374#ifdef FEAT_MOUSE
5375 "mouse",
5376#endif
5377#ifdef FEAT_MOUSESHAPE
5378 "mouseshape",
5379#endif
5380#if defined(UNIX) || defined(VMS)
5381# ifdef FEAT_MOUSE_DEC
5382 "mouse_dec",
5383# endif
5384# ifdef FEAT_MOUSE_GPM
5385 "mouse_gpm",
5386# endif
5387# ifdef FEAT_MOUSE_JSB
5388 "mouse_jsbterm",
5389# endif
5390# ifdef FEAT_MOUSE_NET
5391 "mouse_netterm",
5392# endif
5393# ifdef FEAT_MOUSE_PTERM
5394 "mouse_pterm",
5395# endif
5396# ifdef FEAT_MOUSE_XTERM
5397 "mouse_xterm",
5398# endif
5399#endif
5400#ifdef FEAT_MBYTE
5401 "multi_byte",
5402#endif
5403#ifdef FEAT_MBYTE_IME
5404 "multi_byte_ime",
5405#endif
5406#ifdef FEAT_MULTI_LANG
5407 "multi_lang",
5408#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005409#ifdef FEAT_MZSCHEME
5410 "mzscheme",
5411#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005412#ifdef FEAT_OLE
5413 "ole",
5414#endif
5415#ifdef FEAT_OSFILETYPE
5416 "osfiletype",
5417#endif
5418#ifdef FEAT_PATH_EXTRA
5419 "path_extra",
5420#endif
5421#ifdef FEAT_PERL
5422#ifndef DYNAMIC_PERL
5423 "perl",
5424#endif
5425#endif
5426#ifdef FEAT_PYTHON
5427#ifndef DYNAMIC_PYTHON
5428 "python",
5429#endif
5430#endif
5431#ifdef FEAT_POSTSCRIPT
5432 "postscript",
5433#endif
5434#ifdef FEAT_PRINTER
5435 "printer",
5436#endif
5437#ifdef FEAT_QUICKFIX
5438 "quickfix",
5439#endif
5440#ifdef FEAT_RIGHTLEFT
5441 "rightleft",
5442#endif
5443#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5444 "ruby",
5445#endif
5446#ifdef FEAT_SCROLLBIND
5447 "scrollbind",
5448#endif
5449#ifdef FEAT_CMDL_INFO
5450 "showcmd",
5451 "cmdline_info",
5452#endif
5453#ifdef FEAT_SIGNS
5454 "signs",
5455#endif
5456#ifdef FEAT_SMARTINDENT
5457 "smartindent",
5458#endif
5459#ifdef FEAT_SNIFF
5460 "sniff",
5461#endif
5462#ifdef FEAT_STL_OPT
5463 "statusline",
5464#endif
5465#ifdef FEAT_SUN_WORKSHOP
5466 "sun_workshop",
5467#endif
5468#ifdef FEAT_NETBEANS_INTG
5469 "netbeans_intg",
5470#endif
5471#ifdef FEAT_SYN_HL
5472 "syntax",
5473#endif
5474#if defined(USE_SYSTEM) || !defined(UNIX)
5475 "system",
5476#endif
5477#ifdef FEAT_TAG_BINS
5478 "tag_binary",
5479#endif
5480#ifdef FEAT_TAG_OLDSTATIC
5481 "tag_old_static",
5482#endif
5483#ifdef FEAT_TAG_ANYWHITE
5484 "tag_any_white",
5485#endif
5486#ifdef FEAT_TCL
5487# ifndef DYNAMIC_TCL
5488 "tcl",
5489# endif
5490#endif
5491#ifdef TERMINFO
5492 "terminfo",
5493#endif
5494#ifdef FEAT_TERMRESPONSE
5495 "termresponse",
5496#endif
5497#ifdef FEAT_TEXTOBJ
5498 "textobjects",
5499#endif
5500#ifdef HAVE_TGETENT
5501 "tgetent",
5502#endif
5503#ifdef FEAT_TITLE
5504 "title",
5505#endif
5506#ifdef FEAT_TOOLBAR
5507 "toolbar",
5508#endif
5509#ifdef FEAT_USR_CMDS
5510 "user-commands", /* was accidentally included in 5.4 */
5511 "user_commands",
5512#endif
5513#ifdef FEAT_VIMINFO
5514 "viminfo",
5515#endif
5516#ifdef FEAT_VERTSPLIT
5517 "vertsplit",
5518#endif
5519#ifdef FEAT_VIRTUALEDIT
5520 "virtualedit",
5521#endif
5522#ifdef FEAT_VISUAL
5523 "visual",
5524#endif
5525#ifdef FEAT_VISUALEXTRA
5526 "visualextra",
5527#endif
5528#ifdef FEAT_VREPLACE
5529 "vreplace",
5530#endif
5531#ifdef FEAT_WILDIGN
5532 "wildignore",
5533#endif
5534#ifdef FEAT_WILDMENU
5535 "wildmenu",
5536#endif
5537#ifdef FEAT_WINDOWS
5538 "windows",
5539#endif
5540#ifdef FEAT_WAK
5541 "winaltkeys",
5542#endif
5543#ifdef FEAT_WRITEBACKUP
5544 "writebackup",
5545#endif
5546#ifdef FEAT_XIM
5547 "xim",
5548#endif
5549#ifdef FEAT_XFONTSET
5550 "xfontset",
5551#endif
5552#ifdef USE_XSMP
5553 "xsmp",
5554#endif
5555#ifdef USE_XSMP_INTERACT
5556 "xsmp_interact",
5557#endif
5558#ifdef FEAT_XCLIPBOARD
5559 "xterm_clipboard",
5560#endif
5561#ifdef FEAT_XTERM_SAVE
5562 "xterm_save",
5563#endif
5564#if defined(UNIX) && defined(FEAT_X11)
5565 "X11",
5566#endif
5567 NULL
5568 };
5569
5570 name = get_var_string(&argvars[0]);
5571 for (i = 0; has_list[i] != NULL; ++i)
5572 if (STRICMP(name, has_list[i]) == 0)
5573 {
5574 n = TRUE;
5575 break;
5576 }
5577
5578 if (n == FALSE)
5579 {
5580 if (STRNICMP(name, "patch", 5) == 0)
5581 n = has_patch(atoi((char *)name + 5));
5582 else if (STRICMP(name, "vim_starting") == 0)
5583 n = (starting != 0);
5584#ifdef DYNAMIC_TCL
5585 else if (STRICMP(name, "tcl") == 0)
5586 n = tcl_enabled(FALSE);
5587#endif
5588#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5589 else if (STRICMP(name, "iconv") == 0)
5590 n = iconv_enabled(FALSE);
5591#endif
5592#ifdef DYNAMIC_RUBY
5593 else if (STRICMP(name, "ruby") == 0)
5594 n = ruby_enabled(FALSE);
5595#endif
5596#ifdef DYNAMIC_PYTHON
5597 else if (STRICMP(name, "python") == 0)
5598 n = python_enabled(FALSE);
5599#endif
5600#ifdef DYNAMIC_PERL
5601 else if (STRICMP(name, "perl") == 0)
5602 n = perl_enabled(FALSE);
5603#endif
5604#ifdef FEAT_GUI
5605 else if (STRICMP(name, "gui_running") == 0)
5606 n = (gui.in_use || gui.starting);
5607# ifdef FEAT_GUI_W32
5608 else if (STRICMP(name, "gui_win32s") == 0)
5609 n = gui_is_win32s();
5610# endif
5611# ifdef FEAT_BROWSE
5612 else if (STRICMP(name, "browse") == 0)
5613 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5614# endif
5615#endif
5616#ifdef FEAT_SYN_HL
5617 else if (STRICMP(name, "syntax_items") == 0)
5618 n = syntax_present(curbuf);
5619#endif
5620#if defined(WIN3264)
5621 else if (STRICMP(name, "win95") == 0)
5622 n = mch_windows95();
5623#endif
Bram Moolenaar35a9aaa2004-10-24 19:23:07 +00005624#ifdef FEAT_NETBEANS_INTG
5625 else if (STRICMP(name, "netbeans_enabled") == 0)
5626 n = usingNetbeans;
5627#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005628 }
5629
5630 retvar->var_val.var_number = n;
5631}
5632
5633/*
5634 * "hasmapto()" function
5635 */
5636 static void
5637f_hasmapto(argvars, retvar)
5638 VAR argvars;
5639 VAR retvar;
5640{
5641 char_u *name;
5642 char_u *mode;
5643 char_u buf[NUMBUFLEN];
5644
5645 name = get_var_string(&argvars[0]);
5646 if (argvars[1].var_type == VAR_UNKNOWN)
5647 mode = (char_u *)"nvo";
5648 else
5649 mode = get_var_string_buf(&argvars[1], buf);
5650
5651 if (map_to_exists(name, mode))
5652 retvar->var_val.var_number = TRUE;
5653 else
5654 retvar->var_val.var_number = FALSE;
5655}
5656
5657/*
5658 * "histadd()" function
5659 */
5660/*ARGSUSED*/
5661 static void
5662f_histadd(argvars, retvar)
5663 VAR argvars;
5664 VAR retvar;
5665{
5666#ifdef FEAT_CMDHIST
5667 int histype;
5668 char_u *str;
5669 char_u buf[NUMBUFLEN];
5670#endif
5671
5672 retvar->var_val.var_number = FALSE;
5673 if (check_restricted() || check_secure())
5674 return;
5675#ifdef FEAT_CMDHIST
5676 histype = get_histtype(get_var_string(&argvars[0]));
5677 if (histype >= 0)
5678 {
5679 str = get_var_string_buf(&argvars[1], buf);
5680 if (*str != NUL)
5681 {
5682 add_to_history(histype, str, FALSE, NUL);
5683 retvar->var_val.var_number = TRUE;
5684 return;
5685 }
5686 }
5687#endif
5688}
5689
5690/*
5691 * "histdel()" function
5692 */
5693/*ARGSUSED*/
5694 static void
5695f_histdel(argvars, retvar)
5696 VAR argvars;
5697 VAR retvar;
5698{
5699#ifdef FEAT_CMDHIST
5700 int n;
5701 char_u buf[NUMBUFLEN];
5702
5703 if (argvars[1].var_type == VAR_UNKNOWN)
5704 /* only one argument: clear entire history */
5705 n = clr_history(get_histtype(get_var_string(&argvars[0])));
5706 else if (argvars[1].var_type == VAR_NUMBER)
5707 /* index given: remove that entry */
5708 n = del_history_idx(get_histtype(get_var_string(&argvars[0])),
5709 (int)get_var_number(&argvars[1]));
5710 else
5711 /* string given: remove all matching entries */
5712 n = del_history_entry(get_histtype(get_var_string(&argvars[0])),
5713 get_var_string_buf(&argvars[1], buf));
5714 retvar->var_val.var_number = n;
5715#else
5716 retvar->var_val.var_number = 0;
5717#endif
5718}
5719
5720/*
5721 * "histget()" function
5722 */
5723/*ARGSUSED*/
5724 static void
5725f_histget(argvars, retvar)
5726 VAR argvars;
5727 VAR retvar;
5728{
5729#ifdef FEAT_CMDHIST
5730 int type;
5731 int idx;
5732
5733 type = get_histtype(get_var_string(&argvars[0]));
5734 if (argvars[1].var_type == VAR_UNKNOWN)
5735 idx = get_history_idx(type);
5736 else
5737 idx = (int)get_var_number(&argvars[1]);
5738 retvar->var_val.var_string = vim_strsave(get_history_entry(type, idx));
5739#else
5740 retvar->var_val.var_string = NULL;
5741#endif
5742 retvar->var_type = VAR_STRING;
5743}
5744
5745/*
5746 * "histnr()" function
5747 */
5748/*ARGSUSED*/
5749 static void
5750f_histnr(argvars, retvar)
5751 VAR argvars;
5752 VAR retvar;
5753{
5754 int i;
5755
5756#ifdef FEAT_CMDHIST
5757 i = get_histtype(get_var_string(&argvars[0]));
5758 if (i >= HIST_CMD && i < HIST_COUNT)
5759 i = get_history_idx(i);
5760 else
5761#endif
5762 i = -1;
5763 retvar->var_val.var_number = i;
5764}
5765
5766/*
5767 * "highlight_exists()" function
5768 */
5769 static void
5770f_hlexists(argvars, retvar)
5771 VAR argvars;
5772 VAR retvar;
5773{
5774 retvar->var_val.var_number = highlight_exists(get_var_string(&argvars[0]));
5775}
5776
5777/*
5778 * "highlightID(name)" function
5779 */
5780 static void
5781f_hlID(argvars, retvar)
5782 VAR argvars;
5783 VAR retvar;
5784{
5785 retvar->var_val.var_number = syn_name2id(get_var_string(&argvars[0]));
5786}
5787
5788/*
5789 * "hostname()" function
5790 */
5791/*ARGSUSED*/
5792 static void
5793f_hostname(argvars, retvar)
5794 VAR argvars;
5795 VAR retvar;
5796{
5797 char_u hostname[256];
5798
5799 mch_get_host_name(hostname, 256);
5800 retvar->var_type = VAR_STRING;
5801 retvar->var_val.var_string = vim_strsave(hostname);
5802}
5803
5804/*
5805 * iconv() function
5806 */
5807/*ARGSUSED*/
5808 static void
5809f_iconv(argvars, retvar)
5810 VAR argvars;
5811 VAR retvar;
5812{
5813#ifdef FEAT_MBYTE
5814 char_u buf1[NUMBUFLEN];
5815 char_u buf2[NUMBUFLEN];
5816 char_u *from, *to, *str;
5817 vimconv_T vimconv;
5818#endif
5819
5820 retvar->var_type = VAR_STRING;
5821 retvar->var_val.var_string = NULL;
5822
5823#ifdef FEAT_MBYTE
5824 str = get_var_string(&argvars[0]);
5825 from = enc_canonize(enc_skip(get_var_string_buf(&argvars[1], buf1)));
5826 to = enc_canonize(enc_skip(get_var_string_buf(&argvars[2], buf2)));
5827 vimconv.vc_type = CONV_NONE;
5828 convert_setup(&vimconv, from, to);
5829
5830 /* If the encodings are equal, no conversion needed. */
5831 if (vimconv.vc_type == CONV_NONE)
5832 retvar->var_val.var_string = vim_strsave(str);
5833 else
5834 retvar->var_val.var_string = string_convert(&vimconv, str, NULL);
5835
5836 convert_setup(&vimconv, NULL, NULL);
5837 vim_free(from);
5838 vim_free(to);
5839#endif
5840}
5841
5842/*
5843 * "indent()" function
5844 */
5845 static void
5846f_indent(argvars, retvar)
5847 VAR argvars;
5848 VAR retvar;
5849{
5850 linenr_T lnum;
5851
5852 lnum = get_var_lnum(argvars);
5853 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5854 retvar->var_val.var_number = get_indent_lnum(lnum);
5855 else
5856 retvar->var_val.var_number = -1;
5857}
5858
5859static int inputsecret_flag = 0;
5860
5861/*
5862 * "input()" function
5863 * Also handles inputsecret() when inputsecret is set.
5864 */
5865 static void
5866f_input(argvars, retvar)
5867 VAR argvars;
5868 VAR retvar;
5869{
5870 char_u *prompt = get_var_string(&argvars[0]);
5871 char_u *p = NULL;
5872 int c;
5873 char_u buf[NUMBUFLEN];
5874 int cmd_silent_save = cmd_silent;
5875
5876 retvar->var_type = VAR_STRING;
5877
5878#ifdef NO_CONSOLE_INPUT
5879 /* While starting up, there is no place to enter text. */
5880 if (no_console_input())
5881 {
5882 retvar->var_val.var_string = NULL;
5883 return;
5884 }
5885#endif
5886
5887 cmd_silent = FALSE; /* Want to see the prompt. */
5888 if (prompt != NULL)
5889 {
5890 /* Only the part of the message after the last NL is considered as
5891 * prompt for the command line */
5892 p = vim_strrchr(prompt, '\n');
5893 if (p == NULL)
5894 p = prompt;
5895 else
5896 {
5897 ++p;
5898 c = *p;
5899 *p = NUL;
5900 msg_start();
5901 msg_clr_eos();
5902 msg_puts_attr(prompt, echo_attr);
5903 msg_didout = FALSE;
5904 msg_starthere();
5905 *p = c;
5906 }
5907 cmdline_row = msg_row;
5908 }
5909
5910 if (argvars[1].var_type != VAR_UNKNOWN)
5911 stuffReadbuffSpec(get_var_string_buf(&argvars[1], buf));
5912
5913 retvar->var_val.var_string =
5914 getcmdline_prompt(inputsecret_flag ? NUL : '@', p, echo_attr);
5915
5916 /* since the user typed this, no need to wait for return */
5917 need_wait_return = FALSE;
5918 msg_didout = FALSE;
5919 cmd_silent = cmd_silent_save;
5920}
5921
5922/*
5923 * "inputdialog()" function
5924 */
5925 static void
5926f_inputdialog(argvars, retvar)
5927 VAR argvars;
5928 VAR retvar;
5929{
5930#if defined(FEAT_GUI_TEXTDIALOG)
5931 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5932 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5933 {
5934 char_u *message;
5935 char_u buf[NUMBUFLEN];
5936
5937 message = get_var_string(&argvars[0]);
5938 if (argvars[1].var_type != VAR_UNKNOWN)
5939 {
5940 STRNCPY(IObuff, get_var_string_buf(&argvars[1], buf), IOSIZE);
5941 IObuff[IOSIZE - 1] = NUL;
5942 }
5943 else
5944 IObuff[0] = NUL;
5945 if (do_dialog(VIM_QUESTION, NULL, message, (char_u *)_("&OK\n&Cancel"),
5946 1, IObuff) == 1)
5947 retvar->var_val.var_string = vim_strsave(IObuff);
5948 else
5949 {
5950 if (argvars[1].var_type != VAR_UNKNOWN
5951 && argvars[2].var_type != VAR_UNKNOWN)
5952 retvar->var_val.var_string = vim_strsave(
5953 get_var_string_buf(&argvars[2], buf));
5954 else
5955 retvar->var_val.var_string = NULL;
5956 }
5957 retvar->var_type = VAR_STRING;
5958 }
5959 else
5960#endif
5961 f_input(argvars, retvar);
5962}
5963
5964static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5965
5966/*
5967 * "inputrestore()" function
5968 */
5969/*ARGSUSED*/
5970 static void
5971f_inputrestore(argvars, retvar)
5972 VAR argvars;
5973 VAR retvar;
5974{
5975 if (ga_userinput.ga_len > 0)
5976 {
5977 --ga_userinput.ga_len;
5978 ++ga_userinput.ga_room;
5979 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5980 + ga_userinput.ga_len);
5981 retvar->var_val.var_number = 0; /* OK */
5982 }
5983 else if (p_verbose > 1)
5984 {
5985 msg((char_u *)_("called inputrestore() more often than inputsave()"));
5986 retvar->var_val.var_number = 1; /* Failed */
5987 }
5988}
5989
5990/*
5991 * "inputsave()" function
5992 */
5993/*ARGSUSED*/
5994 static void
5995f_inputsave(argvars, retvar)
5996 VAR argvars;
5997 VAR retvar;
5998{
5999 /* Add an entry to the stack of typehead storage. */
6000 if (ga_grow(&ga_userinput, 1) == OK)
6001 {
6002 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6003 + ga_userinput.ga_len);
6004 ++ga_userinput.ga_len;
6005 --ga_userinput.ga_room;
6006 retvar->var_val.var_number = 0; /* OK */
6007 }
6008 else
6009 retvar->var_val.var_number = 1; /* Failed */
6010}
6011
6012/*
6013 * "inputsecret()" function
6014 */
6015 static void
6016f_inputsecret(argvars, retvar)
6017 VAR argvars;
6018 VAR retvar;
6019{
6020 ++cmdline_star;
6021 ++inputsecret_flag;
6022 f_input(argvars, retvar);
6023 --cmdline_star;
6024 --inputsecret_flag;
6025}
6026
6027/*
6028 * "isdirectory()" function
6029 */
6030 static void
6031f_isdirectory(argvars, retvar)
6032 VAR argvars;
6033 VAR retvar;
6034{
6035 retvar->var_val.var_number = mch_isdir(get_var_string(&argvars[0]));
6036}
6037
6038/*
6039 * "last_buffer_nr()" function.
6040 */
6041/*ARGSUSED*/
6042 static void
6043f_last_buffer_nr(argvars, retvar)
6044 VAR argvars;
6045 VAR retvar;
6046{
6047 int n = 0;
6048 buf_T *buf;
6049
6050 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
6051 if (n < buf->b_fnum)
6052 n = buf->b_fnum;
6053
6054 retvar->var_val.var_number = n;
6055}
6056
6057/*
6058 * "line(string)" function
6059 */
6060 static void
6061f_line(argvars, retvar)
6062 VAR argvars;
6063 VAR retvar;
6064{
6065 linenr_T lnum = 0;
6066 pos_T *fp;
6067
6068 fp = var2fpos(&argvars[0], TRUE);
6069 if (fp != NULL)
6070 lnum = fp->lnum;
6071 retvar->var_val.var_number = lnum;
6072}
6073
6074/*
6075 * "line2byte(lnum)" function
6076 */
6077/*ARGSUSED*/
6078 static void
6079f_line2byte(argvars, retvar)
6080 VAR argvars;
6081 VAR retvar;
6082{
6083#ifndef FEAT_BYTEOFF
6084 retvar->var_val.var_number = -1;
6085#else
6086 linenr_T lnum;
6087
6088 lnum = get_var_lnum(argvars);
6089 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6090 retvar->var_val.var_number = -1;
6091 else
6092 retvar->var_val.var_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6093 if (retvar->var_val.var_number >= 0)
6094 ++retvar->var_val.var_number;
6095#endif
6096}
6097
6098/*
6099 * "lispindent(lnum)" function
6100 */
6101 static void
6102f_lispindent(argvars, retvar)
6103 VAR argvars;
6104 VAR retvar;
6105{
6106#ifdef FEAT_LISP
6107 pos_T pos;
6108 linenr_T lnum;
6109
6110 pos = curwin->w_cursor;
6111 lnum = get_var_lnum(argvars);
6112 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6113 {
6114 curwin->w_cursor.lnum = lnum;
6115 retvar->var_val.var_number = get_lisp_indent();
6116 curwin->w_cursor = pos;
6117 }
6118 else
6119#endif
6120 retvar->var_val.var_number = -1;
6121}
6122
6123/*
6124 * "localtime()" function
6125 */
6126/*ARGSUSED*/
6127 static void
6128f_localtime(argvars, retvar)
6129 VAR argvars;
6130 VAR retvar;
6131{
6132 retvar->var_val.var_number = (varnumber_T)time(NULL);
6133}
6134
6135/*
6136 * "maparg()" function
6137 */
6138 static void
6139f_maparg(argvars, retvar)
6140 VAR argvars;
6141 VAR retvar;
6142{
6143 get_maparg(argvars, retvar, TRUE);
6144}
6145
6146/*
6147 * "mapcheck()" function
6148 */
6149 static void
6150f_mapcheck(argvars, retvar)
6151 VAR argvars;
6152 VAR retvar;
6153{
6154 get_maparg(argvars, retvar, FALSE);
6155}
6156
6157 static void
6158get_maparg(argvars, retvar, exact)
6159 VAR argvars;
6160 VAR retvar;
6161 int exact;
6162{
6163 char_u *keys;
6164 char_u *which;
6165 char_u buf[NUMBUFLEN];
6166 char_u *keys_buf = NULL;
6167 char_u *rhs;
6168 int mode;
6169 garray_T ga;
6170
6171 /* return empty string for failure */
6172 retvar->var_type = VAR_STRING;
6173 retvar->var_val.var_string = NULL;
6174
6175 keys = get_var_string(&argvars[0]);
6176 if (*keys == NUL)
6177 return;
6178
6179 if (argvars[1].var_type != VAR_UNKNOWN)
6180 which = get_var_string_buf(&argvars[1], buf);
6181 else
6182 which = (char_u *)"";
6183 mode = get_map_mode(&which, 0);
6184
6185 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE);
6186 rhs = check_map(keys, mode, exact);
6187 vim_free(keys_buf);
6188 if (rhs != NULL)
6189 {
6190 ga_init(&ga);
6191 ga.ga_itemsize = 1;
6192 ga.ga_growsize = 40;
6193
6194 while (*rhs != NUL)
6195 ga_concat(&ga, str2special(&rhs, FALSE));
6196
6197 ga_append(&ga, NUL);
6198 retvar->var_val.var_string = (char_u *)ga.ga_data;
6199 }
6200}
6201
6202/*
6203 * "match()" function
6204 */
6205 static void
6206f_match(argvars, retvar)
6207 VAR argvars;
6208 VAR retvar;
6209{
6210 find_some_match(argvars, retvar, 1);
6211}
6212
6213/*
6214 * "matchend()" function
6215 */
6216 static void
6217f_matchend(argvars, retvar)
6218 VAR argvars;
6219 VAR retvar;
6220{
6221 find_some_match(argvars, retvar, 0);
6222}
6223
6224/*
6225 * "matchstr()" function
6226 */
6227 static void
6228f_matchstr(argvars, retvar)
6229 VAR argvars;
6230 VAR retvar;
6231{
6232 find_some_match(argvars, retvar, 2);
6233}
6234
6235 static void
6236find_some_match(argvars, retvar, type)
6237 VAR argvars;
6238 VAR retvar;
6239 int type;
6240{
6241 char_u *str;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00006242 char_u *expr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006243 char_u *pat;
6244 regmatch_T regmatch;
6245 char_u patbuf[NUMBUFLEN];
6246 char_u *save_cpo;
6247 long start = 0;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00006248 long nth = 1;
6249 int match;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006250
6251 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6252 save_cpo = p_cpo;
6253 p_cpo = (char_u *)"";
6254
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00006255 expr = str = get_var_string(&argvars[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006256 pat = get_var_string_buf(&argvars[1], patbuf);
6257
6258 if (type == 2)
6259 {
6260 retvar->var_type = VAR_STRING;
6261 retvar->var_val.var_string = NULL;
6262 }
6263 else
6264 retvar->var_val.var_number = -1;
6265
6266 if (argvars[2].var_type != VAR_UNKNOWN)
6267 {
6268 start = get_var_number(&argvars[2]);
6269 if (start < 0)
6270 start = 0;
6271 if (start > (long)STRLEN(str))
6272 goto theend;
6273 str += start;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00006274
6275 if (argvars[3].var_type != VAR_UNKNOWN)
6276 nth = get_var_number(&argvars[3]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277 }
6278
6279 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6280 if (regmatch.regprog != NULL)
6281 {
6282 regmatch.rm_ic = p_ic;
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00006283
6284 while (1)
6285 {
6286 match = vim_regexec_nl(&regmatch, str, (colnr_T)0);
6287 if (!match || --nth <= 0)
6288 break;
6289 /* Advance to just after the match. */
6290#ifdef FEAT_MBYTE
6291 str = regmatch.startp[0] + mb_ptr2len_check(regmatch.startp[0]);
6292#else
6293 str = regmatch.startp[0] + 1;
6294#endif
6295 }
6296
6297 if (match)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006298 {
6299 if (type == 2)
6300 retvar->var_val.var_string = vim_strnsave(regmatch.startp[0],
6301 (int)(regmatch.endp[0] - regmatch.startp[0]));
6302 else
6303 {
6304 if (type != 0)
6305 retvar->var_val.var_number =
6306 (varnumber_T)(regmatch.startp[0] - str);
6307 else
6308 retvar->var_val.var_number =
6309 (varnumber_T)(regmatch.endp[0] - str);
Bram Moolenaar89cb5e02004-07-19 20:55:54 +00006310 retvar->var_val.var_number += str - expr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311 }
6312 }
6313 vim_free(regmatch.regprog);
6314 }
6315
6316theend:
6317 p_cpo = save_cpo;
6318}
6319
6320/*
6321 * "mode()" function
6322 */
6323/*ARGSUSED*/
6324 static void
6325f_mode(argvars, retvar)
6326 VAR argvars;
6327 VAR retvar;
6328{
6329 char_u buf[2];
6330
6331#ifdef FEAT_VISUAL
6332 if (VIsual_active)
6333 {
6334 if (VIsual_select)
6335 buf[0] = VIsual_mode + 's' - 'v';
6336 else
6337 buf[0] = VIsual_mode;
6338 }
6339 else
6340#endif
6341 if (State == HITRETURN || State == ASKMORE || State == SETWSIZE)
6342 buf[0] = 'r';
6343 else if (State & INSERT)
6344 {
6345 if (State & REPLACE_FLAG)
6346 buf[0] = 'R';
6347 else
6348 buf[0] = 'i';
6349 }
6350 else if (State & CMDLINE)
6351 buf[0] = 'c';
6352 else
6353 buf[0] = 'n';
6354
6355 buf[1] = NUL;
6356 retvar->var_val.var_string = vim_strsave(buf);
6357 retvar->var_type = VAR_STRING;
6358}
6359
6360/*
6361 * "nr2char()" function
6362 */
6363 static void
6364f_nr2char(argvars, retvar)
6365 VAR argvars;
6366 VAR retvar;
6367{
6368 char_u buf[NUMBUFLEN];
6369
6370#ifdef FEAT_MBYTE
6371 if (has_mbyte)
6372 buf[(*mb_char2bytes)((int)get_var_number(&argvars[0]), buf)] = NUL;
6373 else
6374#endif
6375 {
6376 buf[0] = (char_u)get_var_number(&argvars[0]);
6377 buf[1] = NUL;
6378 }
6379 retvar->var_type = VAR_STRING;
6380 retvar->var_val.var_string = vim_strsave(buf);
6381}
6382
6383/*
6384 * "rename({from}, {to})" function
6385 */
6386 static void
6387f_rename(argvars, retvar)
6388 VAR argvars;
6389 VAR retvar;
6390{
6391 char_u buf[NUMBUFLEN];
6392
6393 if (check_restricted() || check_secure())
6394 retvar->var_val.var_number = -1;
6395 else
6396 retvar->var_val.var_number = vim_rename(get_var_string(&argvars[0]),
6397 get_var_string_buf(&argvars[1], buf));
6398}
6399
6400/*
6401 * "resolve()" function
6402 */
6403 static void
6404f_resolve(argvars, retvar)
6405 VAR argvars;
6406 VAR retvar;
6407{
6408 char_u *p;
6409
6410 p = get_var_string(&argvars[0]);
6411#ifdef FEAT_SHORTCUT
6412 {
6413 char_u *v = NULL;
6414
6415 v = mch_resolve_shortcut(p);
6416 if (v != NULL)
6417 retvar->var_val.var_string = v;
6418 else
6419 retvar->var_val.var_string = vim_strsave(p);
6420 }
6421#else
6422# ifdef HAVE_READLINK
6423 {
6424 char_u buf[MAXPATHL + 1];
6425 char_u *cpy;
6426 int len;
6427 char_u *remain = NULL;
6428 char_u *q;
6429 int is_relative_to_current = FALSE;
6430 int has_trailing_pathsep = FALSE;
6431 int limit = 100;
6432
6433 p = vim_strsave(p);
6434
6435 if (p[0] == '.' && (vim_ispathsep(p[1])
6436 || (p[1] == '.' && (vim_ispathsep(p[2])))))
6437 is_relative_to_current = TRUE;
6438
6439 len = STRLEN(p);
6440 if (len > 0 && vim_ispathsep(p[len-1]))
6441 has_trailing_pathsep = TRUE;
6442
6443 q = getnextcomp(p);
6444 if (*q != NUL)
6445 {
6446 /* Separate the first path component in "p", and keep the
6447 * remainder (beginning with the path separator). */
6448 remain = vim_strsave(q - 1);
6449 q[-1] = NUL;
6450 }
6451
6452 for (;;)
6453 {
6454 for (;;)
6455 {
6456 len = readlink((char *)p, (char *)buf, MAXPATHL);
6457 if (len <= 0)
6458 break;
6459 buf[len] = NUL;
6460
6461 if (limit-- == 0)
6462 {
6463 vim_free(p);
6464 vim_free(remain);
6465 EMSG(_("E655: Too many symbolic links (cycle?)"));
6466 retvar->var_val.var_string = NULL;
6467 goto fail;
6468 }
6469
6470 /* Ensure that the result will have a trailing path separator
6471 * if the argument has one. */
6472 if (remain == NULL && has_trailing_pathsep)
6473 add_pathsep(buf);
6474
6475 /* Separate the first path component in the link value and
6476 * concatenate the remainders. */
6477 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
6478 if (*q != NUL)
6479 {
6480 if (remain == NULL)
6481 remain = vim_strsave(q - 1);
6482 else
6483 {
6484 cpy = vim_strnsave(q-1, STRLEN(q-1)+STRLEN(remain));
6485 if (cpy != NULL)
6486 {
6487 STRCAT(cpy, remain);
6488 vim_free(remain);
6489 remain = cpy;
6490 }
6491 }
6492 q[-1] = NUL;
6493 }
6494
6495 q = gettail(p);
6496 if (q > p && *q == NUL)
6497 {
6498 /* Ignore trailing path separator. */
6499 q[-1] = NUL;
6500 q = gettail(p);
6501 }
6502 if (q > p && !mch_isFullName(buf))
6503 {
6504 /* symlink is relative to directory of argument */
6505 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
6506 if (cpy != NULL)
6507 {
6508 STRCPY(cpy, p);
6509 STRCPY(gettail(cpy), buf);
6510 vim_free(p);
6511 p = cpy;
6512 }
6513 }
6514 else
6515 {
6516 vim_free(p);
6517 p = vim_strsave(buf);
6518 }
6519 }
6520
6521 if (remain == NULL)
6522 break;
6523
6524 /* Append the first path component of "remain" to "p". */
6525 q = getnextcomp(remain + 1);
6526 len = q - remain - (*q != NUL);
6527 cpy = vim_strnsave(p, STRLEN(p) + len);
6528 if (cpy != NULL)
6529 {
6530 STRNCAT(cpy, remain, len);
6531 vim_free(p);
6532 p = cpy;
6533 }
6534 /* Shorten "remain". */
6535 if (*q != NUL)
6536 STRCPY(remain, q - 1);
6537 else
6538 {
6539 vim_free(remain);
6540 remain = NULL;
6541 }
6542 }
6543
6544 /* If the result is a relative path name, make it explicitly relative to
6545 * the current directory if and only if the argument had this form. */
6546 if (!vim_ispathsep(*p))
6547 {
6548 if (is_relative_to_current
6549 && *p != NUL
6550 && !(p[0] == '.'
6551 && (p[1] == NUL
6552 || vim_ispathsep(p[1])
6553 || (p[1] == '.'
6554 && (p[2] == NUL
6555 || vim_ispathsep(p[2]))))))
6556 {
6557 /* Prepend "./". */
6558 cpy = vim_strnsave((char_u *)"./", 2 + STRLEN(p));
6559 if (cpy != NULL)
6560 {
6561 STRCAT(cpy, p);
6562 vim_free(p);
6563 p = cpy;
6564 }
6565 }
6566 else if (!is_relative_to_current)
6567 {
6568 /* Strip leading "./". */
6569 q = p;
6570 while (q[0] == '.' && vim_ispathsep(q[1]))
6571 q += 2;
6572 if (q > p)
6573 mch_memmove(p, p + 2, STRLEN(p + 2) + (size_t)1);
6574 }
6575 }
6576
6577 /* Ensure that the result will have no trailing path separator
6578 * if the argument had none. But keep "/" or "//". */
6579 if (!has_trailing_pathsep)
6580 {
6581 q = p + STRLEN(p);
6582 while ((q > p + 2 || (q == p + 2 && !vim_ispathsep(*p)))
6583 && vim_ispathsep(q[-1]))
6584 --q;
6585 *q = NUL;
6586 }
6587
6588 retvar->var_val.var_string = p;
6589 }
6590# else
6591 retvar->var_val.var_string = vim_strsave(p);
6592# endif
6593#endif
6594
6595 simplify_filename(retvar->var_val.var_string);
6596
6597#ifdef HAVE_READLINK
6598fail:
6599#endif
6600 retvar->var_type = VAR_STRING;
6601}
6602
6603/*
6604 * "simplify()" function
6605 */
6606 static void
6607f_simplify(argvars, retvar)
6608 VAR argvars;
6609 VAR retvar;
6610{
6611 char_u *p;
6612
6613 p = get_var_string(&argvars[0]);
6614 retvar->var_val.var_string = vim_strsave(p);
6615 simplify_filename(retvar->var_val.var_string); /* simplify in place */
6616 retvar->var_type = VAR_STRING;
6617}
6618
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006619#define SP_NOMOVE 1 /* don't move cursor */
6620#define SP_REPEAT 2 /* repeat to find outer pair */
6621#define SP_RETCOUNT 4 /* return matchcount */
6622
Bram Moolenaar071d4272004-06-13 20:20:40 +00006623/*
6624 * "search()" function
6625 */
6626 static void
6627f_search(argvars, retvar)
6628 VAR argvars;
6629 VAR retvar;
6630{
6631 char_u *pat;
6632 pos_T pos;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006633 pos_T save_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006634 int save_p_ws = p_ws;
6635 int dir;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006636 int flags = 0;
6637
6638 retvar->var_val.var_number = 0; /* default: FAIL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006639
6640 pat = get_var_string(&argvars[0]);
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006641 dir = get_search_arg(&argvars[1], &flags); /* may set p_ws */
6642 if (dir == 0)
6643 goto theend;
6644 if ((flags & ~SP_NOMOVE) != 0)
6645 {
6646 EMSG2(_(e_invarg2), get_var_string(&argvars[1]));
6647 goto theend;
6648 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006650 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006651 if (searchit(curwin, curbuf, &pos, dir, pat, 1L,
6652 SEARCH_KEEP, RE_SEARCH) != FAIL)
6653 {
6654 retvar->var_val.var_number = pos.lnum;
6655 curwin->w_cursor = pos;
6656 /* "/$" will put the cursor after the end of the line, may need to
6657 * correct that here */
6658 check_cursor();
6659 }
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006660
6661 /* If 'n' flag is used: restore cursor position. */
6662 if (flags & SP_NOMOVE)
6663 curwin->w_cursor = save_cursor;
6664theend:
Bram Moolenaar071d4272004-06-13 20:20:40 +00006665 p_ws = save_p_ws;
6666}
6667
Bram Moolenaar071d4272004-06-13 20:20:40 +00006668/*
6669 * "searchpair()" function
6670 */
6671 static void
6672f_searchpair(argvars, retvar)
6673 VAR argvars;
6674 VAR retvar;
6675{
6676 char_u *spat, *mpat, *epat;
6677 char_u *skip;
6678 char_u *pat, *pat2, *pat3;
6679 pos_T pos;
6680 pos_T firstpos;
6681 pos_T save_cursor;
6682 pos_T save_pos;
6683 int save_p_ws = p_ws;
6684 char_u *save_cpo;
6685 int dir;
6686 int flags = 0;
6687 char_u nbuf1[NUMBUFLEN];
6688 char_u nbuf2[NUMBUFLEN];
6689 char_u nbuf3[NUMBUFLEN];
6690 int n;
6691 int r;
6692 int nest = 1;
6693 int err;
6694
6695 retvar->var_val.var_number = 0; /* default: FAIL */
6696
6697 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6698 save_cpo = p_cpo;
6699 p_cpo = (char_u *)"";
6700
6701 /* Get the three pattern arguments: start, middle, end. */
6702 spat = get_var_string(&argvars[0]);
6703 mpat = get_var_string_buf(&argvars[1], nbuf1);
6704 epat = get_var_string_buf(&argvars[2], nbuf2);
6705
6706 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6707 * start/middle/end (pat3, for the top pair). */
6708 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 15));
6709 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 23));
6710 if (pat2 == NULL || pat3 == NULL)
6711 goto theend;
6712 sprintf((char *)pat2, "\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
6713 if (*mpat == NUL)
6714 STRCPY(pat3, pat2);
6715 else
6716 sprintf((char *)pat3, "\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
6717 spat, epat, mpat);
6718
6719 /* Handle the optional fourth argument: flags */
6720 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006721 if (dir == 0)
6722 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006723
6724 /* Optional fifth argument: skip expresion */
6725 if (argvars[3].var_type == VAR_UNKNOWN
6726 || argvars[4].var_type == VAR_UNKNOWN)
6727 skip = (char_u *)"";
6728 else
6729 skip = get_var_string_buf(&argvars[4], nbuf3);
6730
6731 save_cursor = curwin->w_cursor;
6732 pos = curwin->w_cursor;
6733 firstpos.lnum = 0;
6734 pat = pat3;
6735 for (;;)
6736 {
6737 n = searchit(curwin, curbuf, &pos, dir, pat, 1L,
6738 SEARCH_KEEP, RE_SEARCH);
6739 if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos)))
6740 /* didn't find it or found the first match again: FAIL */
6741 break;
6742
6743 if (firstpos.lnum == 0)
6744 firstpos = pos;
6745
6746 /* If the skip pattern matches, ignore this match. */
6747 if (*skip != NUL)
6748 {
6749 save_pos = curwin->w_cursor;
6750 curwin->w_cursor = pos;
6751 r = eval_to_bool(skip, &err, NULL, FALSE);
6752 curwin->w_cursor = save_pos;
6753 if (err)
6754 {
6755 /* Evaluating {skip} caused an error, break here. */
6756 curwin->w_cursor = save_cursor;
6757 retvar->var_val.var_number = -1;
6758 break;
6759 }
6760 if (r)
6761 continue;
6762 }
6763
6764 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6765 {
6766 /* Found end when searching backwards or start when searching
6767 * forward: nested pair. */
6768 ++nest;
6769 pat = pat2; /* nested, don't search for middle */
6770 }
6771 else
6772 {
6773 /* Found end when searching forward or start when searching
6774 * backward: end of (nested) pair; or found middle in outer pair. */
6775 if (--nest == 1)
6776 pat = pat3; /* outer level, search for middle */
6777 }
6778
6779 if (nest == 0)
6780 {
6781 /* Found the match: return matchcount or line number. */
6782 if (flags & SP_RETCOUNT)
6783 ++retvar->var_val.var_number;
6784 else
6785 retvar->var_val.var_number = pos.lnum;
6786 curwin->w_cursor = pos;
6787 if (!(flags & SP_REPEAT))
6788 break;
6789 nest = 1; /* search for next unmatched */
6790 }
6791 }
6792
6793 /* If 'n' flag is used or search failed: restore cursor position. */
6794 if ((flags & SP_NOMOVE) || retvar->var_val.var_number == 0)
6795 curwin->w_cursor = save_cursor;
6796
6797theend:
6798 vim_free(pat2);
6799 vim_free(pat3);
6800 p_ws = save_p_ws;
6801 p_cpo = save_cpo;
6802}
6803
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006804/*
6805 * Get flags for a search function.
6806 * Possibly sets "p_ws".
6807 * Returns BACKWARD, FORWARD or zero (for an error).
6808 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 static int
6810get_search_arg(varp, flagsp)
6811 VAR varp;
6812 int *flagsp;
6813{
6814 int dir = FORWARD;
6815 char_u *flags;
6816 char_u nbuf[NUMBUFLEN];
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006817 int mask;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006818
6819 if (varp->var_type != VAR_UNKNOWN)
6820 {
6821 flags = get_var_string_buf(varp, nbuf);
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006822 while (*flags != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 {
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00006824 switch (*flags)
6825 {
6826 case 'b': dir = BACKWARD; break;
6827 case 'w': p_ws = TRUE; break;
6828 case 'W': p_ws = FALSE; break;
6829 default: mask = 0;
6830 if (flagsp != NULL)
6831 switch (*flags)
6832 {
6833 case 'n': mask = SP_NOMOVE; break;
6834 case 'r': mask = SP_REPEAT; break;
6835 case 'm': mask = SP_RETCOUNT; break;
6836 }
6837 if (mask == 0)
6838 {
6839 EMSG2(_(e_invarg2), flags);
6840 dir = 0;
6841 }
6842 else
6843 *flagsp |= mask;
6844 }
6845 if (dir == 0)
6846 break;
6847 ++flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006848 }
6849 }
6850 return dir;
6851}
6852
6853/*
6854 * "setbufvar()" function
6855 */
6856/*ARGSUSED*/
6857 static void
6858f_setbufvar(argvars, retvar)
6859 VAR argvars;
6860 VAR retvar;
6861{
6862 buf_T *buf;
6863#ifdef FEAT_AUTOCMD
6864 aco_save_T aco;
6865#else
6866 buf_T *save_curbuf;
6867#endif
6868 char_u *varname, *bufvarname;
6869 VAR varp;
6870 char_u nbuf[NUMBUFLEN];
6871
6872 if (check_restricted() || check_secure())
6873 return;
6874 ++emsg_off;
6875 buf = get_buf_var(&argvars[0]);
6876 varname = get_var_string(&argvars[1]);
6877 varp = &argvars[2];
6878
6879 if (buf != NULL && varname != NULL && varp != NULL)
6880 {
6881 /* set curbuf to be our buf, temporarily */
6882#ifdef FEAT_AUTOCMD
6883 aucmd_prepbuf(&aco, buf);
6884#else
6885 save_curbuf = curbuf;
6886 curbuf = buf;
6887#endif
6888
6889 if (*varname == '&')
6890 {
6891 ++varname;
6892 set_option_value(varname, get_var_number(varp),
6893 get_var_string_buf(varp, nbuf), OPT_LOCAL);
6894 }
6895 else
6896 {
6897 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
6898 if (bufvarname != NULL)
6899 {
6900 STRCPY(bufvarname, "b:");
6901 STRCPY(bufvarname + 2, varname);
6902 set_var(bufvarname, varp);
6903 vim_free(bufvarname);
6904 }
6905 }
6906
6907 /* reset notion of buffer */
6908#ifdef FEAT_AUTOCMD
6909 aucmd_restbuf(&aco);
6910#else
6911 curbuf = save_curbuf;
6912#endif
6913 }
6914 --emsg_off;
6915}
6916
6917/*
6918 * "setcmdpos()" function
6919 */
6920 static void
6921f_setcmdpos(argvars, retvar)
6922 VAR argvars;
6923 VAR retvar;
6924{
6925 retvar->var_val.var_number = set_cmdline_pos(
6926 (int)get_var_number(&argvars[0]) - 1);
6927}
6928
6929/*
6930 * "setline()" function
6931 */
6932 static void
6933f_setline(argvars, retvar)
6934 VAR argvars;
6935 VAR retvar;
6936{
6937 linenr_T lnum;
6938 char_u *line;
6939
6940 lnum = get_var_lnum(argvars);
6941 line = get_var_string(&argvars[1]);
6942 retvar->var_val.var_number = 1; /* FAIL is default */
6943
6944 if (lnum >= 1
6945 && lnum <= curbuf->b_ml.ml_line_count
6946 && u_savesub(lnum) == OK
6947 && ml_replace(lnum, line, TRUE) == OK)
6948 {
6949 changed_bytes(lnum, 0);
6950 check_cursor_col();
6951 retvar->var_val.var_number = 0;
6952 }
6953}
6954
6955/*
6956 * "setreg()" function
6957 */
6958 static void
6959f_setreg(argvars, retvar)
6960 VAR argvars;
6961 VAR retvar;
6962{
6963 int regname;
6964 char_u *strregname;
6965 char_u *stropt;
6966 int append;
6967 char_u yank_type;
6968 long block_len;
6969
6970 block_len = -1;
6971 yank_type = MAUTO;
6972 append = FALSE;
6973
6974 strregname = get_var_string(argvars);
6975 retvar->var_val.var_number = 1; /* FAIL is default */
6976
6977 regname = (strregname == NULL ? '"' : *strregname);
6978 if (regname == 0 || regname == '@')
6979 regname = '"';
6980 else if (regname == '=')
6981 return;
6982
6983 if (argvars[2].var_type != VAR_UNKNOWN)
6984 {
6985 for (stropt = get_var_string(&argvars[2]); *stropt != NUL; ++stropt)
6986 switch (*stropt)
6987 {
6988 case 'a': case 'A': /* append */
6989 append = TRUE;
6990 break;
6991 case 'v': case 'c': /* character-wise selection */
6992 yank_type = MCHAR;
6993 break;
6994 case 'V': case 'l': /* line-wise selection */
6995 yank_type = MLINE;
6996 break;
6997#ifdef FEAT_VISUAL
6998 case 'b': case Ctrl_V: /* block-wise selection */
6999 yank_type = MBLOCK;
7000 if (VIM_ISDIGIT(stropt[1]))
7001 {
7002 ++stropt;
7003 block_len = getdigits(&stropt) - 1;
7004 --stropt;
7005 }
7006 break;
7007#endif
7008 }
7009 }
7010
7011 write_reg_contents_ex(regname, get_var_string(&argvars[1]), -1,
7012 append, yank_type, block_len);
7013 retvar->var_val.var_number = 0;
7014}
7015
7016
7017/*
7018 * "setwinvar(expr)" function
7019 */
7020/*ARGSUSED*/
7021 static void
7022f_setwinvar(argvars, retvar)
7023 VAR argvars;
7024 VAR retvar;
7025{
7026 win_T *win;
7027#ifdef FEAT_WINDOWS
7028 win_T *save_curwin;
7029#endif
7030 char_u *varname, *winvarname;
7031 VAR varp;
7032 char_u nbuf[NUMBUFLEN];
7033
7034 if (check_restricted() || check_secure())
7035 return;
7036 ++emsg_off;
7037 win = find_win_by_nr(&argvars[0]);
7038 varname = get_var_string(&argvars[1]);
7039 varp = &argvars[2];
7040
7041 if (win != NULL && varname != NULL && varp != NULL)
7042 {
7043#ifdef FEAT_WINDOWS
7044 /* set curwin to be our win, temporarily */
7045 save_curwin = curwin;
7046 curwin = win;
7047 curbuf = curwin->w_buffer;
7048#endif
7049
7050 if (*varname == '&')
7051 {
7052 ++varname;
7053 set_option_value(varname, get_var_number(varp),
7054 get_var_string_buf(varp, nbuf), OPT_LOCAL);
7055 }
7056 else
7057 {
7058 winvarname = alloc((unsigned)STRLEN(varname) + 3);
7059 if (winvarname != NULL)
7060 {
7061 STRCPY(winvarname, "w:");
7062 STRCPY(winvarname + 2, varname);
7063 set_var(winvarname, varp);
7064 vim_free(winvarname);
7065 }
7066 }
7067
7068#ifdef FEAT_WINDOWS
7069 /* Restore current window, if it's still valid (autocomands can make
7070 * it invalid). */
7071 if (win_valid(save_curwin))
7072 {
7073 curwin = save_curwin;
7074 curbuf = curwin->w_buffer;
7075 }
7076#endif
7077 }
7078 --emsg_off;
7079}
7080
7081/*
7082 * "nextnonblank()" function
7083 */
7084 static void
7085f_nextnonblank(argvars, retvar)
7086 VAR argvars;
7087 VAR retvar;
7088{
7089 linenr_T lnum;
7090
7091 for (lnum = get_var_lnum(argvars); ; ++lnum)
7092 {
7093 if (lnum > curbuf->b_ml.ml_line_count)
7094 {
7095 lnum = 0;
7096 break;
7097 }
7098 if (*skipwhite(ml_get(lnum)) != NUL)
7099 break;
7100 }
7101 retvar->var_val.var_number = lnum;
7102}
7103
7104/*
7105 * "prevnonblank()" function
7106 */
7107 static void
7108f_prevnonblank(argvars, retvar)
7109 VAR argvars;
7110 VAR retvar;
7111{
7112 linenr_T lnum;
7113
7114 lnum = get_var_lnum(argvars);
7115 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7116 lnum = 0;
7117 else
7118 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7119 --lnum;
7120 retvar->var_val.var_number = lnum;
7121}
7122
7123#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
7124static void make_connection __ARGS((void));
7125static int check_connection __ARGS((void));
7126
7127 static void
7128make_connection()
7129{
7130 if (X_DISPLAY == NULL
7131# ifdef FEAT_GUI
7132 && !gui.in_use
7133# endif
7134 )
7135 {
7136 x_force_connect = TRUE;
7137 setup_term_clip();
7138 x_force_connect = FALSE;
7139 }
7140}
7141
7142 static int
7143check_connection()
7144{
7145 make_connection();
7146 if (X_DISPLAY == NULL)
7147 {
7148 EMSG(_("E240: No connection to Vim server"));
7149 return FAIL;
7150 }
7151 return OK;
7152}
7153#endif
7154
7155/*ARGSUSED*/
7156 static void
7157f_serverlist(argvars, retvar)
7158 VAR argvars;
7159 VAR retvar;
7160{
7161 char_u *r = NULL;
7162
7163#ifdef FEAT_CLIENTSERVER
7164# ifdef WIN32
7165 r = serverGetVimNames();
7166# else
7167 make_connection();
7168 if (X_DISPLAY != NULL)
7169 r = serverGetVimNames(X_DISPLAY);
7170# endif
7171#endif
7172 retvar->var_type = VAR_STRING;
7173 retvar->var_val.var_string = r;
7174}
7175
7176/*ARGSUSED*/
7177 static void
7178f_remote_peek(argvars, retvar)
7179 VAR argvars;
7180 VAR retvar;
7181{
7182#ifdef FEAT_CLIENTSERVER
7183 var v;
7184 char_u *s = NULL;
7185# ifdef WIN32
7186 int n = 0;
7187# endif
7188
7189 if (check_restricted() || check_secure())
7190 {
7191 retvar->var_val.var_number = -1;
7192 return;
7193 }
7194# ifdef WIN32
7195 sscanf(get_var_string(&argvars[0]), "%x", &n);
7196 if (n == 0)
7197 retvar->var_val.var_number = -1;
7198 else
7199 {
7200 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
7201 retvar->var_val.var_number = (s != NULL);
7202 }
7203# else
7204 retvar->var_val.var_number = 0;
7205 if (check_connection() == FAIL)
7206 return;
7207
7208 retvar->var_val.var_number = serverPeekReply(X_DISPLAY,
7209 serverStrToWin(get_var_string(&argvars[0])), &s);
7210# endif
7211
7212 if (argvars[1].var_type != VAR_UNKNOWN && retvar->var_val.var_number > 0)
7213 {
7214 v.var_type = VAR_STRING;
7215 v.var_val.var_string = vim_strsave(s);
7216 set_var(get_var_string(&argvars[1]), &v);
7217 }
7218#else
7219 retvar->var_val.var_number = -1;
7220#endif
7221}
7222
7223/*ARGSUSED*/
7224 static void
7225f_remote_read(argvars, retvar)
7226 VAR argvars;
7227 VAR retvar;
7228{
7229 char_u *r = NULL;
7230
7231#ifdef FEAT_CLIENTSERVER
7232 if (!check_restricted() && !check_secure())
7233 {
7234# ifdef WIN32
7235 /* The server's HWND is encoded in the 'id' parameter */
7236 int n = 0;
7237
7238 sscanf(get_var_string(&argvars[0]), "%x", &n);
7239 if (n != 0)
7240 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
7241 if (r == NULL)
7242# else
7243 if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
7244 serverStrToWin(get_var_string(&argvars[0])), &r, FALSE) < 0)
7245# endif
7246 EMSG(_("E277: Unable to read a server reply"));
7247 }
7248#endif
7249 retvar->var_type = VAR_STRING;
7250 retvar->var_val.var_string = r;
7251}
7252
7253/*ARGSUSED*/
7254 static void
7255f_server2client(argvars, retvar)
7256 VAR argvars;
7257 VAR retvar;
7258{
7259#ifdef FEAT_CLIENTSERVER
7260 char_u buf[NUMBUFLEN];
7261 char_u *server = get_var_string(&argvars[0]);
7262 char_u *reply = get_var_string_buf(&argvars[1], buf);
7263
7264 retvar->var_val.var_number = -1;
7265 if (check_restricted() || check_secure())
7266 return;
7267# ifdef FEAT_X11
7268 if (check_connection() == FAIL)
7269 return;
7270# endif
7271
7272 if (serverSendReply(server, reply) < 0)
7273 {
7274 EMSG(_("E258: Unable to send to client"));
7275 return;
7276 }
7277 retvar->var_val.var_number = 0;
7278#else
7279 retvar->var_val.var_number = -1;
7280#endif
7281}
7282
7283#ifdef FEAT_CLIENTSERVER
7284static void remote_common __ARGS((VAR argvars, VAR retvar, int expr));
7285
7286 static void
7287remote_common(argvars, retvar, expr)
7288 VAR argvars;
7289 VAR retvar;
7290 int expr;
7291{
7292 char_u *server_name;
7293 char_u *keys;
7294 char_u *r = NULL;
7295 char_u buf[NUMBUFLEN];
7296# ifdef WIN32
7297 HWND w;
7298# else
7299 Window w;
7300# endif
7301
7302 if (check_restricted() || check_secure())
7303 return;
7304
7305# ifdef FEAT_X11
7306 if (check_connection() == FAIL)
7307 return;
7308# endif
7309
7310 server_name = get_var_string(&argvars[0]);
7311 keys = get_var_string_buf(&argvars[1], buf);
7312# ifdef WIN32
7313 if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
7314# else
7315 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
7316 < 0)
7317# endif
7318 {
7319 if (r != NULL)
7320 EMSG(r); /* sending worked but evaluation failed */
7321 else
7322 EMSG2(_("E241: Unable to send to %s"), server_name);
7323 return;
7324 }
7325
7326 retvar->var_val.var_string = r;
7327
7328 if (argvars[2].var_type != VAR_UNKNOWN)
7329 {
7330 var v;
7331 char_u str[30];
7332
7333 sprintf((char *)str, "0x%x", (unsigned int)w);
7334 v.var_type = VAR_STRING;
7335 v.var_val.var_string = vim_strsave(str);
7336 set_var(get_var_string(&argvars[2]), &v);
7337 }
7338}
7339#endif
7340
7341/*
7342 * "remote_expr()" function
7343 */
7344/*ARGSUSED*/
7345 static void
7346f_remote_expr(argvars, retvar)
7347 VAR argvars;
7348 VAR retvar;
7349{
7350 retvar->var_type = VAR_STRING;
7351 retvar->var_val.var_string = NULL;
7352#ifdef FEAT_CLIENTSERVER
7353 remote_common(argvars, retvar, TRUE);
7354#endif
7355}
7356
7357/*
7358 * "remote_send()" function
7359 */
7360/*ARGSUSED*/
7361 static void
7362f_remote_send(argvars, retvar)
7363 VAR argvars;
7364 VAR retvar;
7365{
7366 retvar->var_type = VAR_STRING;
7367 retvar->var_val.var_string = NULL;
7368#ifdef FEAT_CLIENTSERVER
7369 remote_common(argvars, retvar, FALSE);
7370#endif
7371}
7372
7373/*
7374 * "remote_foreground()" function
7375 */
7376/*ARGSUSED*/
7377 static void
7378f_remote_foreground(argvars, retvar)
7379 VAR argvars;
7380 VAR retvar;
7381{
7382 retvar->var_val.var_number = 0;
7383#ifdef FEAT_CLIENTSERVER
7384# ifdef WIN32
7385 /* On Win32 it's done in this application. */
7386 serverForeground(get_var_string(&argvars[0]));
7387# else
7388 /* Send a foreground() expression to the server. */
7389 argvars[1].var_type = VAR_STRING;
7390 argvars[1].var_val.var_string = vim_strsave((char_u *)"foreground()");
7391 argvars[2].var_type = VAR_UNKNOWN;
7392 remote_common(argvars, retvar, TRUE);
7393 vim_free(argvars[1].var_val.var_string);
7394# endif
7395#endif
7396}
7397
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00007398/*
7399 * "repeat()" function
7400 */
7401/*ARGSUSED*/
7402 static void
7403f_repeat(argvars, retvar)
7404 VAR argvars;
7405 VAR retvar;
7406{
7407 char_u *p;
7408 int n;
7409 int slen;
7410 int len;
7411 char_u *r;
7412 int i;
7413
7414 p = get_var_string(&argvars[0]);
7415 n = get_var_number(&argvars[1]);
7416
7417 retvar->var_type = VAR_STRING;
7418 retvar->var_val.var_string = NULL;
7419
7420 slen = (int)STRLEN(p);
7421 len = slen * n;
7422
7423 if (len <= 0)
7424 return;
7425
7426 r = alloc(len + 1);
7427 if (r != NULL)
7428 {
7429 for (i = 0; i < n; i++)
7430 mch_memmove(r + i * slen, p, (size_t)slen);
7431 r[len] = NUL;
7432 }
7433
7434 retvar->var_val.var_string = r;
7435}
7436
Bram Moolenaar071d4272004-06-13 20:20:40 +00007437#ifdef HAVE_STRFTIME
7438/*
7439 * "strftime({format}[, {time}])" function
7440 */
7441 static void
7442f_strftime(argvars, retvar)
7443 VAR argvars;
7444 VAR retvar;
7445{
7446 char_u result_buf[256];
7447 struct tm *curtime;
7448 time_t seconds;
7449 char_u *p;
7450
7451 retvar->var_type = VAR_STRING;
7452
7453 p = get_var_string(&argvars[0]);
7454 if (argvars[1].var_type == VAR_UNKNOWN)
7455 seconds = time(NULL);
7456 else
7457 seconds = (time_t)get_var_number(&argvars[1]);
7458 curtime = localtime(&seconds);
7459 /* MSVC returns NULL for an invalid value of seconds. */
7460 if (curtime == NULL)
7461 retvar->var_val.var_string = vim_strsave((char_u *)_("(Invalid)"));
7462 else
7463 {
7464# ifdef FEAT_MBYTE
7465 vimconv_T conv;
7466 char_u *enc;
7467
7468 conv.vc_type = CONV_NONE;
7469 enc = enc_locale();
7470 convert_setup(&conv, p_enc, enc);
7471 if (conv.vc_type != CONV_NONE)
7472 p = string_convert(&conv, p, NULL);
7473# endif
7474 if (p != NULL)
7475 (void)strftime((char *)result_buf, sizeof(result_buf),
7476 (char *)p, curtime);
7477 else
7478 result_buf[0] = NUL;
7479
7480# ifdef FEAT_MBYTE
7481 if (conv.vc_type != CONV_NONE)
7482 vim_free(p);
7483 convert_setup(&conv, enc, p_enc);
7484 if (conv.vc_type != CONV_NONE)
7485 retvar->var_val.var_string =
7486 string_convert(&conv, result_buf, NULL);
7487 else
7488# endif
7489 retvar->var_val.var_string = vim_strsave(result_buf);
7490
7491# ifdef FEAT_MBYTE
7492 /* Release conversion descriptors */
7493 convert_setup(&conv, NULL, NULL);
7494 vim_free(enc);
7495# endif
7496 }
7497}
7498#endif
7499
7500/*
7501 * "stridx()" function
7502 */
7503 static void
7504f_stridx(argvars, retvar)
7505 VAR argvars;
7506 VAR retvar;
7507{
7508 char_u buf[NUMBUFLEN];
7509 char_u *needle;
7510 char_u *haystack;
7511 char_u *pos;
7512
7513 needle = get_var_string(&argvars[1]);
7514 haystack = get_var_string_buf(&argvars[0], buf);
7515 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7516
7517 if (pos == NULL)
7518 retvar->var_val.var_number = -1;
7519 else
7520 retvar->var_val.var_number = (varnumber_T) (pos - haystack);
7521}
7522
7523/*
7524 * "strridx()" function
7525 */
7526 static void
7527f_strridx(argvars, retvar)
7528 VAR argvars;
7529 VAR retvar;
7530{
7531 char_u buf[NUMBUFLEN];
7532 char_u *needle;
7533 char_u *haystack;
7534 char_u *rest;
7535 char_u *lastmatch = NULL;
7536
7537 needle = get_var_string(&argvars[1]);
7538 haystack = get_var_string_buf(&argvars[0], buf);
Bram Moolenaard4755bb2004-09-02 19:12:26 +00007539 if (*needle == NUL)
7540 /* Empty string matches past the end. */
7541 lastmatch = haystack + STRLEN(haystack);
7542 else
7543 for (rest = haystack; *rest != '\0'; ++rest)
7544 {
7545 rest = (char_u *)strstr((char *)rest, (char *)needle);
7546 if (rest == NULL)
7547 break;
7548 lastmatch = rest;
7549 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007550
7551 if (lastmatch == NULL)
7552 retvar->var_val.var_number = -1;
7553 else
Bram Moolenaard4755bb2004-09-02 19:12:26 +00007554 retvar->var_val.var_number = (varnumber_T)(lastmatch - haystack);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007555}
7556
7557/*
7558 * "strlen()" function
7559 */
7560 static void
7561f_strlen(argvars, retvar)
7562 VAR argvars;
7563 VAR retvar;
7564{
7565 retvar->var_val.var_number = (varnumber_T) (STRLEN(get_var_string(&argvars[0])));
7566}
7567
7568/*
7569 * "strpart()" function
7570 */
7571 static void
7572f_strpart(argvars, retvar)
7573 VAR argvars;
7574 VAR retvar;
7575{
7576 char_u *p;
7577 int n;
7578 int len;
7579 int slen;
7580
7581 p = get_var_string(&argvars[0]);
7582 slen = (int)STRLEN(p);
7583
7584 n = get_var_number(&argvars[1]);
7585 if (argvars[2].var_type != VAR_UNKNOWN)
7586 len = get_var_number(&argvars[2]);
7587 else
7588 len = slen - n; /* default len: all bytes that are available. */
7589
7590 /*
7591 * Only return the overlap between the specified part and the actual
7592 * string.
7593 */
7594 if (n < 0)
7595 {
7596 len += n;
7597 n = 0;
7598 }
7599 else if (n > slen)
7600 n = slen;
7601 if (len < 0)
7602 len = 0;
7603 else if (n + len > slen)
7604 len = slen - n;
7605
7606 retvar->var_type = VAR_STRING;
7607 retvar->var_val.var_string = vim_strnsave(p + n, len);
7608}
7609
7610/*
7611 * "strtrans()" function
7612 */
7613 static void
7614f_strtrans(argvars, retvar)
7615 VAR argvars;
7616 VAR retvar;
7617{
7618 retvar->var_type = VAR_STRING;
7619 retvar->var_val.var_string = transstr(get_var_string(&argvars[0]));
7620}
7621
7622/*
7623 * "synID(line, col, trans)" function
7624 */
7625/*ARGSUSED*/
7626 static void
7627f_synID(argvars, retvar)
7628 VAR argvars;
7629 VAR retvar;
7630{
7631 int id = 0;
7632#ifdef FEAT_SYN_HL
7633 long line;
7634 long col;
7635 int trans;
7636
7637 line = get_var_lnum(argvars);
7638 col = get_var_number(&argvars[1]) - 1;
7639 trans = get_var_number(&argvars[2]);
7640
7641 if (line >= 1 && line <= curbuf->b_ml.ml_line_count
7642 && col >= 0 && col < (long)STRLEN(ml_get(line)))
7643 id = syn_get_id(line, col, trans);
7644#endif
7645
7646 retvar->var_val.var_number = id;
7647}
7648
7649/*
7650 * "synIDattr(id, what [, mode])" function
7651 */
7652/*ARGSUSED*/
7653 static void
7654f_synIDattr(argvars, retvar)
7655 VAR argvars;
7656 VAR retvar;
7657{
7658 char_u *p = NULL;
7659#ifdef FEAT_SYN_HL
7660 int id;
7661 char_u *what;
7662 char_u *mode;
7663 char_u modebuf[NUMBUFLEN];
7664 int modec;
7665
7666 id = get_var_number(&argvars[0]);
7667 what = get_var_string(&argvars[1]);
7668 if (argvars[2].var_type != VAR_UNKNOWN)
7669 {
7670 mode = get_var_string_buf(&argvars[2], modebuf);
7671 modec = TOLOWER_ASC(mode[0]);
7672 if (modec != 't' && modec != 'c'
7673#ifdef FEAT_GUI
7674 && modec != 'g'
7675#endif
7676 )
7677 modec = 0; /* replace invalid with current */
7678 }
7679 else
7680 {
7681#ifdef FEAT_GUI
7682 if (gui.in_use)
7683 modec = 'g';
7684 else
7685#endif
7686 if (t_colors > 1)
7687 modec = 'c';
7688 else
7689 modec = 't';
7690 }
7691
7692
7693 switch (TOLOWER_ASC(what[0]))
7694 {
7695 case 'b':
7696 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7697 p = highlight_color(id, what, modec);
7698 else /* bold */
7699 p = highlight_has_attr(id, HL_BOLD, modec);
7700 break;
7701
7702 case 'f': /* fg[#] */
7703 p = highlight_color(id, what, modec);
7704 break;
7705
7706 case 'i':
7707 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7708 p = highlight_has_attr(id, HL_INVERSE, modec);
7709 else /* italic */
7710 p = highlight_has_attr(id, HL_ITALIC, modec);
7711 break;
7712
7713 case 'n': /* name */
7714 p = get_highlight_name(NULL, id - 1);
7715 break;
7716
7717 case 'r': /* reverse */
7718 p = highlight_has_attr(id, HL_INVERSE, modec);
7719 break;
7720
7721 case 's': /* standout */
7722 p = highlight_has_attr(id, HL_STANDOUT, modec);
7723 break;
7724
7725 case 'u': /* underline */
7726 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7727 break;
7728 }
7729
7730 if (p != NULL)
7731 p = vim_strsave(p);
7732#endif
7733 retvar->var_type = VAR_STRING;
7734 retvar->var_val.var_string = p;
7735}
7736
7737/*
7738 * "synIDtrans(id)" function
7739 */
7740/*ARGSUSED*/
7741 static void
7742f_synIDtrans(argvars, retvar)
7743 VAR argvars;
7744 VAR retvar;
7745{
7746 int id;
7747
7748#ifdef FEAT_SYN_HL
7749 id = get_var_number(&argvars[0]);
7750
7751 if (id > 0)
7752 id = syn_get_final_id(id);
7753 else
7754#endif
7755 id = 0;
7756
7757 retvar->var_val.var_number = id;
7758}
7759
7760/*
7761 * "system()" function
7762 */
7763 static void
7764f_system(argvars, retvar)
7765 VAR argvars;
7766 VAR retvar;
7767{
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007768 char_u *res = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007769 char_u *p;
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007770 char_u *infile = NULL;
7771 char_u buf[NUMBUFLEN];
7772 int err = FALSE;
7773 FILE *fd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007774
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007775 if (argvars[1].var_type != VAR_UNKNOWN)
7776 {
7777 /*
7778 * Write the string to a temp file, to be used for input of the shell
7779 * command.
7780 */
7781 if ((infile = vim_tempname('i')) == NULL)
7782 {
7783 EMSG(_(e_notmp));
7784 return;
7785 }
7786
7787 fd = mch_fopen((char *)infile, WRITEBIN);
7788 if (fd == NULL)
7789 {
7790 EMSG2(_(e_notopen), infile);
7791 goto done;
7792 }
7793 p = get_var_string_buf(&argvars[1], buf);
7794 if (fwrite(p, STRLEN(p), 1, fd) != 1)
7795 err = TRUE;
7796 if (fclose(fd) != 0)
7797 err = TRUE;
7798 if (err)
7799 {
7800 EMSG(_("E677: Error writing temp file"));
7801 goto done;
7802 }
7803 }
7804
7805 res = get_cmd_output(get_var_string(&argvars[0]), infile, SHELL_SILENT);
7806
Bram Moolenaar071d4272004-06-13 20:20:40 +00007807#ifdef USE_CR
7808 /* translate <CR> into <NL> */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007809 if (res != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007810 {
7811 char_u *s;
7812
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007813 for (s = res; *s; ++s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007814 {
7815 if (*s == CAR)
7816 *s = NL;
7817 }
7818 }
7819#else
7820# ifdef USE_CRNL
7821 /* translate <CR><NL> into <NL> */
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007822 if (res != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007823 {
7824 char_u *s, *d;
7825
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007826 d = res;
7827 for (s = res; *s; ++s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007828 {
7829 if (s[0] == CAR && s[1] == NL)
7830 ++s;
7831 *d++ = *s;
7832 }
7833 *d = NUL;
7834 }
7835# endif
7836#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007837
7838done:
7839 if (infile != NULL)
7840 {
7841 mch_remove(infile);
7842 vim_free(infile);
7843 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007844 retvar->var_type = VAR_STRING;
Bram Moolenaarc0197e22004-09-13 20:26:32 +00007845 retvar->var_val.var_string = res;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007846}
7847
7848/*
7849 * "submatch()" function
7850 */
7851 static void
7852f_submatch(argvars, retvar)
7853 VAR argvars;
7854 VAR retvar;
7855{
7856 retvar->var_type = VAR_STRING;
7857 retvar->var_val.var_string = reg_submatch((int)get_var_number(&argvars[0]));
7858}
7859
7860/*
7861 * "substitute()" function
7862 */
7863 static void
7864f_substitute(argvars, retvar)
7865 VAR argvars;
7866 VAR retvar;
7867{
7868 char_u patbuf[NUMBUFLEN];
7869 char_u subbuf[NUMBUFLEN];
7870 char_u flagsbuf[NUMBUFLEN];
7871
7872 retvar->var_type = VAR_STRING;
7873 retvar->var_val.var_string = do_string_sub(
7874 get_var_string(&argvars[0]),
7875 get_var_string_buf(&argvars[1], patbuf),
7876 get_var_string_buf(&argvars[2], subbuf),
7877 get_var_string_buf(&argvars[3], flagsbuf));
7878}
7879
7880/*
7881 * "tempname()" function
7882 */
7883/*ARGSUSED*/
7884 static void
7885f_tempname(argvars, retvar)
7886 VAR argvars;
7887 VAR retvar;
7888{
7889 static int x = 'A';
7890
7891 retvar->var_type = VAR_STRING;
7892 retvar->var_val.var_string = vim_tempname(x);
7893
7894 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
7895 * names. Skip 'I' and 'O', they are used for shell redirection. */
7896 do
7897 {
7898 if (x == 'Z')
7899 x = '0';
7900 else if (x == '9')
7901 x = 'A';
7902 else
7903 {
7904#ifdef EBCDIC
7905 if (x == 'I')
7906 x = 'J';
7907 else if (x == 'R')
7908 x = 'S';
7909 else
7910#endif
7911 ++x;
7912 }
7913 } while (x == 'I' || x == 'O');
7914}
7915
7916/*
7917 * "tolower(string)" function
7918 */
7919 static void
7920f_tolower(argvars, retvar)
7921 VAR argvars;
7922 VAR retvar;
7923{
7924 char_u *p;
7925
7926 p = vim_strsave(get_var_string(&argvars[0]));
7927 retvar->var_type = VAR_STRING;
7928 retvar->var_val.var_string = p;
7929
7930 if (p != NULL)
7931 while (*p != NUL)
7932 {
7933#ifdef FEAT_MBYTE
7934 int l;
7935
7936 if (enc_utf8)
7937 {
7938 int c, lc;
7939
7940 c = utf_ptr2char(p);
7941 lc = utf_tolower(c);
7942 l = utf_ptr2len_check(p);
7943 /* TODO: reallocate string when byte count changes. */
7944 if (utf_char2len(lc) == l)
7945 utf_char2bytes(lc, p);
7946 p += l;
7947 }
7948 else if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
7949 p += l; /* skip multi-byte character */
7950 else
7951#endif
7952 {
7953 *p = TOLOWER_LOC(*p); /* note that tolower() can be a macro */
7954 ++p;
7955 }
7956 }
7957}
7958
7959/*
7960 * "toupper(string)" function
7961 */
7962 static void
7963f_toupper(argvars, retvar)
7964 VAR argvars;
7965 VAR retvar;
7966{
7967 char_u *p;
7968
7969 p = vim_strsave(get_var_string(&argvars[0]));
7970 retvar->var_type = VAR_STRING;
7971 retvar->var_val.var_string = p;
7972
7973 if (p != NULL)
7974 while (*p != NUL)
7975 {
7976#ifdef FEAT_MBYTE
7977 int l;
7978
7979 if (enc_utf8)
7980 {
7981 int c, uc;
7982
7983 c = utf_ptr2char(p);
7984 uc = utf_toupper(c);
7985 l = utf_ptr2len_check(p);
7986 /* TODO: reallocate string when byte count changes. */
7987 if (utf_char2len(uc) == l)
7988 utf_char2bytes(uc, p);
7989 p += l;
7990 }
7991 else if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
7992 p += l; /* skip multi-byte character */
7993 else
7994#endif
7995 {
7996 *p = TOUPPER_LOC(*p); /* note that toupper() can be a macro */
7997 p++;
7998 }
7999 }
8000}
8001
8002/*
Bram Moolenaar8299df92004-07-10 09:47:34 +00008003 * "tr(string, fromstr, tostr)" function
8004 */
8005 static void
8006f_tr(argvars, retvar)
8007 VAR argvars;
8008 VAR retvar;
8009{
8010 char_u *instr;
8011 char_u *fromstr;
8012 char_u *tostr;
8013 char_u *p;
8014#ifdef FEAT_MBYTE
8015 int inlen;
8016 int fromlen;
8017 int tolen;
8018 int idx;
8019 char_u *cpstr;
8020 int cplen;
8021 int first = TRUE;
8022#endif
8023 char_u buf[NUMBUFLEN];
8024 char_u buf2[NUMBUFLEN];
8025 garray_T ga;
8026
8027 instr = get_var_string(&argvars[0]);
8028 fromstr = get_var_string_buf(&argvars[1], buf);
8029 tostr = get_var_string_buf(&argvars[2], buf2);
8030
8031 /* Default return value: empty string. */
8032 retvar->var_type = VAR_STRING;
8033 retvar->var_val.var_string = NULL;
8034 ga_init2(&ga, (int)sizeof(char), 80);
8035
8036#ifdef FEAT_MBYTE
8037 if (!has_mbyte)
8038#endif
8039 /* not multi-byte: fromstr and tostr must be the same length */
8040 if (STRLEN(fromstr) != STRLEN(tostr))
8041 {
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00008042#ifdef FEAT_MBYTE
Bram Moolenaar8299df92004-07-10 09:47:34 +00008043error:
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00008044#endif
Bram Moolenaar8299df92004-07-10 09:47:34 +00008045 EMSG2(_(e_invarg2), fromstr);
8046 ga_clear(&ga);
8047 return;
8048 }
8049
8050 /* fromstr and tostr have to contain the same number of chars */
8051 while (*instr != NUL)
8052 {
8053#ifdef FEAT_MBYTE
8054 if (has_mbyte)
8055 {
8056 inlen = mb_ptr2len_check(instr);
8057 cpstr = instr;
8058 cplen = inlen;
8059 idx = 0;
8060 for (p = fromstr; *p != NUL; p += fromlen)
8061 {
8062 fromlen = mb_ptr2len_check(p);
8063 if (fromlen == inlen && STRNCMP(instr, p, inlen) == 0)
8064 {
8065 for (p = tostr; *p != NUL; p += tolen)
8066 {
8067 tolen = mb_ptr2len_check(p);
8068 if (idx-- == 0)
8069 {
8070 cplen = tolen;
8071 cpstr = p;
8072 break;
8073 }
8074 }
8075 if (*p == NUL) /* tostr is shorter than fromstr */
8076 goto error;
8077 break;
8078 }
8079 ++idx;
8080 }
8081
8082 if (first && cpstr == instr)
8083 {
8084 /* Check that fromstr and tostr have the same number of
8085 * (multi-byte) characters. Done only once when a character
8086 * of instr doesn't appear in fromstr. */
8087 first = FALSE;
8088 for (p = tostr; *p != NUL; p += tolen)
8089 {
8090 tolen = mb_ptr2len_check(p);
8091 --idx;
8092 }
8093 if (idx != 0)
8094 goto error;
8095 }
8096
8097 ga_grow(&ga, cplen);
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00008098 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
Bram Moolenaar8299df92004-07-10 09:47:34 +00008099 ga.ga_len += cplen;
8100 ga.ga_room -= cplen;
8101
8102 instr += inlen;
8103 }
8104 else
8105#endif
8106 {
8107 /* When not using multi-byte chars we can do it faster. */
8108 p = vim_strchr(fromstr, *instr);
8109 if (p != NULL)
8110 ga_append(&ga, tostr[p - fromstr]);
8111 else
8112 ga_append(&ga, *instr);
8113 ++instr;
8114 }
8115 }
8116
8117 retvar->var_val.var_string = ga.ga_data;
8118}
8119
8120/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00008121 * "type(expr)" function
8122 */
8123 static void
8124f_type(argvars, retvar)
8125 VAR argvars;
8126 VAR retvar;
8127{
8128 if (argvars[0].var_type == VAR_NUMBER)
8129 retvar->var_val.var_number = 0;
8130 else
8131 retvar->var_val.var_number = 1;
8132}
8133
8134/*
8135 * "virtcol(string)" function
8136 */
8137 static void
8138f_virtcol(argvars, retvar)
8139 VAR argvars;
8140 VAR retvar;
8141{
8142 colnr_T vcol = 0;
8143 pos_T *fp;
8144
8145 fp = var2fpos(&argvars[0], FALSE);
8146 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count)
8147 {
8148 getvvcol(curwin, fp, NULL, NULL, &vcol);
8149 ++vcol;
8150 }
8151
8152 retvar->var_val.var_number = vcol;
8153}
8154
8155/*
8156 * "visualmode()" function
8157 */
8158/*ARGSUSED*/
8159 static void
8160f_visualmode(argvars, retvar)
8161 VAR argvars;
8162 VAR retvar;
8163{
8164#ifdef FEAT_VISUAL
8165 char_u str[2];
8166
8167 retvar->var_type = VAR_STRING;
8168 str[0] = curbuf->b_visual_mode_eval;
8169 str[1] = NUL;
8170 retvar->var_val.var_string = vim_strsave(str);
8171
8172 /* A non-zero number or non-empty string argument: reset mode. */
8173 if ((argvars[0].var_type == VAR_NUMBER
8174 && argvars[0].var_val.var_number != 0)
8175 || (argvars[0].var_type == VAR_STRING
8176 && *get_var_string(&argvars[0]) != NUL))
8177 curbuf->b_visual_mode_eval = NUL;
8178#else
8179 retvar->var_val.var_number = 0; /* return anything, it won't work anyway */
8180#endif
8181}
8182
8183/*
8184 * "winbufnr(nr)" function
8185 */
8186 static void
8187f_winbufnr(argvars, retvar)
8188 VAR argvars;
8189 VAR retvar;
8190{
8191 win_T *wp;
8192
8193 wp = find_win_by_nr(&argvars[0]);
8194 if (wp == NULL)
8195 retvar->var_val.var_number = -1;
8196 else
8197 retvar->var_val.var_number = wp->w_buffer->b_fnum;
8198}
8199
8200/*
8201 * "wincol()" function
8202 */
8203/*ARGSUSED*/
8204 static void
8205f_wincol(argvars, retvar)
8206 VAR argvars;
8207 VAR retvar;
8208{
8209 validate_cursor();
8210 retvar->var_val.var_number = curwin->w_wcol + 1;
8211}
8212
8213/*
8214 * "winheight(nr)" function
8215 */
8216 static void
8217f_winheight(argvars, retvar)
8218 VAR argvars;
8219 VAR retvar;
8220{
8221 win_T *wp;
8222
8223 wp = find_win_by_nr(&argvars[0]);
8224 if (wp == NULL)
8225 retvar->var_val.var_number = -1;
8226 else
8227 retvar->var_val.var_number = wp->w_height;
8228}
8229
8230/*
8231 * "winline()" function
8232 */
8233/*ARGSUSED*/
8234 static void
8235f_winline(argvars, retvar)
8236 VAR argvars;
8237 VAR retvar;
8238{
8239 validate_cursor();
8240 retvar->var_val.var_number = curwin->w_wrow + 1;
8241}
8242
8243/*
8244 * "winnr()" function
8245 */
8246/* ARGSUSED */
8247 static void
8248f_winnr(argvars, retvar)
8249 VAR argvars;
8250 VAR retvar;
8251{
8252 int nr = 1;
8253#ifdef FEAT_WINDOWS
8254 win_T *wp;
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00008255 win_T *twin = curwin;
8256 char_u *arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008257
Bram Moolenaar5eb86f92004-07-26 12:53:41 +00008258 if (argvars[0].var_type != VAR_UNKNOWN)
8259 {
8260 arg = get_var_string(&argvars[0]);
8261 if (STRCMP(arg, "$") == 0)
8262 twin = lastwin;
8263 else if (STRCMP(arg, "#") == 0)
8264 {
8265 twin = prevwin;
8266 if (prevwin == NULL)
8267 nr = 0;
8268 }
8269 else
8270 {
8271 EMSG2(_(e_invexpr2), arg);
8272 nr = 0;
8273 }
8274 }
8275
8276 if (nr > 0)
8277 for (wp = firstwin; wp != twin; wp = wp->w_next)
8278 ++nr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008279#endif
8280 retvar->var_val.var_number = nr;
8281}
8282
8283/*
8284 * "winrestcmd()" function
8285 */
8286/* ARGSUSED */
8287 static void
8288f_winrestcmd(argvars, retvar)
8289 VAR argvars;
8290 VAR retvar;
8291{
8292#ifdef FEAT_WINDOWS
8293 win_T *wp;
8294 int winnr = 1;
8295 garray_T ga;
8296 char_u buf[50];
8297
8298 ga_init2(&ga, (int)sizeof(char), 70);
8299 for (wp = firstwin; wp != NULL; wp = wp->w_next)
8300 {
8301 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
8302 ga_concat(&ga, buf);
8303# ifdef FEAT_VERTSPLIT
8304 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
8305 ga_concat(&ga, buf);
8306# endif
8307 ++winnr;
8308 }
Bram Moolenaar269ec652004-07-29 08:43:53 +00008309 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00008310
8311 retvar->var_val.var_string = ga.ga_data;
8312#else
8313 retvar->var_val.var_string = NULL;
8314#endif
8315 retvar->var_type = VAR_STRING;
8316}
8317
8318/*
8319 * "winwidth(nr)" function
8320 */
8321 static void
8322f_winwidth(argvars, retvar)
8323 VAR argvars;
8324 VAR retvar;
8325{
8326 win_T *wp;
8327
8328 wp = find_win_by_nr(&argvars[0]);
8329 if (wp == NULL)
8330 retvar->var_val.var_number = -1;
8331 else
8332#ifdef FEAT_VERTSPLIT
8333 retvar->var_val.var_number = wp->w_width;
8334#else
8335 retvar->var_val.var_number = Columns;
8336#endif
8337}
8338
8339 static win_T *
8340find_win_by_nr(vp)
8341 VAR vp;
8342{
8343#ifdef FEAT_WINDOWS
8344 win_T *wp;
8345#endif
8346 int nr;
8347
8348 nr = get_var_number(vp);
8349
8350#ifdef FEAT_WINDOWS
8351 if (nr == 0)
8352 return curwin;
8353
8354 for (wp = firstwin; wp != NULL; wp = wp->w_next)
8355 if (--nr <= 0)
8356 break;
8357 return wp;
8358#else
8359 if (nr == 0 || nr == 1)
8360 return curwin;
8361 return NULL;
8362#endif
8363}
8364
8365/*
8366 * Translate a String variable into a position.
8367 */
8368 static pos_T *
8369var2fpos(varp, lnum)
8370 VAR varp;
8371 int lnum; /* TRUE when $ is last line */
8372{
8373 char_u *name;
8374 static pos_T pos;
8375 pos_T *pp;
8376
8377 name = get_var_string(varp);
8378 if (name[0] == '.') /* cursor */
8379 return &curwin->w_cursor;
8380 if (name[0] == '\'') /* mark */
8381 {
8382 pp = getmark(name[1], FALSE);
8383 if (pp == NULL || pp == (pos_T *)-1 || pp->lnum <= 0)
8384 return NULL;
8385 return pp;
8386 }
8387 if (name[0] == '$') /* last column or line */
8388 {
8389 if (lnum)
8390 {
8391 pos.lnum = curbuf->b_ml.ml_line_count;
8392 pos.col = 0;
8393 }
8394 else
8395 {
8396 pos.lnum = curwin->w_cursor.lnum;
8397 pos.col = (colnr_T)STRLEN(ml_get_curline());
8398 }
8399 return &pos;
8400 }
8401 return NULL;
8402}
8403
8404/*
8405 * Get the length of an environment variable name.
8406 * Advance "arg" to the first character after the name.
8407 * Return 0 for error.
8408 */
8409 static int
8410get_env_len(arg)
8411 char_u **arg;
8412{
8413 char_u *p;
8414 int len;
8415
8416 for (p = *arg; vim_isIDc(*p); ++p)
8417 ;
8418 if (p == *arg) /* no name found */
8419 return 0;
8420
8421 len = (int)(p - *arg);
8422 *arg = p;
8423 return len;
8424}
8425
8426/*
8427 * Get the length of the name of a function or internal variable.
8428 * "arg" is advanced to the first non-white character after the name.
8429 * Return 0 if something is wrong.
8430 */
8431 static int
8432get_id_len(arg)
8433 char_u **arg;
8434{
8435 char_u *p;
8436 int len;
8437
8438 /* Find the end of the name. */
8439 for (p = *arg; eval_isnamec(*p); ++p)
8440 ;
8441 if (p == *arg) /* no name found */
8442 return 0;
8443
8444 len = (int)(p - *arg);
8445 *arg = skipwhite(p);
8446
8447 return len;
8448}
8449
8450/*
8451 * Get the length of the name of a function.
8452 * "arg" is advanced to the first non-white character after the name.
8453 * Return 0 if something is wrong.
8454 * If the name contains 'magic' {}'s, expand them and return the
8455 * expanded name in an allocated string via 'alias' - caller must free.
8456 */
8457 static int
8458get_func_len(arg, alias, evaluate)
8459 char_u **arg;
8460 char_u **alias;
8461 int evaluate;
8462{
8463 int len;
8464#ifdef FEAT_MAGIC_BRACES
8465 char_u *p;
8466 char_u *expr_start;
8467 char_u *expr_end;
8468#endif
8469
8470 *alias = NULL; /* default to no alias */
8471
8472 if ((*arg)[0] == K_SPECIAL && (*arg)[1] == KS_EXTRA
8473 && (*arg)[2] == (int)KE_SNR)
8474 {
8475 /* hard coded <SNR>, already translated */
8476 *arg += 3;
8477 return get_id_len(arg) + 3;
8478 }
8479 len = eval_fname_script(*arg);
8480 if (len > 0)
8481 {
8482 /* literal "<SID>", "s:" or "<SNR>" */
8483 *arg += len;
8484 }
8485
8486#ifdef FEAT_MAGIC_BRACES
8487 /*
8488 * Find the end of the name;
8489 */
8490 p = find_name_end(*arg, &expr_start, &expr_end);
8491 /* check for {} construction */
8492 if (expr_start != NULL)
8493 {
8494 char_u *temp_string;
8495
8496 if (!evaluate)
8497 {
8498 len += (int)(p - *arg);
8499 *arg = skipwhite(p);
8500 return len;
8501 }
8502
8503 /*
8504 * Include any <SID> etc in the expanded string:
8505 * Thus the -len here.
8506 */
8507 temp_string = make_expanded_name(*arg - len, expr_start, expr_end, p);
8508 if (temp_string == NULL)
8509 return 0;
8510 *alias = temp_string;
8511 *arg = skipwhite(p);
8512 return (int)STRLEN(temp_string);
8513 }
8514#endif
8515
8516 len += get_id_len(arg);
8517 if (len == 0)
8518 EMSG2(_(e_invexpr2), *arg);
8519
8520 return len;
8521}
8522
8523 static char_u *
8524find_name_end(arg, expr_start, expr_end)
8525 char_u *arg;
8526 char_u **expr_start;
8527 char_u **expr_end;
8528{
8529 int nesting = 0;
8530 char_u *p;
8531
8532 *expr_start = NULL;
8533 *expr_end = NULL;
8534
8535 for (p = arg; (*p != NUL && (eval_isnamec(*p) || nesting != 0)); ++p)
8536 {
8537#ifdef FEAT_MAGIC_BRACES
8538 if (*p == '{')
8539 {
8540 nesting++;
8541 if (*expr_start == NULL)
8542 *expr_start = p;
8543 }
8544 else if (*p == '}')
8545 {
8546 nesting--;
8547 if (nesting == 0 && *expr_end == NULL)
8548 *expr_end = p;
8549 }
8550#endif
8551 }
8552
8553 return p;
8554}
8555
8556/*
8557 * Return TRUE if character "c" can be used in a variable or function name.
8558 */
8559 static int
8560eval_isnamec(c)
8561 int c;
8562{
8563 return (ASCII_ISALNUM(c) || c == '_' || c == ':'
8564#ifdef FEAT_MAGIC_BRACES
8565 || c == '{' || c == '}'
8566#endif
8567 );
8568}
8569
8570/*
8571 * Find a v: variable.
8572 * Return it's index, or -1 if not found.
8573 */
8574 static int
8575find_vim_var(name, len)
8576 char_u *name;
8577 int len; /* length of "name" */
8578{
8579 char_u *vname;
8580 int vlen;
8581 int i;
8582
8583 /*
8584 * Ignore "v:" for old built-in variables, require it for new ones.
8585 */
8586 if (name[0] == 'v' && name[1] == ':')
8587 {
8588 vname = name + 2;
8589 vlen = len - 2;
8590 }
8591 else
8592 {
8593 vname = name;
8594 vlen = len;
8595 }
8596 for (i = 0; i < VV_LEN; ++i)
8597 if (vlen == vimvars[i].len && STRCMP(vname, vimvars[i].name) == 0
8598 && ((vimvars[i].flags & VV_COMPAT) || vname != name))
8599 return i;
8600 return -1;
8601}
8602
8603/*
8604 * Set number v: variable to "val".
8605 */
8606 void
8607set_vim_var_nr(idx, val)
8608 int idx;
8609 long val;
8610{
8611 vimvars[idx].val = (char_u *)val;
8612}
8613
8614/*
8615 * Get number v: variable value;
8616 */
8617 long
8618get_vim_var_nr(idx)
8619 int idx;
8620{
8621 return (long)vimvars[idx].val;
8622}
8623
8624/*
8625 * Set v:count, v:count1 and v:prevcount.
8626 */
8627 void
8628set_vcount(count, count1)
8629 long count;
8630 long count1;
8631{
8632 vimvars[VV_PREVCOUNT].val = vimvars[VV_COUNT].val;
8633 vimvars[VV_COUNT].val = (char_u *)count;
8634 vimvars[VV_COUNT1].val = (char_u *)count1;
8635}
8636
8637/*
8638 * Set string v: variable to a copy of "val".
8639 */
8640 void
8641set_vim_var_string(idx, val, len)
8642 int idx;
8643 char_u *val;
8644 int len; /* length of "val" to use or -1 (whole string) */
8645{
8646 vim_free(vimvars[idx].val);
8647 if (val == NULL)
8648 vimvars[idx].val = NULL;
8649 else if (len == -1)
8650 vimvars[idx].val = vim_strsave(val);
8651 else
8652 vimvars[idx].val = vim_strnsave(val, len);
8653}
8654
8655/*
8656 * Set v:register if needed.
8657 */
8658 void
8659set_reg_var(c)
8660 int c;
8661{
8662 char_u regname;
8663
8664 if (c == 0 || c == ' ')
8665 regname = '"';
8666 else
8667 regname = c;
8668 /* Avoid free/alloc when the value is already right. */
8669 if (vimvars[VV_REG].val == NULL || vimvars[VV_REG].val[0] != c)
8670 set_vim_var_string(VV_REG, &regname, 1);
8671}
8672
8673/*
8674 * Get or set v:exception. If "oldval" == NULL, return the current value.
8675 * Otherwise, restore the value to "oldval" and return NULL.
8676 * Must always be called in pairs to save and restore v:exception! Does not
8677 * take care of memory allocations.
8678 */
8679 char_u *
8680v_exception(oldval)
8681 char_u *oldval;
8682{
8683 if (oldval == NULL)
8684 return vimvars[VV_EXCEPTION].val;
8685
8686 vimvars[VV_EXCEPTION].val = oldval;
8687 return NULL;
8688}
8689
8690/*
8691 * Get or set v:throwpoint. If "oldval" == NULL, return the current value.
8692 * Otherwise, restore the value to "oldval" and return NULL.
8693 * Must always be called in pairs to save and restore v:throwpoint! Does not
8694 * take care of memory allocations.
8695 */
8696 char_u *
8697v_throwpoint(oldval)
8698 char_u *oldval;
8699{
8700 if (oldval == NULL)
8701 return vimvars[VV_THROWPOINT].val;
8702
8703 vimvars[VV_THROWPOINT].val = oldval;
8704 return NULL;
8705}
8706
8707#if defined(FEAT_AUTOCMD) || defined(PROTO)
8708/*
8709 * Set v:cmdarg.
8710 * If "eap" != NULL, use "eap" to generate the value and return the old value.
8711 * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
8712 * Must always be called in pairs!
8713 */
8714 char_u *
8715set_cmdarg(eap, oldarg)
8716 exarg_T *eap;
8717 char_u *oldarg;
8718{
8719 char_u *oldval;
8720 char_u *newval;
8721 unsigned len;
8722
8723 oldval = vimvars[VV_CMDARG].val;
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00008724 if (eap == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008725 {
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00008726 vim_free(oldval);
8727 vimvars[VV_CMDARG].val = oldarg;
8728 return NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008729 }
8730
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00008731 if (eap->force_bin == FORCE_BIN)
8732 len = 6;
8733 else if (eap->force_bin == FORCE_NOBIN)
8734 len = 8;
8735 else
8736 len = 0;
8737 if (eap->force_ff != 0)
8738 len += (unsigned)STRLEN(eap->cmd + eap->force_ff) + 6;
8739# ifdef FEAT_MBYTE
8740 if (eap->force_enc != 0)
8741 len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
8742# endif
8743
8744 newval = alloc(len + 1);
8745 if (newval == NULL)
8746 return NULL;
8747
8748 if (eap->force_bin == FORCE_BIN)
8749 sprintf((char *)newval, " ++bin");
8750 else if (eap->force_bin == FORCE_NOBIN)
8751 sprintf((char *)newval, " ++nobin");
8752 else
8753 *newval = NUL;
8754 if (eap->force_ff != 0)
8755 sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
8756 eap->cmd + eap->force_ff);
8757# ifdef FEAT_MBYTE
8758 if (eap->force_enc != 0)
8759 sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
8760 eap->cmd + eap->force_enc);
8761# endif
8762 vimvars[VV_CMDARG].val = newval;
8763 return oldval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008764}
8765#endif
8766
8767/*
8768 * Get the value of internal variable "name".
8769 * Return OK or FAIL.
8770 */
8771 static int
8772get_var_var(name, len, retvar)
8773 char_u *name;
8774 int len; /* length of "name" */
8775 VAR retvar; /* NULL when only checking existence */
8776{
8777 int ret = OK;
8778 int type = VAR_UNKNOWN;
8779 long number = 1;
8780 char_u *string = NULL;
8781 VAR v;
8782 int cc;
8783 int i;
8784
8785 /* truncate the name, so that we can use strcmp() */
8786 cc = name[len];
8787 name[len] = NUL;
8788
8789 /*
8790 * Check for "b:changedtick".
8791 */
8792 if (STRCMP(name, "b:changedtick") == 0)
8793 {
8794 type = VAR_NUMBER;
8795 number = curbuf->b_changedtick;
8796 }
8797
8798 /*
8799 * Check for built-in v: variables.
8800 */
8801 else if ((i = find_vim_var(name, len)) >= 0)
8802 {
8803 type = vimvars[i].type;
8804 number = (long)vimvars[i].val;
8805 string = vimvars[i].val;
8806 }
8807
8808 /*
8809 * Check for user-defined variables.
8810 */
8811 else
8812 {
8813 v = find_var(name, FALSE);
8814 if (v != NULL)
8815 {
8816 type = v->var_type;
8817 number = v->var_val.var_number;
8818 string = v->var_val.var_string;
8819 }
8820 }
8821
8822 if (type == VAR_UNKNOWN)
8823 {
8824 if (retvar != NULL)
8825 EMSG2(_("E121: Undefined variable: %s"), name);
8826 ret = FAIL;
8827 }
8828 else if (retvar != NULL)
8829 {
8830 retvar->var_type = type;
8831 if (type == VAR_NUMBER)
8832 retvar->var_val.var_number = number;
8833 else if (type == VAR_STRING)
8834 {
8835 if (string != NULL)
8836 string = vim_strsave(string);
8837 retvar->var_val.var_string = string;
8838 }
8839 }
8840
8841 name[len] = cc;
8842
8843 return ret;
8844}
8845
8846/*
8847 * Allocate memory for a variable, and make it emtpy (0 or NULL value).
8848 */
8849 static VAR
8850alloc_var()
8851{
8852 return (VAR)alloc_clear((unsigned)sizeof(var));
8853}
8854
8855/*
8856 * Allocate memory for a variable, and assign a string to it.
8857 * The string "s" must have been allocated, it is consumed.
8858 * Return NULL for out of memory, the variable otherwise.
8859 */
8860 static VAR
8861alloc_string_var(s)
8862 char_u *s;
8863{
8864 VAR retvar;
8865
8866 retvar = alloc_var();
8867 if (retvar != NULL)
8868 {
8869 retvar->var_type = VAR_STRING;
8870 retvar->var_val.var_string = s;
8871 }
8872 else
8873 vim_free(s);
8874 return retvar;
8875}
8876
8877/*
8878 * Free the memory for a variable.
8879 */
8880 static void
8881free_var(varp)
8882 VAR varp;
8883{
8884 if (varp != NULL)
8885 {
8886 if (varp->var_type == VAR_STRING)
8887 vim_free(varp->var_val.var_string);
8888 vim_free(varp->var_name);
8889 vim_free(varp);
8890 }
8891}
8892
8893/*
8894 * Free the memory for a variable value and set the value to NULL or 0.
8895 */
8896 static void
8897clear_var(varp)
8898 VAR varp;
8899{
8900 if (varp != NULL)
8901 {
8902 if (varp->var_type == VAR_STRING)
8903 {
8904 vim_free(varp->var_val.var_string);
8905 varp->var_val.var_string = NULL;
8906 }
8907 else
8908 varp->var_val.var_number = 0;
8909 }
8910}
8911
8912/*
8913 * Get the number value of a variable.
8914 * If it is a String variable, uses vim_str2nr().
8915 */
8916 static long
8917get_var_number(varp)
8918 VAR varp;
8919{
8920 long n;
8921
8922 if (varp->var_type == VAR_NUMBER)
8923 return (long)(varp->var_val.var_number);
8924 else if (varp->var_type == VAR_UNKNOWN || varp->var_val.var_string == NULL)
8925 return 0L;
8926 else
8927 {
8928 vim_str2nr(varp->var_val.var_string, NULL, NULL, TRUE, TRUE, &n, NULL);
8929 return n;
8930 }
8931}
8932
8933/*
8934 * Get the lnum from the first argument. Also accepts ".", "$", etc.
8935 */
8936 static linenr_T
8937get_var_lnum(argvars)
8938 VAR argvars;
8939{
8940 var retvar;
8941 linenr_T lnum;
8942
8943 lnum = get_var_number(&argvars[0]);
8944 if (lnum == 0) /* no valid number, try using line() */
8945 {
8946 retvar.var_type = VAR_NUMBER;
8947 f_line(argvars, &retvar);
8948 lnum = retvar.var_val.var_number;
8949 clear_var(&retvar);
8950 }
8951 return lnum;
8952}
8953
8954/*
8955 * Get the string value of a variable.
8956 * If it is a Number variable, the number is converted into a string.
8957 * get_var_string() uses a single, static buffer. YOU CAN ONLY USE IT ONCE!
8958 * get_var_string_buf() uses a given buffer.
8959 * If the String variable has never been set, return an empty string.
8960 * Never returns NULL;
8961 */
8962 static char_u *
8963get_var_string(varp)
8964 VAR varp;
8965{
8966 static char_u mybuf[NUMBUFLEN];
8967
8968 return get_var_string_buf(varp, mybuf);
8969}
8970
8971 static char_u *
8972get_var_string_buf(varp, buf)
8973 VAR varp;
8974 char_u *buf;
8975{
8976 if (varp->var_type == VAR_NUMBER)
8977 {
8978 sprintf((char *)buf, "%ld", (long)varp->var_val.var_number);
8979 return buf;
8980 }
8981 else if (varp->var_val.var_string == NULL)
8982 return (char_u *)"";
8983 else
8984 return varp->var_val.var_string;
8985}
8986
8987/*
8988 * Find variable "name" in the list of variables.
8989 * Return a pointer to it if found, NULL if not found.
8990 */
8991 static VAR
8992find_var(name, writing)
8993 char_u *name;
8994 int writing;
8995{
8996 int i;
8997 char_u *varname;
8998 garray_T *gap;
8999
9000 /* Check for function arguments "a:" */
9001 if (name[0] == 'a' && name[1] == ':')
9002 {
9003 if (writing)
9004 {
9005 EMSG2(_(e_readonlyvar), name);
9006 return NULL;
9007 }
9008 name += 2;
9009 if (current_funccal == NULL)
9010 return NULL;
9011 if (VIM_ISDIGIT(*name))
9012 {
9013 i = atol((char *)name);
9014 if (i == 0) /* a:0 */
9015 return &current_funccal->a0_var;
9016 i += current_funccal->func->args.ga_len;
9017 if (i > current_funccal->argcount) /* a:999 */
9018 return NULL;
9019 return &(current_funccal->argvars[i - 1]); /* a:1, a:2, etc. */
9020 }
9021 if (STRCMP(name, "firstline") == 0)
9022 return &(current_funccal->firstline);
9023 if (STRCMP(name, "lastline") == 0)
9024 return &(current_funccal->lastline);
9025 for (i = 0; i < current_funccal->func->args.ga_len; ++i)
9026 if (STRCMP(name, ((char_u **)
9027 (current_funccal->func->args.ga_data))[i]) == 0)
9028 return &(current_funccal->argvars[i]); /* a:name */
9029 return NULL;
9030 }
9031
9032 gap = find_var_ga(name, &varname);
9033 if (gap == NULL)
9034 return NULL;
9035 return find_var_in_ga(gap, varname);
9036}
9037
9038 static VAR
9039find_var_in_ga(gap, varname)
9040 garray_T *gap;
9041 char_u *varname;
9042{
9043 int i;
9044
9045 for (i = gap->ga_len; --i >= 0; )
9046 if (VAR_GAP_ENTRY(i, gap).var_name != NULL
9047 && STRCMP(VAR_GAP_ENTRY(i, gap).var_name, varname) == 0)
9048 break;
9049 if (i < 0)
9050 return NULL;
9051 return &VAR_GAP_ENTRY(i, gap);
9052}
9053
9054/*
9055 * Find the growarray and start of name without ':' for a variable name.
9056 */
9057 static garray_T *
9058find_var_ga(name, varname)
9059 char_u *name;
9060 char_u **varname;
9061{
9062 if (name[1] != ':')
9063 {
9064 /* If not "x:name" there must not be any ":" in the name. */
9065 if (vim_strchr(name, ':') != NULL)
9066 return NULL;
9067 *varname = name;
9068 if (current_funccal == NULL)
9069 return &variables; /* global variable */
9070 return &current_funccal->l_vars; /* local function variable */
9071 }
9072 *varname = name + 2;
9073 if (*name == 'b') /* buffer variable */
9074 return &curbuf->b_vars;
9075 if (*name == 'w') /* window variable */
9076 return &curwin->w_vars;
9077 if (*name == 'g') /* global variable */
9078 return &variables;
9079 if (*name == 'l' && current_funccal != NULL)/* local function variable */
9080 return &current_funccal->l_vars;
9081 if (*name == 's' /* script variable */
9082 && current_SID > 0 && current_SID <= ga_scripts.ga_len)
9083 return &SCRIPT_VARS(current_SID);
9084 return NULL;
9085}
9086
9087/*
9088 * Get the string value of a (global/local) variable.
9089 * Returns NULL when it doesn't exist.
9090 */
9091 char_u *
9092get_var_value(name)
9093 char_u *name;
9094{
9095 VAR v;
9096
9097 v = find_var(name, FALSE);
9098 if (v == NULL)
9099 return NULL;
9100 return get_var_string(v);
9101}
9102
9103/*
9104 * Allocate a new growarry for a sourced script. It will be used while
9105 * sourcing this script and when executing functions defined in the script.
9106 */
9107 void
9108new_script_vars(id)
9109 scid_T id;
9110{
9111 if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK)
9112 {
9113 while (ga_scripts.ga_len < id)
9114 {
9115 var_init(&SCRIPT_VARS(ga_scripts.ga_len + 1));
9116 ++ga_scripts.ga_len;
9117 --ga_scripts.ga_room;
9118 }
9119 }
9120}
9121
9122/*
9123 * Initialize internal variables for use.
9124 */
9125 void
9126var_init(gap)
9127 garray_T *gap;
9128{
9129 ga_init2(gap, (int)sizeof(var), 4);
9130}
9131
9132/*
9133 * Clean up a list of internal variables.
9134 */
9135 void
9136var_clear(gap)
9137 garray_T *gap;
9138{
9139 int i;
9140
9141 for (i = gap->ga_len; --i >= 0; )
9142 var_free_one(&VAR_GAP_ENTRY(i, gap));
9143 ga_clear(gap);
9144}
9145
9146 static void
9147var_free_one(v)
9148 VAR v;
9149{
9150 vim_free(v->var_name);
9151 v->var_name = NULL;
9152 if (v->var_type == VAR_STRING)
9153 vim_free(v->var_val.var_string);
9154 v->var_val.var_string = NULL;
9155}
9156
9157/*
9158 * List the value of one internal variable.
9159 */
9160 static void
9161list_one_var(v, prefix)
9162 VAR v;
9163 char_u *prefix;
9164{
9165 list_one_var_a(prefix, v->var_name, v->var_type, get_var_string(v));
9166}
9167
9168/*
9169 * List the value of one "v:" variable.
9170 */
9171 static void
9172list_vim_var(i)
9173 int i; /* index in vimvars[] */
9174{
9175 char_u *p;
9176 char_u numbuf[NUMBUFLEN];
9177
9178 if (vimvars[i].type == VAR_NUMBER)
9179 {
9180 p = numbuf;
9181 sprintf((char *)p, "%ld", (long)vimvars[i].val);
9182 }
9183 else if (vimvars[i].val == NULL)
9184 p = (char_u *)"";
9185 else
9186 p = vimvars[i].val;
9187 list_one_var_a((char_u *)"v:", (char_u *)vimvars[i].name,
9188 vimvars[i].type, p);
9189}
9190
9191 static void
9192list_one_var_a(prefix, name, type, string)
9193 char_u *prefix;
9194 char_u *name;
9195 int type;
9196 char_u *string;
9197{
9198 msg_attr(prefix, 0); /* don't use msg(), it overwrites "v:statusmsg" */
9199 if (name != NULL) /* "a:" vars don't have a name stored */
9200 msg_puts(name);
9201 msg_putchar(' ');
9202 msg_advance(22);
9203 if (type == VAR_NUMBER)
9204 msg_putchar('#');
9205 else
9206 msg_putchar(' ');
9207 msg_outtrans(string);
9208}
9209
9210/*
9211 * Set variable "name" to value in "varp".
9212 * If the variable already exists, the value is updated.
9213 * Otherwise the variable is created.
9214 */
9215 static void
9216set_var(name, varp)
9217 char_u *name;
9218 VAR varp;
9219{
9220 int i;
9221 VAR v;
9222 char_u *varname;
9223 garray_T *gap;
9224
9225 /*
9226 * Handle setting internal v: variables.
9227 */
9228 i = find_vim_var(name, (int)STRLEN(name));
9229 if (i >= 0)
9230 {
9231 if (vimvars[i].flags & VV_RO)
9232 EMSG2(_(e_readonlyvar), name);
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00009233 else if ((vimvars[i].flags & VV_RO_SBX) && sandbox)
9234 EMSG2(_(e_readonlysbx), name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00009235 else
9236 {
9237 if (vimvars[i].type == VAR_STRING)
9238 {
9239 vim_free(vimvars[i].val);
9240 vimvars[i].val = vim_strsave(get_var_string(varp));
9241 }
9242 else
9243 vimvars[i].val = (char_u *)(long)varp->var_val.var_number;
9244 }
9245 return;
9246 }
9247
9248 v = find_var(name, TRUE);
9249 if (v != NULL) /* existing variable, only need to free string */
9250 {
9251 if (v->var_type == VAR_STRING)
9252 vim_free(v->var_val.var_string);
9253 }
9254 else /* add a new variable */
9255 {
9256 gap = find_var_ga(name, &varname);
9257 if (gap == NULL) /* illegal name */
9258 {
9259 EMSG2(_("E461: Illegal variable name: %s"), name);
9260 return;
9261 }
9262
9263 /* Try to use an empty entry */
9264 for (i = gap->ga_len; --i >= 0; )
9265 if (VAR_GAP_ENTRY(i, gap).var_name == NULL)
9266 break;
9267 if (i < 0) /* need to allocate more room */
9268 {
9269 if (ga_grow(gap, 1) == FAIL)
9270 return;
9271 i = gap->ga_len;
9272 }
9273 v = &VAR_GAP_ENTRY(i, gap);
9274 if ((v->var_name = vim_strsave(varname)) == NULL)
9275 return;
9276 if (i == gap->ga_len)
9277 {
9278 ++gap->ga_len;
9279 --gap->ga_room;
9280 }
9281 }
9282 copy_var(varp, v);
9283}
9284
9285 static void
9286copy_var(from, to)
9287 VAR from;
9288 VAR to;
9289{
9290 to->var_type = from->var_type;
9291 if (from->var_type == VAR_STRING)
9292 to->var_val.var_string = vim_strsave(get_var_string(from));
9293 else
9294 to->var_val.var_number = from->var_val.var_number;
9295}
9296
9297/*
9298 * ":echo expr1 ..." print each argument separated with a space, add a
9299 * newline at the end.
9300 * ":echon expr1 ..." print each argument plain.
9301 */
9302 void
9303ex_echo(eap)
9304 exarg_T *eap;
9305{
9306 char_u *arg = eap->arg;
9307 var retvar;
9308 char_u *p;
9309 int needclr = TRUE;
9310 int atstart = TRUE;
9311
9312 if (eap->skip)
9313 ++emsg_skip;
9314 while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int)
9315 {
9316 p = arg;
9317 if (eval1(&arg, &retvar, !eap->skip) == FAIL)
9318 {
9319 /*
9320 * Report the invalid expression unless the expression evaluation
9321 * has been cancelled due to an aborting error, an interrupt, or an
9322 * exception.
9323 */
9324 if (!aborting())
9325 EMSG2(_(e_invexpr2), p);
9326 break;
9327 }
9328 if (!eap->skip)
9329 {
9330 if (atstart)
9331 {
9332 atstart = FALSE;
9333 /* Call msg_start() after eval1(), evaluating the expression
9334 * may cause a message to appear. */
9335 if (eap->cmdidx == CMD_echo)
9336 msg_start();
9337 }
9338 else if (eap->cmdidx == CMD_echo)
9339 msg_puts_attr((char_u *)" ", echo_attr);
9340 for (p = get_var_string(&retvar); *p != NUL && !got_int; ++p)
9341 if (*p == '\n' || *p == '\r' || *p == TAB)
9342 {
9343 if (*p != TAB && needclr)
9344 {
9345 /* remove any text still there from the command */
9346 msg_clr_eos();
9347 needclr = FALSE;
9348 }
9349 msg_putchar_attr(*p, echo_attr);
9350 }
9351 else
9352 {
9353#ifdef FEAT_MBYTE
9354 if (has_mbyte)
9355 {
9356 int i = (*mb_ptr2len_check)(p);
9357
9358 (void)msg_outtrans_len_attr(p, i, echo_attr);
9359 p += i - 1;
9360 }
9361 else
9362#endif
9363 (void)msg_outtrans_len_attr(p, 1, echo_attr);
9364 }
9365 }
9366 clear_var(&retvar);
9367 arg = skipwhite(arg);
9368 }
9369 eap->nextcmd = check_nextcmd(arg);
9370
9371 if (eap->skip)
9372 --emsg_skip;
9373 else
9374 {
9375 /* remove text that may still be there from the command */
9376 if (needclr)
9377 msg_clr_eos();
9378 if (eap->cmdidx == CMD_echo)
9379 msg_end();
9380 }
9381}
9382
9383/*
9384 * ":echohl {name}".
9385 */
9386 void
9387ex_echohl(eap)
9388 exarg_T *eap;
9389{
9390 int id;
9391
9392 id = syn_name2id(eap->arg);
9393 if (id == 0)
9394 echo_attr = 0;
9395 else
9396 echo_attr = syn_id2attr(id);
9397}
9398
9399/*
9400 * ":execute expr1 ..." execute the result of an expression.
9401 * ":echomsg expr1 ..." Print a message
9402 * ":echoerr expr1 ..." Print an error
9403 * Each gets spaces around each argument and a newline at the end for
9404 * echo commands
9405 */
9406 void
9407ex_execute(eap)
9408 exarg_T *eap;
9409{
9410 char_u *arg = eap->arg;
9411 var retvar;
9412 int ret = OK;
9413 char_u *p;
9414 garray_T ga;
9415 int len;
9416 int save_did_emsg;
9417
9418 ga_init2(&ga, 1, 80);
9419
9420 if (eap->skip)
9421 ++emsg_skip;
9422 while (*arg != NUL && *arg != '|' && *arg != '\n')
9423 {
9424 p = arg;
9425 if (eval1(&arg, &retvar, !eap->skip) == FAIL)
9426 {
9427 /*
9428 * Report the invalid expression unless the expression evaluation
9429 * has been cancelled due to an aborting error, an interrupt, or an
9430 * exception.
9431 */
9432 if (!aborting())
9433 EMSG2(_(e_invexpr2), p);
9434 ret = FAIL;
9435 break;
9436 }
9437
9438 if (!eap->skip)
9439 {
9440 p = get_var_string(&retvar);
9441 len = (int)STRLEN(p);
9442 if (ga_grow(&ga, len + 2) == FAIL)
9443 {
9444 clear_var(&retvar);
9445 ret = FAIL;
9446 break;
9447 }
9448 if (ga.ga_len)
9449 {
9450 ((char_u *)(ga.ga_data))[ga.ga_len++] = ' ';
9451 --ga.ga_room;
9452 }
9453 STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p);
9454 ga.ga_room -= len;
9455 ga.ga_len += len;
9456 }
9457
9458 clear_var(&retvar);
9459 arg = skipwhite(arg);
9460 }
9461
9462 if (ret != FAIL && ga.ga_data != NULL)
9463 {
9464 if (eap->cmdidx == CMD_echomsg)
9465 MSG_ATTR(ga.ga_data, echo_attr);
9466 else if (eap->cmdidx == CMD_echoerr)
9467 {
9468 /* We don't want to abort following commands, restore did_emsg. */
9469 save_did_emsg = did_emsg;
9470 EMSG((char_u *)ga.ga_data);
9471 if (!force_abort)
9472 did_emsg = save_did_emsg;
9473 }
9474 else if (eap->cmdidx == CMD_execute)
9475 do_cmdline((char_u *)ga.ga_data,
9476 eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE);
9477 }
9478
9479 ga_clear(&ga);
9480
9481 if (eap->skip)
9482 --emsg_skip;
9483
9484 eap->nextcmd = check_nextcmd(arg);
9485}
9486
9487/*
9488 * Skip over the name of an option: "&option", "&g:option" or "&l:option".
9489 * "arg" points to the "&" or '+' when called, to "option" when returning.
9490 * Returns NULL when no option name found. Otherwise pointer to the char
9491 * after the option name.
9492 */
9493 static char_u *
9494find_option_end(arg, opt_flags)
9495 char_u **arg;
9496 int *opt_flags;
9497{
9498 char_u *p = *arg;
9499
9500 ++p;
9501 if (*p == 'g' && p[1] == ':')
9502 {
9503 *opt_flags = OPT_GLOBAL;
9504 p += 2;
9505 }
9506 else if (*p == 'l' && p[1] == ':')
9507 {
9508 *opt_flags = OPT_LOCAL;
9509 p += 2;
9510 }
9511 else
9512 *opt_flags = 0;
9513
9514 if (!ASCII_ISALPHA(*p))
9515 return NULL;
9516 *arg = p;
9517
9518 if (p[0] == 't' && p[1] == '_' && p[2] != NUL && p[3] != NUL)
9519 p += 4; /* termcap option */
9520 else
9521 while (ASCII_ISALPHA(*p))
9522 ++p;
9523 return p;
9524}
9525
9526/*
9527 * ":function"
9528 */
9529 void
9530ex_function(eap)
9531 exarg_T *eap;
9532{
9533 char_u *theline;
9534 int j;
9535 int c;
9536#ifdef FEAT_MAGIC_BRACES
9537 int saved_did_emsg;
9538#endif
9539 char_u *name = NULL;
9540 char_u *p;
9541 char_u *arg;
9542 garray_T newargs;
9543 garray_T newlines;
9544 int varargs = FALSE;
9545 int mustend = FALSE;
9546 int flags = 0;
9547 ufunc_T *fp;
9548 int indent;
9549 int nesting;
9550 char_u *skip_until = NULL;
9551 static char_u e_funcexts[] = N_("E122: Function %s already exists, add ! to replace it");
9552
9553 /*
9554 * ":function" without argument: list functions.
9555 */
9556 if (ends_excmd(*eap->arg))
9557 {
9558 if (!eap->skip)
9559 for (fp = firstfunc; fp != NULL && !got_int; fp = fp->next)
9560 list_func_head(fp, FALSE);
9561 eap->nextcmd = check_nextcmd(eap->arg);
9562 return;
9563 }
9564
9565 p = eap->arg;
9566 name = trans_function_name(&p, eap->skip, FALSE);
9567 if (name == NULL && !eap->skip)
9568 {
9569 /*
9570 * Return on an invalid expression in braces, unless the expression
9571 * evaluation has been cancelled due to an aborting error, an
9572 * interrupt, or an exception.
9573 */
9574 if (!aborting())
9575 return;
9576 else
9577 eap->skip = TRUE;
9578 }
9579#ifdef FEAT_MAGIC_BRACES
9580 /* An error in a function call during evaluation of an expression in magic
9581 * braces should not cause the function not to be defined. */
9582 saved_did_emsg = did_emsg;
9583 did_emsg = FALSE;
9584#endif
9585
9586 /*
9587 * ":function func" with only function name: list function.
9588 */
9589 if (vim_strchr(p, '(') == NULL)
9590 {
9591 if (!ends_excmd(*skipwhite(p)))
9592 {
9593 EMSG(_(e_trailing));
9594 goto erret_name;
9595 }
9596 eap->nextcmd = check_nextcmd(p);
9597 if (eap->nextcmd != NULL)
9598 *p = NUL;
9599 if (!eap->skip && !got_int)
9600 {
9601 fp = find_func(name);
9602 if (fp != NULL)
9603 {
9604 list_func_head(fp, TRUE);
9605 for (j = 0; j < fp->lines.ga_len && !got_int; ++j)
9606 {
9607 msg_putchar('\n');
9608 msg_outnum((long)(j + 1));
9609 if (j < 9)
9610 msg_putchar(' ');
9611 if (j < 99)
9612 msg_putchar(' ');
9613 msg_prt_line(FUNCLINE(fp, j));
9614 out_flush(); /* show a line at a time */
9615 ui_breakcheck();
9616 }
9617 if (!got_int)
9618 {
9619 msg_putchar('\n');
9620 msg_puts((char_u *)" endfunction");
9621 }
9622 }
9623 else
9624 EMSG2(_("E123: Undefined function: %s"), eap->arg);
9625 }
9626 goto erret_name;
9627 }
9628
9629 /*
9630 * ":function name(arg1, arg2)" Define function.
9631 */
9632 p = skipwhite(p);
9633 if (*p != '(')
9634 {
9635 if (!eap->skip)
9636 {
9637 EMSG2(_("E124: Missing '(': %s"), eap->arg);
9638 goto erret_name;
9639 }
9640 /* attempt to continue by skipping some text */
9641 if (vim_strchr(p, '(') != NULL)
9642 p = vim_strchr(p, '(');
9643 }
9644 p = skipwhite(p + 1);
9645
9646 ga_init2(&newargs, (int)sizeof(char_u *), 3);
9647 ga_init2(&newlines, (int)sizeof(char_u *), 3);
9648
9649 /*
9650 * Isolate the arguments: "arg1, arg2, ...)"
9651 */
9652 while (*p != ')')
9653 {
9654 if (p[0] == '.' && p[1] == '.' && p[2] == '.')
9655 {
9656 varargs = TRUE;
9657 p += 3;
9658 mustend = TRUE;
9659 }
9660 else
9661 {
9662 arg = p;
9663 while (ASCII_ISALNUM(*p) || *p == '_')
9664 ++p;
9665 if (arg == p || isdigit(*arg)
9666 || (p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0)
9667 || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0))
9668 {
9669 if (!eap->skip)
9670 EMSG2(_("E125: Illegal argument: %s"), arg);
9671 break;
9672 }
9673 if (ga_grow(&newargs, 1) == FAIL)
9674 goto erret;
9675 c = *p;
9676 *p = NUL;
9677 arg = vim_strsave(arg);
9678 if (arg == NULL)
9679 goto erret;
9680 ((char_u **)(newargs.ga_data))[newargs.ga_len] = arg;
9681 *p = c;
9682 newargs.ga_len++;
9683 newargs.ga_room--;
9684 if (*p == ',')
9685 ++p;
9686 else
9687 mustend = TRUE;
9688 }
9689 p = skipwhite(p);
9690 if (mustend && *p != ')')
9691 {
9692 if (!eap->skip)
9693 EMSG2(_(e_invarg2), eap->arg);
9694 break;
9695 }
9696 }
9697 ++p; /* skip the ')' */
9698
9699 /* find extra arguments "range" and "abort" */
9700 for (;;)
9701 {
9702 p = skipwhite(p);
9703 if (STRNCMP(p, "range", 5) == 0)
9704 {
9705 flags |= FC_RANGE;
9706 p += 5;
9707 }
9708 else if (STRNCMP(p, "abort", 5) == 0)
9709 {
9710 flags |= FC_ABORT;
9711 p += 5;
9712 }
9713 else
9714 break;
9715 }
9716
9717 if (*p != NUL && *p != '"' && *p != '\n' && !eap->skip && !did_emsg)
9718 EMSG(_(e_trailing));
9719
9720 /*
9721 * Read the body of the function, until ":endfunction" is found.
9722 */
9723 if (KeyTyped)
9724 {
9725 /* Check if the function already exists, don't let the user type the
9726 * whole function before telling him it doesn't work! For a script we
9727 * need to skip the body to be able to find what follows. */
9728 if (!eap->skip && !eap->forceit && find_func(name) != NULL)
9729 EMSG2(_(e_funcexts), name);
9730
9731 msg_putchar('\n'); /* don't overwrite the function name */
9732 cmdline_row = msg_row;
9733 }
9734
9735 indent = 2;
9736 nesting = 0;
9737 for (;;)
9738 {
9739 msg_scroll = TRUE;
9740 need_wait_return = FALSE;
9741 if (eap->getline == NULL)
9742 theline = getcmdline(':', 0L, indent);
9743 else
9744 theline = eap->getline(':', eap->cookie, indent);
9745 if (KeyTyped)
9746 lines_left = Rows - 1;
9747 if (theline == NULL)
9748 {
9749 EMSG(_("E126: Missing :endfunction"));
9750 goto erret;
9751 }
9752
9753 if (skip_until != NULL)
9754 {
9755 /* between ":append" and "." and between ":python <<EOF" and "EOF"
9756 * don't check for ":endfunc". */
9757 if (STRCMP(theline, skip_until) == 0)
9758 {
9759 vim_free(skip_until);
9760 skip_until = NULL;
9761 }
9762 }
9763 else
9764 {
9765 /* skip ':' and blanks*/
9766 for (p = theline; vim_iswhite(*p) || *p == ':'; ++p)
9767 ;
9768
9769 /* Check for "endfunction" (should be more strict...). */
9770 if (STRNCMP(p, "endf", 4) == 0 && nesting-- == 0)
9771 {
9772 vim_free(theline);
9773 break;
9774 }
9775
9776 /* Increase indent inside "if", "while", and "try", decrease
9777 * at "end". */
9778 if (indent > 2 && STRNCMP(p, "end", 3) == 0)
9779 indent -= 2;
9780 else if (STRNCMP(p, "if", 2) == 0 || STRNCMP(p, "wh", 2) == 0
9781 || STRNCMP(p, "try", 3) == 0)
9782 indent += 2;
9783
9784 /* Check for defining a function inside this function. */
9785 if (STRNCMP(p, "fu", 2) == 0)
9786 {
9787 p = skipwhite(skiptowhite(p));
9788 p += eval_fname_script(p);
9789 if (ASCII_ISALPHA(*p))
9790 {
9791 vim_free(trans_function_name(&p, TRUE, FALSE));
9792 if (*skipwhite(p) == '(')
9793 {
9794 ++nesting;
9795 indent += 2;
9796 }
9797 }
9798 }
9799
9800 /* Check for ":append" or ":insert". */
9801 p = skip_range(p, NULL);
9802 if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
9803 || (p[0] == 'i'
9804 && (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
9805 && (!ASCII_ISALPHA(p[2]) || (p[2] == 's'))))))
9806 skip_until = vim_strsave((char_u *)".");
9807
9808 /* Check for ":python <<EOF", ":tcl <<EOF", etc. */
9809 arg = skipwhite(skiptowhite(p));
9810 if (arg[0] == '<' && arg[1] =='<'
9811 && ((p[0] == 'p' && p[1] == 'y'
9812 && (!ASCII_ISALPHA(p[2]) || p[2] == 't'))
9813 || (p[0] == 'p' && p[1] == 'e'
9814 && (!ASCII_ISALPHA(p[2]) || p[2] == 'r'))
9815 || (p[0] == 't' && p[1] == 'c'
9816 && (!ASCII_ISALPHA(p[2]) || p[2] == 'l'))
9817 || (p[0] == 'r' && p[1] == 'u' && p[2] == 'b'
9818 && (!ASCII_ISALPHA(p[3]) || p[3] == 'y'))
Bram Moolenaar325b7a22004-07-05 15:58:32 +00009819 || (p[0] == 'm' && p[1] == 'z'
9820 && (!ASCII_ISALPHA(p[2]) || p[2] == 's'))
Bram Moolenaar071d4272004-06-13 20:20:40 +00009821 ))
9822 {
9823 /* ":python <<" continues until a dot, like ":append" */
9824 p = skipwhite(arg + 2);
9825 if (*p == NUL)
9826 skip_until = vim_strsave((char_u *)".");
9827 else
9828 skip_until = vim_strsave(p);
9829 }
9830 }
9831
9832 /* Add the line to the function. */
9833 if (ga_grow(&newlines, 1) == FAIL)
9834 goto erret;
9835 ((char_u **)(newlines.ga_data))[newlines.ga_len] = theline;
9836 newlines.ga_len++;
9837 newlines.ga_room--;
9838 }
9839
9840 /* Don't define the function when skipping commands or when an error was
9841 * detected. */
9842 if (eap->skip || did_emsg)
9843 goto erret;
9844
9845 /*
9846 * If there are no errors, add the function
9847 */
9848 fp = find_func(name);
9849 if (fp != NULL)
9850 {
9851 if (!eap->forceit)
9852 {
9853 EMSG2(_(e_funcexts), name);
9854 goto erret;
9855 }
9856 if (fp->calls)
9857 {
9858 EMSG2(_("E127: Cannot redefine function %s: It is in use"), name);
9859 goto erret;
9860 }
9861 /* redefine existing function */
9862 ga_clear_strings(&(fp->args));
9863 ga_clear_strings(&(fp->lines));
9864 vim_free(name);
9865 }
9866 else
9867 {
9868 fp = (ufunc_T *)alloc((unsigned)sizeof(ufunc_T));
9869 if (fp == NULL)
9870 goto erret;
9871 /* insert the new function in the function list */
9872 fp->next = firstfunc;
9873 firstfunc = fp;
9874 fp->name = name;
9875 }
9876 fp->args = newargs;
9877 fp->lines = newlines;
9878 fp->varargs = varargs;
9879 fp->flags = flags;
9880 fp->calls = 0;
9881 fp->script_ID = current_SID;
9882#ifdef FEAT_MAGIC_BRACES
9883 did_emsg |= saved_did_emsg;
9884#endif
9885 vim_free(skip_until);
9886 return;
9887
9888erret:
9889 vim_free(skip_until);
9890 ga_clear_strings(&newargs);
9891 ga_clear_strings(&newlines);
9892erret_name:
9893 vim_free(name);
9894#ifdef FEAT_MAGIC_BRACES
9895 did_emsg |= saved_did_emsg;
9896#endif
9897}
9898
9899/*
9900 * Get a function name, translating "<SID>" and "<SNR>".
9901 * Returns the function name in allocated memory, or NULL for failure.
9902 * Advances "pp" to just after the function name (if no error).
9903 */
9904 static char_u *
9905trans_function_name(pp, skip, internal)
9906 char_u **pp;
9907 int skip; /* only find the end, don't evaluate */
9908 int internal; /* TRUE if internal function name OK */
9909{
9910 char_u *name;
9911 char_u *start;
9912 char_u *end;
9913 int lead;
9914 char_u sid_buf[20];
9915 char_u *temp_string = NULL;
9916 char_u *expr_start, *expr_end;
9917 int len;
9918
9919 /* A name starting with "<SID>" or "<SNR>" is local to a script. */
9920 start = *pp;
9921 lead = eval_fname_script(start);
9922 if (lead > 0)
9923 start += lead;
9924 end = find_name_end(start, &expr_start, &expr_end);
9925 if (end == start)
9926 {
9927 if (!skip)
9928 EMSG(_("E129: Function name required"));
9929 return NULL;
9930 }
9931#ifdef FEAT_MAGIC_BRACES
9932 if (expr_start != NULL && !skip)
9933 {
9934 /* expand magic curlies */
9935 temp_string = make_expanded_name(start, expr_start, expr_end, end);
9936 if (temp_string == NULL)
9937 {
9938 /*
9939 * Report an invalid expression in braces, unless the expression
9940 * evaluation has been cancelled due to an aborting error, an
9941 * interrupt, or an exception.
9942 */
9943 if (!aborting())
9944 EMSG2(_(e_invarg2), start);
9945 else
9946 *pp = end;
9947 return NULL;
9948 }
9949 start = temp_string;
9950 len = (int)STRLEN(temp_string);
9951 }
9952 else
9953#endif
9954 len = (int)(end - start);
9955
9956 /*
9957 * Copy the function name to allocated memory.
9958 * Accept <SID>name() inside a script, translate into <SNR>123_name().
9959 * Accept <SNR>123_name() outside a script.
9960 */
9961 if (skip)
9962 lead = 0; /* do nothing */
9963 else if (lead > 0)
9964 {
9965 lead = 3;
9966 if (eval_fname_sid(*pp)) /* If it's "<SID>" */
9967 {
9968 if (current_SID <= 0)
9969 {
9970 EMSG(_(e_usingsid));
9971 return NULL;
9972 }
9973 sprintf((char *)sid_buf, "%ld_", (long)current_SID);
9974 lead += (int)STRLEN(sid_buf);
9975 }
9976 }
9977 else if (!internal && !ASCII_ISUPPER(*start))
9978 {
9979 EMSG2(_("E128: Function name must start with a capital: %s"), start);
9980 return NULL;
9981 }
9982 name = alloc((unsigned)(len + lead + 1));
9983 if (name != NULL)
9984 {
9985 if (lead > 0)
9986 {
9987 name[0] = K_SPECIAL;
9988 name[1] = KS_EXTRA;
9989 name[2] = (int)KE_SNR;
9990 if (eval_fname_sid(*pp)) /* If it's "<SID>" */
9991 STRCPY(name + 3, sid_buf);
9992 }
9993 mch_memmove(name + lead, start, (size_t)len);
9994 name[len + lead] = NUL;
9995 }
9996 *pp = end;
9997
9998 vim_free(temp_string);
9999 return name;
10000}
10001
10002/*
10003 * Return 5 if "p" starts with "<SID>" or "<SNR>" (ignoring case).
10004 * Return 2 if "p" starts with "s:".
10005 * Return 0 otherwise.
10006 */
10007 static int
10008eval_fname_script(p)
10009 char_u *p;
10010{
10011 if (p[0] == '<' && (STRNICMP(p + 1, "SID>", 4) == 0
10012 || STRNICMP(p + 1, "SNR>", 4) == 0))
10013 return 5;
10014 if (p[0] == 's' && p[1] == ':')
10015 return 2;
10016 return 0;
10017}
10018
10019/*
10020 * Return TRUE if "p" starts with "<SID>" or "s:".
10021 * Only works if eval_fname_script() returned non-zero for "p"!
10022 */
10023 static int
10024eval_fname_sid(p)
10025 char_u *p;
10026{
10027 return (*p == 's' || TOUPPER_ASC(p[2]) == 'I');
10028}
10029
10030/*
10031 * List the head of the function: "name(arg1, arg2)".
10032 */
10033 static void
10034list_func_head(fp, indent)
10035 ufunc_T *fp;
10036 int indent;
10037{
10038 int j;
10039
10040 msg_start();
10041 if (indent)
10042 MSG_PUTS(" ");
10043 MSG_PUTS("function ");
10044 if (fp->name[0] == K_SPECIAL)
10045 {
10046 MSG_PUTS_ATTR("<SNR>", hl_attr(HLF_8));
10047 msg_puts(fp->name + 3);
10048 }
10049 else
10050 msg_puts(fp->name);
10051 msg_putchar('(');
10052 for (j = 0; j < fp->args.ga_len; ++j)
10053 {
10054 if (j)
10055 MSG_PUTS(", ");
10056 msg_puts(FUNCARG(fp, j));
10057 }
10058 if (fp->varargs)
10059 {
10060 if (j)
10061 MSG_PUTS(", ");
10062 MSG_PUTS("...");
10063 }
10064 msg_putchar(')');
10065}
10066
10067/*
10068 * Find a function by name, return pointer to it in ufuncs.
10069 * Return NULL for unknown function.
10070 */
10071 static ufunc_T *
10072find_func(name)
10073 char_u *name;
10074{
10075 ufunc_T *fp;
10076
10077 for (fp = firstfunc; fp != NULL; fp = fp->next)
10078 if (STRCMP(name, fp->name) == 0)
10079 break;
10080 return fp;
10081}
10082
10083#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
10084
10085/*
10086 * Function given to ExpandGeneric() to obtain the list of user defined
10087 * function names.
10088 */
10089 char_u *
10090get_user_func_name(xp, idx)
10091 expand_T *xp;
10092 int idx;
10093{
10094 static ufunc_T *fp = NULL;
10095
10096 if (idx == 0)
10097 fp = firstfunc;
10098 if (fp != NULL)
10099 {
10100 if (STRLEN(fp->name) + 4 >= IOSIZE)
10101 return fp->name; /* prevents overflow */
10102
10103 cat_func_name(IObuff, fp);
10104 if (xp->xp_context != EXPAND_USER_FUNC)
10105 {
10106 STRCAT(IObuff, "(");
10107 if (!fp->varargs && fp->args.ga_len == 0)
10108 STRCAT(IObuff, ")");
10109 }
10110
10111 fp = fp->next;
10112 return IObuff;
10113 }
10114 return NULL;
10115}
10116
10117#endif /* FEAT_CMDL_COMPL */
10118
10119/*
10120 * Copy the function name of "fp" to buffer "buf".
10121 * "buf" must be able to hold the function name plus three bytes.
10122 * Takes care of script-local function names.
10123 */
10124 static void
10125cat_func_name(buf, fp)
10126 char_u *buf;
10127 ufunc_T *fp;
10128{
10129 if (fp->name[0] == K_SPECIAL)
10130 {
10131 STRCPY(buf, "<SNR>");
10132 STRCAT(buf, fp->name + 3);
10133 }
10134 else
10135 STRCPY(buf, fp->name);
10136}
10137
10138/*
10139 * ":delfunction {name}"
10140 */
10141 void
10142ex_delfunction(eap)
10143 exarg_T *eap;
10144{
10145 ufunc_T *fp = NULL, *pfp;
10146 char_u *p;
10147 char_u *name;
10148
10149 p = eap->arg;
10150 name = trans_function_name(&p, eap->skip, FALSE);
10151 if (name == NULL)
10152 return;
10153 if (!ends_excmd(*skipwhite(p)))
10154 {
10155 vim_free(name);
10156 EMSG(_(e_trailing));
10157 return;
10158 }
10159 eap->nextcmd = check_nextcmd(p);
10160 if (eap->nextcmd != NULL)
10161 *p = NUL;
10162
10163 if (!eap->skip)
10164 fp = find_func(name);
10165 vim_free(name);
10166
10167 if (!eap->skip)
10168 {
10169 if (fp == NULL)
10170 {
10171 EMSG2(_("E130: Undefined function: %s"), eap->arg);
10172 return;
10173 }
10174 if (fp->calls)
10175 {
10176 EMSG2(_("E131: Cannot delete function %s: It is in use"), eap->arg);
10177 return;
10178 }
10179
10180 /* clear this function */
10181 vim_free(fp->name);
10182 ga_clear_strings(&(fp->args));
10183 ga_clear_strings(&(fp->lines));
10184
10185 /* remove the function from the function list */
10186 if (firstfunc == fp)
10187 firstfunc = fp->next;
10188 else
10189 {
10190 for (pfp = firstfunc; pfp != NULL; pfp = pfp->next)
10191 if (pfp->next == fp)
10192 {
10193 pfp->next = fp->next;
10194 break;
10195 }
10196 }
10197 vim_free(fp);
10198 }
10199}
10200
10201/*
10202 * Call a user function.
10203 */
10204 static void
10205call_user_func(fp, argcount, argvars, retvar, firstline, lastline)
10206 ufunc_T *fp; /* pointer to function */
10207 int argcount; /* nr of args */
10208 VAR argvars; /* arguments */
10209 VAR retvar; /* return value */
10210 linenr_T firstline; /* first line of range */
10211 linenr_T lastline; /* last line of range */
10212{
10213 char_u *save_sourcing_name;
10214 linenr_T save_sourcing_lnum;
10215 scid_T save_current_SID;
10216 struct funccall fc;
10217 struct funccall *save_fcp = current_funccal;
10218 int save_did_emsg;
10219 static int depth = 0;
10220
10221 /* If depth of calling is getting too high, don't execute the function */
10222 if (depth >= p_mfd)
10223 {
10224 EMSG(_("E132: Function call depth is higher than 'maxfuncdepth'"));
10225 retvar->var_type = VAR_NUMBER;
10226 retvar->var_val.var_number = -1;
10227 return;
10228 }
10229 ++depth;
10230
10231 line_breakcheck(); /* check for CTRL-C hit */
10232
10233 /* set local variables */
10234 var_init(&fc.l_vars);
10235 fc.func = fp;
10236 fc.argcount = argcount;
10237 fc.argvars = argvars;
10238 fc.retvar = retvar;
10239 retvar->var_val.var_number = 0;
10240 fc.linenr = 0;
10241 fc.returned = FALSE;
10242 fc.level = ex_nesting_level;
10243 fc.a0_var.var_type = VAR_NUMBER;
10244 fc.a0_var.var_val.var_number = argcount - fp->args.ga_len;
10245 fc.a0_var.var_name = NULL;
10246 current_funccal = &fc;
10247 fc.firstline.var_type = VAR_NUMBER;
10248 fc.firstline.var_val.var_number = firstline;
10249 fc.firstline.var_name = NULL;
10250 fc.lastline.var_type = VAR_NUMBER;
10251 fc.lastline.var_val.var_number = lastline;
10252 fc.lastline.var_name = NULL;
10253 /* Check if this function has a breakpoint. */
10254 fc.breakpoint = dbg_find_breakpoint(FALSE, fp->name, (linenr_T)0);
10255 fc.dbg_tick = debug_tick;
10256
10257 /* Don't redraw while executing the function. */
10258 ++RedrawingDisabled;
10259 save_sourcing_name = sourcing_name;
10260 save_sourcing_lnum = sourcing_lnum;
10261 sourcing_lnum = 1;
10262 sourcing_name = alloc((unsigned)((save_sourcing_name == NULL ? 0
10263 : STRLEN(save_sourcing_name)) + STRLEN(fp->name) + 13));
10264 if (sourcing_name != NULL)
10265 {
10266 if (save_sourcing_name != NULL
10267 && STRNCMP(save_sourcing_name, "function ", 9) == 0)
10268 sprintf((char *)sourcing_name, "%s..", save_sourcing_name);
10269 else
10270 STRCPY(sourcing_name, "function ");
10271 cat_func_name(sourcing_name + STRLEN(sourcing_name), fp);
10272
10273 if (p_verbose >= 12)
10274 {
10275 ++no_wait_return;
10276 msg_scroll = TRUE; /* always scroll up, don't overwrite */
10277 msg_str((char_u *)_("calling %s"), sourcing_name);
10278 if (p_verbose >= 14)
10279 {
10280 int i;
10281 char_u buf[MSG_BUF_LEN];
10282
10283 msg_puts((char_u *)"(");
10284 for (i = 0; i < argcount; ++i)
10285 {
10286 if (i > 0)
10287 msg_puts((char_u *)", ");
10288 if (argvars[i].var_type == VAR_NUMBER)
10289 msg_outnum((long)argvars[i].var_val.var_number);
10290 else
10291 {
10292 trunc_string(get_var_string(&argvars[i]),
10293 buf, MSG_BUF_LEN);
10294 msg_puts((char_u *)"\"");
10295 msg_puts(buf);
10296 msg_puts((char_u *)"\"");
10297 }
10298 }
10299 msg_puts((char_u *)")");
10300 }
10301 msg_puts((char_u *)"\n"); /* don't overwrite this either */
10302 cmdline_row = msg_row;
10303 --no_wait_return;
10304 }
10305 }
10306 save_current_SID = current_SID;
10307 current_SID = fp->script_ID;
10308 save_did_emsg = did_emsg;
10309 did_emsg = FALSE;
10310
10311 /* call do_cmdline() to execute the lines */
10312 do_cmdline(NULL, get_func_line, (void *)&fc,
10313 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
10314
10315 --RedrawingDisabled;
10316
10317 /* when the function was aborted because of an error, return -1 */
10318 if ((did_emsg && (fp->flags & FC_ABORT)) || retvar->var_type == VAR_UNKNOWN)
10319 {
10320 clear_var(retvar);
10321 retvar->var_type = VAR_NUMBER;
10322 retvar->var_val.var_number = -1;
10323 }
10324
10325 /* when being verbose, mention the return value */
10326 if (p_verbose >= 12)
10327 {
10328 char_u *sn, *val;
10329
10330 ++no_wait_return;
10331 msg_scroll = TRUE; /* always scroll up, don't overwrite */
10332
10333 /* Make sure the output fits in IObuff. */
10334 sn = sourcing_name;
10335 if (STRLEN(sourcing_name) > IOSIZE / 2 - 50)
10336 sn = sourcing_name + STRLEN(sourcing_name) - (IOSIZE / 2 - 50);
10337
10338 if (aborting())
10339 smsg((char_u *)_("%s aborted"), sn);
10340 else if (fc.retvar->var_type == VAR_NUMBER)
10341 smsg((char_u *)_("%s returning #%ld"), sn,
10342 (long)fc.retvar->var_val.var_number);
10343 else if (fc.retvar->var_type == VAR_STRING)
10344 {
10345 val = get_var_string(fc.retvar);
10346 if (STRLEN(val) > IOSIZE / 2 - 50)
10347 val = val + STRLEN(val) - (IOSIZE / 2 - 50);
10348 smsg((char_u *)_("%s returning \"%s\""), sn, val);
10349 }
10350 msg_puts((char_u *)"\n"); /* don't overwrite this either */
10351 cmdline_row = msg_row;
10352 --no_wait_return;
10353 }
10354
10355 vim_free(sourcing_name);
10356 sourcing_name = save_sourcing_name;
10357 sourcing_lnum = save_sourcing_lnum;
10358 current_SID = save_current_SID;
10359
10360 if (p_verbose >= 12 && sourcing_name != NULL)
10361 {
10362 ++no_wait_return;
10363 msg_scroll = TRUE; /* always scroll up, don't overwrite */
10364 msg_str((char_u *)_("continuing in %s"), sourcing_name);
10365 msg_puts((char_u *)"\n"); /* don't overwrite this either */
10366 cmdline_row = msg_row;
10367 --no_wait_return;
10368 }
10369
10370 did_emsg |= save_did_emsg;
10371 current_funccal = save_fcp;
10372
10373 var_clear(&fc.l_vars); /* free all local variables */
10374 --depth;
10375}
10376
10377/*
10378 * ":return [expr]"
10379 */
10380 void
10381ex_return(eap)
10382 exarg_T *eap;
10383{
10384 char_u *arg = eap->arg;
10385 var retvar;
10386 int returning = FALSE;
10387
10388 if (current_funccal == NULL)
10389 {
10390 EMSG(_("E133: :return not inside a function"));
10391 return;
10392 }
10393
10394 if (eap->skip)
10395 ++emsg_skip;
10396
10397 eap->nextcmd = NULL;
10398 if ((*arg != NUL && *arg != '|' && *arg != '\n')
10399 && eval0(arg, &retvar, &eap->nextcmd, !eap->skip) != FAIL)
10400 {
10401 if (!eap->skip)
10402 returning = do_return(eap, FALSE, TRUE, &retvar);
10403 else
10404 clear_var(&retvar);
10405 }
10406 /* It's safer to return also on error. */
10407 else if (!eap->skip)
10408 {
10409 /*
10410 * Return unless the expression evaluation has been cancelled due to an
10411 * aborting error, an interrupt, or an exception.
10412 */
10413 if (!aborting())
10414 returning = do_return(eap, FALSE, TRUE, NULL);
10415 }
10416
10417 /* When skipping or the return gets pending, advance to the next command
10418 * in this line (!returning). Otherwise, ignore the rest of the line.
10419 * Following lines will be ignored by get_func_line(). */
10420 if (returning)
10421 eap->nextcmd = NULL;
10422 else if (eap->nextcmd == NULL) /* no argument */
10423 eap->nextcmd = check_nextcmd(arg);
10424
10425 if (eap->skip)
10426 --emsg_skip;
10427}
10428
10429/*
10430 * Return from a function. Possibly makes the return pending. Also called
10431 * for a pending return at the ":endtry" or after returning from an extra
10432 * do_cmdline(). "reanimate" is used in the latter case. "is_cmd" is set
10433 * when called due to a ":return" command. "value" may point to a variable
10434 * with the return value. Returns TRUE when the return can be carried out,
10435 * FALSE when the return gets pending.
10436 */
10437 int
10438do_return(eap, reanimate, is_cmd, value)
10439 exarg_T *eap;
10440 int reanimate;
10441 int is_cmd;
10442 void *value;
10443{
10444 int idx;
10445 struct condstack *cstack = eap->cstack;
10446
10447 if (reanimate)
10448 /* Undo the return. */
10449 current_funccal->returned = FALSE;
10450
10451 /*
10452 * Cleanup (and inactivate) conditionals, but stop when a try conditional
10453 * not in its finally clause (which then is to be executed next) is found.
10454 * In this case, make the ":return" pending for execution at the ":endtry".
10455 * Otherwise, return normally.
10456 */
10457 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
10458 if (idx >= 0)
10459 {
10460 cstack->cs_pending[idx] = CSTP_RETURN;
10461
10462 if (!is_cmd && !reanimate)
10463 /* A pending return again gets pending. "value" points to an
10464 * allocated variable with the value of the original ":return"'s
10465 * argument if present or is NULL else. */
10466 cstack->cs_retvar[idx] = value;
10467 else
10468 {
10469 /* When undoing a return in order to make it pending, get the stored
10470 * return value. */
10471 if (reanimate)
10472 value = current_funccal->retvar;
10473
10474 if (value != NULL)
10475 {
10476 /* Store the value of the pending return. */
10477 if ((cstack->cs_retvar[idx] = alloc_var()) != NULL)
10478 *(VAR)cstack->cs_retvar[idx] = *(VAR)value;
10479 else
10480 EMSG(_(e_outofmem));
10481 }
10482 else
10483 cstack->cs_retvar[idx] = NULL;
10484
10485 if (reanimate)
10486 {
10487 /* The pending return value could be overwritten by a ":return"
10488 * without argument in a finally clause; reset the default
10489 * return value. */
10490 current_funccal->retvar->var_type = VAR_NUMBER;
10491 current_funccal->retvar->var_val.var_number = 0;
10492 }
10493 }
10494 report_make_pending(CSTP_RETURN, value);
10495 }
10496 else
10497 {
10498 current_funccal->returned = TRUE;
10499
10500 /* If the return is carried out now, store the return value. For
10501 * a return immediately after reanimation, the value is already
10502 * there. */
10503 if (!reanimate && value != NULL)
10504 {
10505 clear_var(current_funccal->retvar);
10506 *current_funccal->retvar = *(VAR)value;
10507 if (!is_cmd)
10508 vim_free(value);
10509 }
10510 }
10511
10512 return idx < 0;
10513}
10514
10515/*
10516 * Free the variable with a pending return value.
10517 */
10518 void
10519discard_pending_return(retvar)
10520 void *retvar;
10521{
10522 /* The variable was copied from one with an undefined var_name. So we can't
10523 * use free_var() to clear and free it. */
10524 clear_var((VAR)retvar);
10525 vim_free(retvar);
10526}
10527
10528/*
10529 * Generate a return command for producing the value of "retvar". The result
10530 * is an allocated string. Used by report_pending() for verbose messages.
10531 */
10532 char_u *
10533get_return_cmd(retvar)
10534 void *retvar;
10535{
10536 char_u *s = IObuff;
10537
10538 if (retvar == NULL || ((VAR)retvar)->var_type == VAR_UNKNOWN)
10539 s = (char_u *)":return";
10540 else if (((VAR)retvar)->var_type == VAR_STRING)
10541 sprintf((char *)IObuff, ":return \"%s\"",
10542 ((VAR)retvar)->var_val.var_string);
10543 else
10544 sprintf((char *)IObuff, ":return %ld",
10545 (long)(((VAR)retvar)->var_val.var_number));
10546 return vim_strsave(s);
10547}
10548
10549/*
10550 * Get next function line.
10551 * Called by do_cmdline() to get the next line.
10552 * Returns allocated string, or NULL for end of function.
10553 */
10554/* ARGSUSED */
10555 char_u *
10556get_func_line(c, cookie, indent)
10557 int c; /* not used */
10558 void *cookie;
10559 int indent; /* not used */
10560{
10561 struct funccall *fcp = (struct funccall *)cookie;
10562 char_u *retval;
10563 garray_T *gap; /* growarray with function lines */
10564
10565 /* If breakpoints have been added/deleted need to check for it. */
10566 if (fcp->dbg_tick != debug_tick)
10567 {
10568 fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->name,
10569 sourcing_lnum);
10570 fcp->dbg_tick = debug_tick;
10571 }
10572
10573 gap = &fcp->func->lines;
10574 if ((fcp->func->flags & FC_ABORT) && did_emsg && !aborted_in_try())
10575 retval = NULL;
10576 else if (fcp->returned || fcp->linenr >= gap->ga_len)
10577 retval = NULL;
10578 else
10579 {
10580 retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
10581 sourcing_lnum = fcp->linenr;
10582 }
10583
10584 /* Did we encounter a breakpoint? */
10585 if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum)
10586 {
10587 dbg_breakpoint(fcp->func->name, sourcing_lnum);
10588 /* Find next breakpoint. */
10589 fcp->breakpoint = dbg_find_breakpoint(FALSE, fcp->func->name,
10590 sourcing_lnum);
10591 fcp->dbg_tick = debug_tick;
10592 }
10593
10594 return retval;
10595}
10596
10597/*
10598 * Return TRUE if the currently active function should be ended, because a
10599 * return was encountered or an error occured. Used inside a ":while".
10600 */
10601 int
10602func_has_ended(cookie)
10603 void *cookie;
10604{
10605 struct funccall *fcp = (struct funccall *)cookie;
10606
10607 /* Ignore the "abort" flag if the abortion behavior has been changed due to
10608 * an error inside a try conditional. */
10609 return (((fcp->func->flags & FC_ABORT) && did_emsg && !aborted_in_try())
10610 || fcp->returned);
10611}
10612
10613/*
10614 * return TRUE if cookie indicates a function which "abort"s on errors.
10615 */
10616 int
10617func_has_abort(cookie)
10618 void *cookie;
10619{
10620 return ((struct funccall *)cookie)->func->flags & FC_ABORT;
10621}
10622
10623#if defined(FEAT_VIMINFO) || defined(FEAT_SESSION)
10624typedef enum
10625{
10626 VAR_FLAVOUR_DEFAULT,
10627 VAR_FLAVOUR_SESSION,
10628 VAR_FLAVOUR_VIMINFO
10629} var_flavour_T;
10630
10631static var_flavour_T var_flavour __ARGS((char_u *varname));
10632
10633 static var_flavour_T
10634var_flavour(varname)
10635 char_u *varname;
10636{
10637 char_u *p = varname;
10638
10639 if (ASCII_ISUPPER(*p))
10640 {
10641 while (*(++p))
10642 if (ASCII_ISLOWER(*p))
10643 return VAR_FLAVOUR_SESSION;
10644 return VAR_FLAVOUR_VIMINFO;
10645 }
10646 else
10647 return VAR_FLAVOUR_DEFAULT;
10648}
10649#endif
10650
10651#if defined(FEAT_VIMINFO) || defined(PROTO)
10652/*
10653 * Restore global vars that start with a capital from the viminfo file
10654 */
10655 int
10656read_viminfo_varlist(virp, writing)
10657 vir_T *virp;
10658 int writing;
10659{
10660 char_u *tab;
10661 int is_string = FALSE;
10662 VAR varp = NULL;
10663 char_u *val;
10664
10665 if (!writing && (find_viminfo_parameter('!') != NULL))
10666 {
10667 tab = vim_strchr(virp->vir_line + 1, '\t');
10668 if (tab != NULL)
10669 {
10670 *tab++ = '\0'; /* isolate the variable name */
10671 if (*tab == 'S') /* string var */
10672 is_string = TRUE;
10673
10674 tab = vim_strchr(tab, '\t');
10675 if (tab != NULL)
10676 {
10677 /* create a nameless variable to hold the value */
10678 if (is_string)
10679 {
10680 val = viminfo_readstring(virp,
10681 (int)(tab - virp->vir_line + 1), TRUE);
10682 if (val != NULL)
10683 varp = alloc_string_var(val);
10684 }
10685 else
10686 {
10687 varp = alloc_var();
10688 if (varp != NULL)
10689 {
10690 varp->var_type = VAR_NUMBER;
10691 varp->var_val.var_number = atol((char *)tab + 1);
10692 }
10693 }
10694 /* assign the value to the variable */
10695 if (varp != NULL)
10696 {
10697 set_var(virp->vir_line + 1, varp);
10698 free_var(varp);
10699 }
10700 }
10701 }
10702 }
10703
10704 return viminfo_readline(virp);
10705}
10706
10707/*
10708 * Write global vars that start with a capital to the viminfo file
10709 */
10710 void
10711write_viminfo_varlist(fp)
10712 FILE *fp;
10713{
10714 garray_T *gap = &variables; /* global variable */
10715 VAR this_var;
10716 int i;
10717
10718 if (find_viminfo_parameter('!') == NULL)
10719 return;
10720
10721 fprintf(fp, _("\n# global variables:\n"));
10722 for (i = gap->ga_len; --i >= 0; )
10723 {
10724 this_var = &VAR_GAP_ENTRY(i, gap);
10725 if (this_var->var_name != NULL
10726 && var_flavour(this_var->var_name) == VAR_FLAVOUR_VIMINFO)
10727 {
10728 fprintf(fp, "!%s\t%s\t", this_var->var_name,
10729 (this_var->var_type == VAR_STRING) ? "STR" : "NUM");
10730 viminfo_writestring(fp, get_var_string(this_var));
10731 }
10732 }
10733}
10734#endif
10735
10736#if defined(FEAT_SESSION) || defined(PROTO)
10737 int
10738store_session_globals(fd)
10739 FILE *fd;
10740{
10741 garray_T *gap = &variables; /* global variable */
10742 VAR this_var;
10743 int i;
10744 char_u *p, *t;
10745
10746 for (i = gap->ga_len; --i >= 0; )
10747 {
10748 this_var = &VAR_GAP_ENTRY(i, gap);
10749 if (this_var->var_name != NULL)
10750 {
10751 if (var_flavour(this_var->var_name) == VAR_FLAVOUR_SESSION)
10752 {
10753 /* Escapse special characters with a backslash. Turn a LF and
10754 * CR into \n and \r. */
10755 p = vim_strsave_escaped(get_var_string(this_var),
10756 (char_u *)"\\\"\n\r");
10757 if (p == NULL) /* out of memory */
10758 continue;
10759 for (t = p; *t != NUL; ++t)
10760 if (*t == '\n')
10761 *t = 'n';
10762 else if (*t == '\r')
10763 *t = 'r';
10764 if ((fprintf(fd, "let %s = %c%s%c",
10765 this_var->var_name,
10766 (this_var->var_type == VAR_STRING) ? '"' : ' ',
10767 p,
10768 (this_var->var_type == VAR_STRING) ? '"' : ' ') < 0)
10769 || put_eol(fd) == FAIL)
10770 {
10771 vim_free(p);
10772 return FAIL;
10773 }
10774 vim_free(p);
10775 }
10776
10777 }
10778 }
10779 return OK;
10780}
10781#endif
10782
10783#endif /* FEAT_EVAL */
10784
10785#if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) || defined(PROTO)
10786
10787
10788#ifdef WIN3264
10789/*
10790 * Functions for ":8" filename modifier: get 8.3 version of a filename.
10791 */
10792static int get_short_pathname __ARGS((char_u **fnamep, char_u **bufp, int *fnamelen));
10793static int shortpath_for_invalid_fname __ARGS((char_u **fname, char_u **bufp, int *fnamelen));
10794static int shortpath_for_partial __ARGS((char_u **fnamep, char_u **bufp, int *fnamelen));
10795
10796/*
10797 * Get the short pathname of a file.
10798 * Returns 1 on success. *fnamelen is 0 for nonexistant path.
10799 */
10800 static int
10801get_short_pathname(fnamep, bufp, fnamelen)
10802 char_u **fnamep;
10803 char_u **bufp;
10804 int *fnamelen;
10805{
10806 int l,len;
10807 char_u *newbuf;
10808
10809 len = *fnamelen;
10810
10811 l = GetShortPathName(*fnamep, *fnamep, len);
10812 if (l > len - 1)
10813 {
10814 /* If that doesn't work (not enough space), then save the string
10815 * and try again with a new buffer big enough
10816 */
10817 newbuf = vim_strnsave(*fnamep, l);
10818 if (newbuf == NULL)
10819 return 0;
10820
10821 vim_free(*bufp);
10822 *fnamep = *bufp = newbuf;
10823
10824 l = GetShortPathName(*fnamep,*fnamep,l+1);
10825
10826 /* Really should always succeed, as the buffer is big enough */
10827 }
10828
10829 *fnamelen = l;
10830 return 1;
10831}
10832
10833/*
10834 * Create a short path name. Returns the length of the buffer it needs.
10835 * Doesn't copy over the end of the buffer passed in.
10836 */
10837 static int
10838shortpath_for_invalid_fname(fname, bufp, fnamelen)
10839 char_u **fname;
10840 char_u **bufp;
10841 int *fnamelen;
10842{
10843 char_u *s, *p, *pbuf2, *pbuf3;
10844 char_u ch;
10845 int l,len,len2,plen,slen;
10846
10847 /* Make a copy */
10848 len2 = *fnamelen;
10849 pbuf2 = vim_strnsave(*fname, len2);
10850 pbuf3 = NULL;
10851
10852 s = pbuf2 + len2 - 1; /* Find the end */
10853 slen = 1;
10854 plen = len2;
10855
10856 l = 0;
10857 if (vim_ispathsep(*s))
10858 {
10859 --s;
10860 ++slen;
10861 --plen;
10862 }
10863
10864 do
10865 {
10866 /* Go back one path-seperator */
10867 while (s > pbuf2 && !vim_ispathsep(*s))
10868 {
10869 --s;
10870 ++slen;
10871 --plen;
10872 }
10873 if (s <= pbuf2)
10874 break;
10875
10876 /* Remeber the character that is about to be blatted */
10877 ch = *s;
10878 *s = 0; /* get_short_pathname requires a null-terminated string */
10879
10880 /* Try it in situ */
10881 p = pbuf2;
10882 if (!get_short_pathname(&p, &pbuf3, &plen))
10883 {
10884 vim_free(pbuf2);
10885 return -1;
10886 }
10887 *s = ch; /* Preserve the string */
10888 } while (plen == 0);
10889
10890 if (plen > 0)
10891 {
10892 /* Remeber the length of the new string. */
10893 *fnamelen = len = plen + slen;
10894 vim_free(*bufp);
10895 if (len > len2)
10896 {
10897 /* If there's not enough space in the currently allocated string,
10898 * then copy it to a buffer big enough.
10899 */
10900 *fname= *bufp = vim_strnsave(p, len);
10901 if (*fname == NULL)
10902 return -1;
10903 }
10904 else
10905 {
10906 /* Transfer pbuf2 to being the main buffer (it's big enough) */
10907 *fname = *bufp = pbuf2;
10908 if (p != pbuf2)
10909 strncpy(*fname, p, plen);
10910 pbuf2 = NULL;
10911 }
10912 /* Concat the next bit */
10913 strncpy(*fname + plen, s, slen);
10914 (*fname)[len] = '\0';
10915 }
10916 vim_free(pbuf3);
10917 vim_free(pbuf2);
10918 return 0;
10919}
10920
10921/*
10922 * Get a pathname for a partial path.
10923 */
10924 static int
10925shortpath_for_partial(fnamep, bufp, fnamelen)
10926 char_u **fnamep;
10927 char_u **bufp;
10928 int *fnamelen;
10929{
10930 int sepcount, len, tflen;
10931 char_u *p;
10932 char_u *pbuf, *tfname;
10933 int hasTilde;
10934
10935 /* Count up the path seperators from the RHS.. so we know which part
10936 * of the path to return.
10937 */
10938 sepcount = 0;
10939 for (p = *fnamep + *fnamelen - 1; p >= *fnamep; --p)
10940 if (vim_ispathsep(*p))
10941 ++sepcount;
10942
10943 /* Need full path first (use expand_env() to remove a "~/") */
10944 hasTilde = (**fnamep == '~');
10945 if (hasTilde)
10946 pbuf = tfname = expand_env_save(*fnamep);
10947 else
10948 pbuf = tfname = FullName_save(*fnamep, FALSE);
10949
10950 len = tflen = STRLEN(tfname);
10951
10952 if (!get_short_pathname(&tfname, &pbuf, &len))
10953 return -1;
10954
10955 if (len == 0)
10956 {
10957 /* Don't have a valid filename, so shorten the rest of the
10958 * path if we can. This CAN give us invalid 8.3 filenames, but
10959 * there's not a lot of point in guessing what it might be.
10960 */
10961 len = tflen;
10962 if (shortpath_for_invalid_fname(&tfname, &pbuf, &len) == -1)
10963 return -1;
10964 }
10965
10966 /* Count the paths backward to find the beginning of the desired string. */
10967 for (p = tfname + len - 1; p >= tfname; --p)
10968 if (vim_ispathsep(*p))
10969 {
10970 if (sepcount == 0 || (hasTilde && sepcount == 1))
10971 break;
10972 else
10973 sepcount --;
10974 }
10975 if (hasTilde)
10976 {
10977 --p;
10978 if (p >= tfname)
10979 *p = '~';
10980 else
10981 return -1;
10982 }
10983 else
10984 ++p;
10985
10986 /* Copy in the string - p indexes into tfname - allocated at pbuf */
10987 vim_free(*bufp);
10988 *fnamelen = (int)STRLEN(p);
10989 *bufp = pbuf;
10990 *fnamep = p;
10991
10992 return 0;
10993}
10994#endif /* WIN3264 */
10995
10996/*
10997 * Adjust a filename, according to a string of modifiers.
10998 * *fnamep must be NUL terminated when called. When returning, the length is
10999 * determined by *fnamelen.
11000 * Returns valid flags.
11001 * When there is an error, *fnamep is set to NULL.
11002 */
11003 int
11004modify_fname(src, usedlen, fnamep, bufp, fnamelen)
11005 char_u *src; /* string with modifiers */
11006 int *usedlen; /* characters after src that are used */
11007 char_u **fnamep; /* file name so far */
11008 char_u **bufp; /* buffer for allocated file name or NULL */
11009 int *fnamelen; /* length of fnamep */
11010{
11011 int valid = 0;
11012 char_u *tail;
11013 char_u *s, *p, *pbuf;
11014 char_u dirname[MAXPATHL];
11015 int c;
11016 int has_fullname = 0;
11017#ifdef WIN3264
11018 int has_shortname = 0;
11019#endif
11020
11021repeat:
11022 /* ":p" - full path/file_name */
11023 if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p')
11024 {
11025 has_fullname = 1;
11026
11027 valid |= VALID_PATH;
11028 *usedlen += 2;
11029
11030 /* Expand "~/path" for all systems and "~user/path" for Unix and VMS */
11031 if ((*fnamep)[0] == '~'
11032#if !defined(UNIX) && !(defined(VMS) && defined(USER_HOME))
11033 && ((*fnamep)[1] == '/'
11034# ifdef BACKSLASH_IN_FILENAME
11035 || (*fnamep)[1] == '\\'
11036# endif
11037 || (*fnamep)[1] == NUL)
11038
11039#endif
11040 )
11041 {
11042 *fnamep = expand_env_save(*fnamep);
11043 vim_free(*bufp); /* free any allocated file name */
11044 *bufp = *fnamep;
11045 if (*fnamep == NULL)
11046 return -1;
11047 }
11048
11049 /* When "/." or "/.." is used: force expansion to get rid of it. */
11050 for (p = *fnamep; *p != NUL; ++p)
11051 {
11052 if (vim_ispathsep(*p)
11053 && p[1] == '.'
11054 && (p[2] == NUL
11055 || vim_ispathsep(p[2])
11056 || (p[2] == '.'
11057 && (p[3] == NUL || vim_ispathsep(p[3])))))
11058 break;
11059 }
11060
11061 /* FullName_save() is slow, don't use it when not needed. */
11062 if (*p != NUL || !vim_isAbsName(*fnamep))
11063 {
11064 *fnamep = FullName_save(*fnamep, *p != NUL);
11065 vim_free(*bufp); /* free any allocated file name */
11066 *bufp = *fnamep;
11067 if (*fnamep == NULL)
11068 return -1;
11069 }
11070
11071 /* Append a path separator to a directory. */
11072 if (mch_isdir(*fnamep))
11073 {
11074 /* Make room for one or two extra characters. */
11075 *fnamep = vim_strnsave(*fnamep, (int)STRLEN(*fnamep) + 2);
11076 vim_free(*bufp); /* free any allocated file name */
11077 *bufp = *fnamep;
11078 if (*fnamep == NULL)
11079 return -1;
11080 add_pathsep(*fnamep);
11081 }
11082 }
11083
11084 /* ":." - path relative to the current directory */
11085 /* ":~" - path relative to the home directory */
11086 /* ":8" - shortname path - postponed till after */
11087 while (src[*usedlen] == ':'
11088 && ((c = src[*usedlen + 1]) == '.' || c == '~' || c == '8'))
11089 {
11090 *usedlen += 2;
11091 if (c == '8')
11092 {
11093#ifdef WIN3264
11094 has_shortname = 1; /* Postpone this. */
11095#endif
11096 continue;
11097 }
11098 pbuf = NULL;
11099 /* Need full path first (use expand_env() to remove a "~/") */
11100 if (!has_fullname)
11101 {
11102 if (c == '.' && **fnamep == '~')
11103 p = pbuf = expand_env_save(*fnamep);
11104 else
11105 p = pbuf = FullName_save(*fnamep, FALSE);
11106 }
11107 else
11108 p = *fnamep;
11109
11110 has_fullname = 0;
11111
11112 if (p != NULL)
11113 {
11114 if (c == '.')
11115 {
11116 mch_dirname(dirname, MAXPATHL);
11117 s = shorten_fname(p, dirname);
11118 if (s != NULL)
11119 {
11120 *fnamep = s;
11121 if (pbuf != NULL)
11122 {
11123 vim_free(*bufp); /* free any allocated file name */
11124 *bufp = pbuf;
11125 pbuf = NULL;
11126 }
11127 }
11128 }
11129 else
11130 {
11131 home_replace(NULL, p, dirname, MAXPATHL, TRUE);
11132 /* Only replace it when it starts with '~' */
11133 if (*dirname == '~')
11134 {
11135 s = vim_strsave(dirname);
11136 if (s != NULL)
11137 {
11138 *fnamep = s;
11139 vim_free(*bufp);
11140 *bufp = s;
11141 }
11142 }
11143 }
11144 vim_free(pbuf);
11145 }
11146 }
11147
11148 tail = gettail(*fnamep);
11149 *fnamelen = (int)STRLEN(*fnamep);
11150
11151 /* ":h" - head, remove "/file_name", can be repeated */
11152 /* Don't remove the first "/" or "c:\" */
11153 while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h')
11154 {
11155 valid |= VALID_HEAD;
11156 *usedlen += 2;
11157 s = get_past_head(*fnamep);
11158 while (tail > s && vim_ispathsep(tail[-1]))
11159 --tail;
11160 *fnamelen = (int)(tail - *fnamep);
11161#ifdef VMS
11162 if (*fnamelen > 0)
11163 *fnamelen += 1; /* the path separator is part of the path */
11164#endif
11165 while (tail > s && !vim_ispathsep(tail[-1]))
11166 --tail;
11167 }
11168
11169 /* ":8" - shortname */
11170 if (src[*usedlen] == ':' && src[*usedlen + 1] == '8')
11171 {
11172 *usedlen += 2;
11173#ifdef WIN3264
11174 has_shortname = 1;
11175#endif
11176 }
11177
11178#ifdef WIN3264
11179 /* Check shortname after we have done 'heads' and before we do 'tails'
11180 */
11181 if (has_shortname)
11182 {
11183 pbuf = NULL;
11184 /* Copy the string if it is shortened by :h */
11185 if (*fnamelen < (int)STRLEN(*fnamep))
11186 {
11187 p = vim_strnsave(*fnamep, *fnamelen);
11188 if (p == 0)
11189 return -1;
11190 vim_free(*bufp);
11191 *bufp = *fnamep = p;
11192 }
11193
11194 /* Split into two implementations - makes it easier. First is where
11195 * there isn't a full name already, second is where there is.
11196 */
11197 if (!has_fullname && !vim_isAbsName(*fnamep))
11198 {
11199 if (shortpath_for_partial(fnamep, bufp, fnamelen) == -1)
11200 return -1;
11201 }
11202 else
11203 {
11204 int l;
11205
11206 /* Simple case, already have the full-name
11207 * Nearly always shorter, so try first time. */
11208 l = *fnamelen;
11209 if (!get_short_pathname(fnamep, bufp, &l))
11210 return -1;
11211
11212 if (l == 0)
11213 {
11214 /* Couldn't find the filename.. search the paths.
11215 */
11216 l = *fnamelen;
11217 if (shortpath_for_invalid_fname(fnamep, bufp, &l ) == -1)
11218 return -1;
11219 }
11220 *fnamelen = l;
11221 }
11222 }
11223#endif /* WIN3264 */
11224
11225 /* ":t" - tail, just the basename */
11226 if (src[*usedlen] == ':' && src[*usedlen + 1] == 't')
11227 {
11228 *usedlen += 2;
11229 *fnamelen -= (int)(tail - *fnamep);
11230 *fnamep = tail;
11231 }
11232
11233 /* ":e" - extension, can be repeated */
11234 /* ":r" - root, without extension, can be repeated */
11235 while (src[*usedlen] == ':'
11236 && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r'))
11237 {
11238 /* find a '.' in the tail:
11239 * - for second :e: before the current fname
11240 * - otherwise: The last '.'
11241 */
11242 if (src[*usedlen + 1] == 'e' && *fnamep > tail)
11243 s = *fnamep - 2;
11244 else
11245 s = *fnamep + *fnamelen - 1;
11246 for ( ; s > tail; --s)
11247 if (s[0] == '.')
11248 break;
11249 if (src[*usedlen + 1] == 'e') /* :e */
11250 {
11251 if (s > tail)
11252 {
11253 *fnamelen += (int)(*fnamep - (s + 1));
11254 *fnamep = s + 1;
11255#ifdef VMS
11256 /* cut version from the extension */
11257 s = *fnamep + *fnamelen - 1;
11258 for ( ; s > *fnamep; --s)
11259 if (s[0] == ';')
11260 break;
11261 if (s > *fnamep)
11262 *fnamelen = s - *fnamep;
11263#endif
11264 }
11265 else if (*fnamep <= tail)
11266 *fnamelen = 0;
11267 }
11268 else /* :r */
11269 {
11270 if (s > tail) /* remove one extension */
11271 *fnamelen = (int)(s - *fnamep);
11272 }
11273 *usedlen += 2;
11274 }
11275
11276 /* ":s?pat?foo?" - substitute */
11277 /* ":gs?pat?foo?" - global substitute */
11278 if (src[*usedlen] == ':'
11279 && (src[*usedlen + 1] == 's'
11280 || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's')))
11281 {
11282 char_u *str;
11283 char_u *pat;
11284 char_u *sub;
11285 int sep;
11286 char_u *flags;
11287 int didit = FALSE;
11288
11289 flags = (char_u *)"";
11290 s = src + *usedlen + 2;
11291 if (src[*usedlen + 1] == 'g')
11292 {
11293 flags = (char_u *)"g";
11294 ++s;
11295 }
11296
11297 sep = *s++;
11298 if (sep)
11299 {
11300 /* find end of pattern */
11301 p = vim_strchr(s, sep);
11302 if (p != NULL)
11303 {
11304 pat = vim_strnsave(s, (int)(p - s));
11305 if (pat != NULL)
11306 {
11307 s = p + 1;
11308 /* find end of substitution */
11309 p = vim_strchr(s, sep);
11310 if (p != NULL)
11311 {
11312 sub = vim_strnsave(s, (int)(p - s));
11313 str = vim_strnsave(*fnamep, *fnamelen);
11314 if (sub != NULL && str != NULL)
11315 {
11316 *usedlen = (int)(p + 1 - src);
11317 s = do_string_sub(str, pat, sub, flags);
11318 if (s != NULL)
11319 {
11320 *fnamep = s;
11321 *fnamelen = (int)STRLEN(s);
11322 vim_free(*bufp);
11323 *bufp = s;
11324 didit = TRUE;
11325 }
11326 }
11327 vim_free(sub);
11328 vim_free(str);
11329 }
11330 vim_free(pat);
11331 }
11332 }
11333 /* after using ":s", repeat all the modifiers */
11334 if (didit)
11335 goto repeat;
11336 }
11337 }
11338
11339 return valid;
11340}
11341
11342/*
11343 * Perform a substitution on "str" with pattern "pat" and substitute "sub".
11344 * "flags" can be "g" to do a global substitute.
11345 * Returns an allocated string, NULL for error.
11346 */
11347 char_u *
11348do_string_sub(str, pat, sub, flags)
11349 char_u *str;
11350 char_u *pat;
11351 char_u *sub;
11352 char_u *flags;
11353{
11354 int sublen;
11355 regmatch_T regmatch;
11356 int i;
11357 int do_all;
11358 char_u *tail;
11359 garray_T ga;
11360 char_u *ret;
11361 char_u *save_cpo;
11362
11363 /* Make 'cpoptions' empty, so that the 'l' flag doesn't work here */
11364 save_cpo = p_cpo;
11365 p_cpo = (char_u *)"";
11366
11367 ga_init2(&ga, 1, 200);
11368
11369 do_all = (flags[0] == 'g');
11370
11371 regmatch.rm_ic = p_ic;
11372 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
11373 if (regmatch.regprog != NULL)
11374 {
11375 tail = str;
11376 while (vim_regexec_nl(&regmatch, str, (colnr_T)(tail - str)))
11377 {
11378 /*
11379 * Get some space for a temporary buffer to do the substitution
11380 * into. It will contain:
11381 * - The text up to where the match is.
11382 * - The substituted text.
11383 * - The text after the match.
11384 */
11385 sublen = vim_regsub(&regmatch, sub, tail, FALSE, TRUE, FALSE);
11386 if (ga_grow(&ga, (int)(STRLEN(tail) + sublen -
11387 (regmatch.endp[0] - regmatch.startp[0]))) == FAIL)
11388 {
11389 ga_clear(&ga);
11390 break;
11391 }
11392
11393 /* copy the text up to where the match is */
11394 i = (int)(regmatch.startp[0] - tail);
11395 mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
11396 /* add the substituted text */
11397 (void)vim_regsub(&regmatch, sub, (char_u *)ga.ga_data
11398 + ga.ga_len + i, TRUE, TRUE, FALSE);
11399 ga.ga_len += i + sublen - 1;
11400 ga.ga_room -= i + sublen - 1;
11401 /* avoid getting stuck on a match with an empty string */
11402 if (tail == regmatch.endp[0])
11403 {
11404 if (*tail == NUL)
11405 break;
11406 *((char_u *)ga.ga_data + ga.ga_len) = *tail++;
11407 ++ga.ga_len;
11408 --ga.ga_room;
11409 }
11410 else
11411 {
11412 tail = regmatch.endp[0];
11413 if (*tail == NUL)
11414 break;
11415 }
11416 if (!do_all)
11417 break;
11418 }
11419
11420 if (ga.ga_data != NULL)
11421 STRCPY((char *)ga.ga_data + ga.ga_len, tail);
11422
11423 vim_free(regmatch.regprog);
11424 }
11425
11426 ret = vim_strsave(ga.ga_data == NULL ? str : (char_u *)ga.ga_data);
11427 ga_clear(&ga);
11428 p_cpo = save_cpo;
11429
11430 return ret;
11431}
11432
11433#endif /* defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) */