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