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