blob: 4614deab80b60f0ff8f7d6ec0340244adf64167c [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 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
17static void cmd_source __ARGS((char_u *fname, exarg_T *eap));
18
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
71
72/*
73 * do_debug(): Debug mode.
74 * Repeatedly get Ex commands, until told to continue normal execution.
75 */
76 void
77do_debug(cmd)
78 char_u *cmd;
79{
80 int save_msg_scroll = msg_scroll;
81 int save_State = State;
82 int save_did_emsg = did_emsg;
83 int save_cmd_silent = cmd_silent;
84 int save_msg_silent = msg_silent;
85 int save_emsg_silent = emsg_silent;
86 int save_redir_off = redir_off;
87 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000088 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000089 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000090# ifdef FEAT_EX_EXTRA
91 int save_ex_normal_busy;
92# endif
93 int n;
94 char_u *cmdline = NULL;
95 char_u *p;
96 char *tail = NULL;
97 static int last_cmd = 0;
98#define CMD_CONT 1
99#define CMD_NEXT 2
100#define CMD_STEP 3
101#define CMD_FINISH 4
102#define CMD_QUIT 5
103#define CMD_INTERRUPT 6
104
105#ifdef ALWAYS_USE_GUI
106 /* Can't do this when there is no terminal for input/output. */
107 if (!gui.in_use)
108 {
109 /* Break as soon as possible. */
110 debug_break_level = 9999;
111 return;
112 }
113#endif
114
115 /* Make sure we are in raw mode and start termcap mode. Might have side
116 * effects... */
117 settmode(TMODE_RAW);
118 starttermcap();
119
120 ++RedrawingDisabled; /* don't redisplay the window */
121 ++no_wait_return; /* don't wait for return */
122 did_emsg = FALSE; /* don't use error from debugged stuff */
123 cmd_silent = FALSE; /* display commands */
124 msg_silent = FALSE; /* display messages */
125 emsg_silent = FALSE; /* display error messages */
126 redir_off = TRUE; /* don't redirect debug commands */
127
128 State = NORMAL;
129#ifdef FEAT_SNIFF
130 want_sniff_request = 0; /* No K_SNIFF wanted */
131#endif
132
133 if (!debug_did_msg)
134 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
135 if (sourcing_name != NULL)
136 msg(sourcing_name);
137 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000138 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141
142 /*
143 * Repeat getting a command and executing it.
144 */
145 for (;;)
146 {
147 msg_scroll = TRUE;
148 need_wait_return = FALSE;
149#ifdef FEAT_SNIFF
150 ProcessSniffRequests();
151#endif
152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157# ifdef FEAT_EX_EXTRA
158 save_ex_normal_busy = ex_normal_busy;
159 ex_normal_busy = 0;
160# endif
161 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000164 typeahead_saved = TRUE;
165 save_ignore_script = ignore_script;
166 ignore_script = TRUE;
167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000169 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000171 if (typeahead_saved)
172 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 ignore_script = save_ignore_script;
175 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176# ifdef FEAT_EX_EXTRA
177 ex_normal_busy = save_ex_normal_busy;
178# endif
179
180 cmdline_row = msg_row;
181 if (cmdline != NULL)
182 {
183 /* If this is a debug command, set "last_cmd".
184 * If not, reset "last_cmd".
185 * For a blank line use previous command. */
186 p = skipwhite(cmdline);
187 if (*p != NUL)
188 {
189 switch (*p)
190 {
191 case 'c': last_cmd = CMD_CONT;
192 tail = "ont";
193 break;
194 case 'n': last_cmd = CMD_NEXT;
195 tail = "ext";
196 break;
197 case 's': last_cmd = CMD_STEP;
198 tail = "tep";
199 break;
200 case 'f': last_cmd = CMD_FINISH;
201 tail = "inish";
202 break;
203 case 'q': last_cmd = CMD_QUIT;
204 tail = "uit";
205 break;
206 case 'i': last_cmd = CMD_INTERRUPT;
207 tail = "nterrupt";
208 break;
209 default: last_cmd = 0;
210 }
211 if (last_cmd != 0)
212 {
213 /* Check that the tail matches. */
214 ++p;
215 while (*p != NUL && *p == *tail)
216 {
217 ++p;
218 ++tail;
219 }
220 if (ASCII_ISALPHA(*p))
221 last_cmd = 0;
222 }
223 }
224
225 if (last_cmd != 0)
226 {
227 /* Execute debug command: decided where to break next and
228 * return. */
229 switch (last_cmd)
230 {
231 case CMD_CONT:
232 debug_break_level = -1;
233 break;
234 case CMD_NEXT:
235 debug_break_level = ex_nesting_level;
236 break;
237 case CMD_STEP:
238 debug_break_level = 9999;
239 break;
240 case CMD_FINISH:
241 debug_break_level = ex_nesting_level - 1;
242 break;
243 case CMD_QUIT:
244 got_int = TRUE;
245 debug_break_level = -1;
246 break;
247 case CMD_INTERRUPT:
248 got_int = TRUE;
249 debug_break_level = 9999;
250 /* Do not repeat ">interrupt" cmd, continue stepping. */
251 last_cmd = CMD_STEP;
252 break;
253 }
254 break;
255 }
256
257 /* don't debug this command */
258 n = debug_break_level;
259 debug_break_level = -1;
260 (void)do_cmdline(cmdline, getexline, NULL,
261 DOCMD_VERBOSE|DOCMD_EXCRESET);
262 debug_break_level = n;
263
264 vim_free(cmdline);
265 }
266 lines_left = Rows - 1;
267 }
268 vim_free(cmdline);
269
270 --RedrawingDisabled;
271 --no_wait_return;
272 redraw_all_later(NOT_VALID);
273 need_wait_return = FALSE;
274 msg_scroll = save_msg_scroll;
275 lines_left = Rows - 1;
276 State = save_State;
277 did_emsg = save_did_emsg;
278 cmd_silent = save_cmd_silent;
279 msg_silent = save_msg_silent;
280 emsg_silent = save_emsg_silent;
281 redir_off = save_redir_off;
282
283 /* Only print the message again when typing a command before coming back
284 * here. */
285 debug_did_msg = TRUE;
286}
287
288/*
289 * ":debug".
290 */
291 void
292ex_debug(eap)
293 exarg_T *eap;
294{
295 int debug_break_level_save = debug_break_level;
296
297 debug_break_level = 9999;
298 do_cmdline_cmd(eap->arg);
299 debug_break_level = debug_break_level_save;
300}
301
302static char_u *debug_breakpoint_name = NULL;
303static linenr_T debug_breakpoint_lnum;
304
305/*
306 * When debugging or a breakpoint is set on a skipped command, no debug prompt
307 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
308 * debug_skipped_name is then set to the source name in the breakpoint case. If
309 * a skipped command decides itself that a debug prompt should be displayed, it
310 * can do so by calling dbg_check_skipped().
311 */
312static int debug_skipped;
313static char_u *debug_skipped_name;
314
315/*
316 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
317 * at or below the break level. But only when the line is actually
318 * executed. Return TRUE and set breakpoint_name for skipped commands that
319 * decide to execute something themselves.
320 * Called from do_one_cmd() before executing a command.
321 */
322 void
323dbg_check_breakpoint(eap)
324 exarg_T *eap;
325{
326 char_u *p;
327
328 debug_skipped = FALSE;
329 if (debug_breakpoint_name != NULL)
330 {
331 if (!eap->skip)
332 {
333 /* replace K_SNR with "<SNR>" */
334 if (debug_breakpoint_name[0] == K_SPECIAL
335 && debug_breakpoint_name[1] == KS_EXTRA
336 && debug_breakpoint_name[2] == (int)KE_SNR)
337 p = (char_u *)"<SNR>";
338 else
339 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000340 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
341 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 debug_breakpoint_name + (*p == NUL ? 0 : 3),
343 (long)debug_breakpoint_lnum);
344 debug_breakpoint_name = NULL;
345 do_debug(eap->cmd);
346 }
347 else
348 {
349 debug_skipped = TRUE;
350 debug_skipped_name = debug_breakpoint_name;
351 debug_breakpoint_name = NULL;
352 }
353 }
354 else if (ex_nesting_level <= debug_break_level)
355 {
356 if (!eap->skip)
357 do_debug(eap->cmd);
358 else
359 {
360 debug_skipped = TRUE;
361 debug_skipped_name = NULL;
362 }
363 }
364}
365
366/*
367 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
368 * set. Return TRUE when the debug mode is entered this time.
369 */
370 int
371dbg_check_skipped(eap)
372 exarg_T *eap;
373{
374 int prev_got_int;
375
376 if (debug_skipped)
377 {
378 /*
379 * Save the value of got_int and reset it. We don't want a previous
380 * interruption cause flushing the input buffer.
381 */
382 prev_got_int = got_int;
383 got_int = FALSE;
384 debug_breakpoint_name = debug_skipped_name;
385 /* eap->skip is TRUE */
386 eap->skip = FALSE;
387 (void)dbg_check_breakpoint(eap);
388 eap->skip = TRUE;
389 got_int |= prev_got_int;
390 return TRUE;
391 }
392 return FALSE;
393}
394
395/*
396 * The list of breakpoints: dbg_breakp.
397 * This is a grow-array of structs.
398 */
399struct debuggy
400{
401 int dbg_nr; /* breakpoint number */
402 int dbg_type; /* DBG_FUNC or DBG_FILE */
403 char_u *dbg_name; /* function or file name */
404 regprog_T *dbg_prog; /* regexp program */
405 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000406 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407};
408
409static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000410#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
411#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412static int last_breakp = 0; /* nr of last defined breakpoint */
413
Bram Moolenaar05159a02005-02-26 23:04:13 +0000414#ifdef FEAT_PROFILE
415/* Profiling uses file and func names similar to breakpoints. */
416static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
417#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418#define DBG_FUNC 1
419#define DBG_FILE 2
420
Bram Moolenaar05159a02005-02-26 23:04:13 +0000421static int dbg_parsearg __ARGS((char_u *arg, garray_T *gap));
422static linenr_T debuggy_find __ARGS((int file,char_u *fname, linenr_T after, garray_T *gap, int *fp));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423
424/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000425 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
426 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
427 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 * Returns FAIL for failure.
429 */
430 static int
Bram Moolenaar05159a02005-02-26 23:04:13 +0000431dbg_parsearg(arg, gap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 char_u *arg;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000433 garray_T *gap; /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434{
435 char_u *p = arg;
436 char_u *q;
437 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000438 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439
Bram Moolenaar05159a02005-02-26 23:04:13 +0000440 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000442 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
444 /* Find "func" or "file". */
445 if (STRNCMP(p, "func", 4) == 0)
446 bp->dbg_type = DBG_FUNC;
447 else if (STRNCMP(p, "file", 4) == 0)
448 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000449 else if (
450#ifdef FEAT_PROFILE
451 gap != &prof_ga &&
452#endif
453 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000454 {
455 if (curbuf->b_ffname == NULL)
456 {
457 EMSG(_(e_noname));
458 return FAIL;
459 }
460 bp->dbg_type = DBG_FILE;
461 here = TRUE;
462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 else
464 {
465 EMSG2(_(e_invarg2), p);
466 return FAIL;
467 }
468 p = skipwhite(p + 4);
469
470 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000471 if (here)
472 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000473 else if (
474#ifdef FEAT_PROFILE
475 gap != &prof_ga &&
476#endif
477 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478 {
479 bp->dbg_lnum = getdigits(&p);
480 p = skipwhite(p);
481 }
482 else
483 bp->dbg_lnum = 0;
484
485 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000486 if ((!here && *p == NUL)
487 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
489 {
490 EMSG2(_(e_invarg2), arg);
491 return FAIL;
492 }
493
494 if (bp->dbg_type == DBG_FUNC)
495 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000496 else if (here)
497 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 else
499 {
500 /* Expand the file name in the same way as do_source(). This means
501 * doing it twice, so that $DIR/file gets expanded when $DIR is
502 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 if (q == NULL)
505 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 vim_free(q);
508 if (p == NULL)
509 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000510 if (*p != '*')
511 {
512 bp->dbg_name = fix_fname(p);
513 vim_free(p);
514 }
515 else
516 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 }
518
519 if (bp->dbg_name == NULL)
520 return FAIL;
521 return OK;
522}
523
524/*
525 * ":breakadd".
526 */
527 void
528ex_breakadd(eap)
529 exarg_T *eap;
530{
531 struct debuggy *bp;
532 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaar05159a02005-02-26 23:04:13 +0000535 gap = &dbg_breakp;
536#ifdef FEAT_PROFILE
537 if (eap->cmdidx == CMD_profile)
538 gap = &prof_ga;
539#endif
540
541 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000543 bp = &DEBUGGY(gap, gap->ga_len);
544 bp->dbg_forceit = eap->forceit;
545
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
547 if (pat != NULL)
548 {
549 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
550 vim_free(pat);
551 }
552 if (pat == NULL || bp->dbg_prog == NULL)
553 vim_free(bp->dbg_name);
554 else
555 {
556 if (bp->dbg_lnum == 0) /* default line number is 1 */
557 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000558#ifdef FEAT_PROFILE
559 if (eap->cmdidx != CMD_profile)
560#endif
561 {
562 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
563 ++debug_tick;
564 }
565 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 }
567 }
568}
569
570/*
571 * ":debuggreedy".
572 */
573 void
574ex_debuggreedy(eap)
575 exarg_T *eap;
576{
577 if (eap->addr_count == 0 || eap->line2 != 0)
578 debug_greedy = TRUE;
579 else
580 debug_greedy = FALSE;
581}
582
583/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000584 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 */
586 void
587ex_breakdel(eap)
588 exarg_T *eap;
589{
590 struct debuggy *bp, *bpi;
591 int nr;
592 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000593 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 int i;
595 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000596 garray_T *gap;
597
598 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000599 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200600 {
601#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000602 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200603#else
604 ex_ni(eap);
605 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000606#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608
609 if (vim_isdigit(*eap->arg))
610 {
611 /* ":breakdel {nr}" */
612 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000613 for (i = 0; i < gap->ga_len; ++i)
614 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 {
616 todel = i;
617 break;
618 }
619 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000620 else if (*eap->arg == '*')
621 {
622 todel = 0;
623 del_all = TRUE;
624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000628 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000630 bp = &DEBUGGY(gap, gap->ga_len);
631 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000633 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 if (bp->dbg_type == bpi->dbg_type
635 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
636 && (bp->dbg_lnum == bpi->dbg_lnum
637 || (bp->dbg_lnum == 0
638 && (best_lnum == 0
639 || bpi->dbg_lnum < best_lnum))))
640 {
641 todel = i;
642 best_lnum = bpi->dbg_lnum;
643 }
644 }
645 vim_free(bp->dbg_name);
646 }
647
648 if (todel < 0)
649 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
650 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000651 {
652 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000653 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000654 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200655 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000656 --gap->ga_len;
657 if (todel < gap->ga_len)
658 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
659 (gap->ga_len - todel) * sizeof(struct debuggy));
660#ifdef FEAT_PROFILE
661 if (eap->cmdidx == CMD_breakdel)
662#endif
663 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000664 if (!del_all)
665 break;
666 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000667
668 /* If all breakpoints were removed clear the array. */
669 if (gap->ga_len == 0)
670 ga_clear(gap);
671 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672}
673
674/*
675 * ":breaklist".
676 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 void
678ex_breaklist(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +0000679 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680{
681 struct debuggy *bp;
682 int i;
683
684 if (dbg_breakp.ga_len == 0)
685 MSG(_("No breakpoints defined"));
686 else
687 for (i = 0; i < dbg_breakp.ga_len; ++i)
688 {
689 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200690 if (bp->dbg_type == DBG_FILE)
691 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 smsg((char_u *)_("%3d %s %s line %ld"),
693 bp->dbg_nr,
694 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200695 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 (long)bp->dbg_lnum);
697 }
698}
699
700/*
701 * Find a breakpoint for a function or sourced file.
702 * Returns line number at which to break; zero when no matching breakpoint.
703 */
704 linenr_T
705dbg_find_breakpoint(file, fname, after)
706 int file; /* TRUE for a file, FALSE for a function */
707 char_u *fname; /* file or function name */
708 linenr_T after; /* after this line number */
709{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000710 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
711}
712
713#if defined(FEAT_PROFILE) || defined(PROTO)
714/*
715 * Return TRUE if profiling is on for a function or sourced file.
716 */
717 int
718has_profiling(file, fname, fp)
719 int file; /* TRUE for a file, FALSE for a function */
720 char_u *fname; /* file or function name */
721 int *fp; /* return: forceit */
722{
723 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
724 != (linenr_T)0);
725}
726#endif
727
728/*
729 * Common code for dbg_find_breakpoint() and has_profiling().
730 */
731 static linenr_T
732debuggy_find(file, fname, after, gap, fp)
733 int file; /* TRUE for a file, FALSE for a function */
734 char_u *fname; /* file or function name */
735 linenr_T after; /* after this line number */
736 garray_T *gap; /* either &dbg_breakp or &prof_ga */
737 int *fp; /* if not NULL: return forceit */
738{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 struct debuggy *bp;
740 int i;
741 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 char_u *name = fname;
743 int prev_got_int;
744
Bram Moolenaar05159a02005-02-26 23:04:13 +0000745 /* Return quickly when there are no breakpoints. */
746 if (gap->ga_len == 0)
747 return (linenr_T)0;
748
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 /* Replace K_SNR in function name with "<SNR>". */
750 if (!file && fname[0] == K_SPECIAL)
751 {
752 name = alloc((unsigned)STRLEN(fname) + 3);
753 if (name == NULL)
754 name = fname;
755 else
756 {
757 STRCPY(name, "<SNR>");
758 STRCPY(name + 5, fname + 3);
759 }
760 }
761
Bram Moolenaar05159a02005-02-26 23:04:13 +0000762 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000764 /* Skip entries that are not useful or are for a line that is beyond
765 * an already found breakpoint. */
766 bp = &DEBUGGY(gap, i);
767 if (((bp->dbg_type == DBG_FILE) == file && (
768#ifdef FEAT_PROFILE
769 gap == &prof_ga ||
770#endif
771 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000774 * Save the value of got_int and reset it. We don't want a
775 * previous interruption cancel matching, only hitting CTRL-C
776 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 */
778 prev_got_int = got_int;
779 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100780 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000781 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000783 if (fp != NULL)
784 *fp = bp->dbg_forceit;
785 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 got_int |= prev_got_int;
787 }
788 }
789 if (name != fname)
790 vim_free(name);
791
792 return lnum;
793}
794
795/*
796 * Called when a breakpoint was encountered.
797 */
798 void
799dbg_breakpoint(name, lnum)
800 char_u *name;
801 linenr_T lnum;
802{
803 /* We need to check if this line is actually executed in do_one_cmd() */
804 debug_breakpoint_name = name;
805 debug_breakpoint_lnum = lnum;
806}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000807
808
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000809# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000810/*
811 * Store the current time in "tm".
812 */
813 void
814profile_start(tm)
815 proftime_T *tm;
816{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000817# ifdef WIN3264
818 QueryPerformanceCounter(tm);
819# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000820 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000821# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000822}
823
824/*
825 * Compute the elapsed time from "tm" till now and store in "tm".
826 */
827 void
828profile_end(tm)
829 proftime_T *tm;
830{
831 proftime_T now;
832
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000833# ifdef WIN3264
834 QueryPerformanceCounter(&now);
835 tm->QuadPart = now.QuadPart - tm->QuadPart;
836# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000837 gettimeofday(&now, NULL);
838 tm->tv_usec = now.tv_usec - tm->tv_usec;
839 tm->tv_sec = now.tv_sec - tm->tv_sec;
840 if (tm->tv_usec < 0)
841 {
842 tm->tv_usec += 1000000;
843 --tm->tv_sec;
844 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000845# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000846}
847
848/*
849 * Subtract the time "tm2" from "tm".
850 */
851 void
852profile_sub(tm, tm2)
853 proftime_T *tm, *tm2;
854{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000855# ifdef WIN3264
856 tm->QuadPart -= tm2->QuadPart;
857# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000858 tm->tv_usec -= tm2->tv_usec;
859 tm->tv_sec -= tm2->tv_sec;
860 if (tm->tv_usec < 0)
861 {
862 tm->tv_usec += 1000000;
863 --tm->tv_sec;
864 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000865# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000866}
867
868/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000869 * Return a string that represents the time in "tm".
870 * Uses a static buffer!
871 */
872 char *
873profile_msg(tm)
874 proftime_T *tm;
875{
876 static char buf[50];
877
878# ifdef WIN3264
879 LARGE_INTEGER fr;
880
881 QueryPerformanceFrequency(&fr);
882 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
883# else
884 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +0000885# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000886 return buf;
887}
888
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000889/*
Bram Moolenaar76929292008-01-06 19:07:36 +0000890 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000891 */
Bram Moolenaar76929292008-01-06 19:07:36 +0000892 void
893profile_setlimit(msec, tm)
894 long msec;
895 proftime_T *tm;
896{
897 if (msec <= 0) /* no limit */
898 profile_zero(tm);
899 else
900 {
901# ifdef WIN3264
902 LARGE_INTEGER fr;
903
904 QueryPerformanceCounter(tm);
905 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +0000906 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +0000907# else
908 long usec;
909
910 gettimeofday(tm, NULL);
911 usec = (long)tm->tv_usec + (long)msec * 1000;
912 tm->tv_usec = usec % 1000000L;
913 tm->tv_sec += usec / 1000000L;
914# endif
915 }
916}
917
918/*
919 * Return TRUE if the current time is past "tm".
920 */
921 int
922profile_passed_limit(tm)
923 proftime_T *tm;
924{
925 proftime_T now;
926
927# ifdef WIN3264
928 if (tm->QuadPart == 0) /* timer was not set */
929 return FALSE;
930 QueryPerformanceCounter(&now);
931 return (now.QuadPart > tm->QuadPart);
932# else
933 if (tm->tv_sec == 0) /* timer was not set */
934 return FALSE;
935 gettimeofday(&now, NULL);
936 return (now.tv_sec > tm->tv_sec
937 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
938# endif
939}
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000940
941/*
942 * Set the time in "tm" to zero.
943 */
944 void
945profile_zero(tm)
946 proftime_T *tm;
947{
948# ifdef WIN3264
949 tm->QuadPart = 0;
950# else
951 tm->tv_usec = 0;
952 tm->tv_sec = 0;
953# endif
954}
955
Bram Moolenaar76929292008-01-06 19:07:36 +0000956# endif /* FEAT_PROFILE || FEAT_RELTIME */
957
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200958#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
959# if defined(HAVE_MATH_H)
960# include <math.h>
961# endif
962
963/*
964 * Divide the time "tm" by "count" and store in "tm2".
965 */
966 void
967profile_divide(tm, count, tm2)
968 proftime_T *tm;
969 proftime_T *tm2;
970 int count;
971{
972 if (count == 0)
973 profile_zero(tm2);
974 else
975 {
976# ifdef WIN3264
977 tm2->QuadPart = tm->QuadPart / count;
978# else
979 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
980
981 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +0200982 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +0200983# endif
984 }
985}
986#endif
987
Bram Moolenaar76929292008-01-06 19:07:36 +0000988# if defined(FEAT_PROFILE) || defined(PROTO)
989/*
990 * Functions for profiling.
991 */
992static void script_do_profile __ARGS((scriptitem_T *si));
993static void script_dump_profile __ARGS((FILE *fd));
994static proftime_T prof_wait_time;
995
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000996/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000997 * Add the time "tm2" to "tm".
998 */
999 void
1000profile_add(tm, tm2)
1001 proftime_T *tm, *tm2;
1002{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001003# ifdef WIN3264
1004 tm->QuadPart += tm2->QuadPart;
1005# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001006 tm->tv_usec += tm2->tv_usec;
1007 tm->tv_sec += tm2->tv_sec;
1008 if (tm->tv_usec >= 1000000)
1009 {
1010 tm->tv_usec -= 1000000;
1011 ++tm->tv_sec;
1012 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001013# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001014}
1015
1016/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001017 * Add the "self" time from the total time and the children's time.
1018 */
1019 void
1020profile_self(self, total, children)
1021 proftime_T *self, *total, *children;
1022{
1023 /* Check that the result won't be negative. Can happen with recursive
1024 * calls. */
1025#ifdef WIN3264
1026 if (total->QuadPart <= children->QuadPart)
1027 return;
1028#else
1029 if (total->tv_sec < children->tv_sec
1030 || (total->tv_sec == children->tv_sec
1031 && total->tv_usec <= children->tv_usec))
1032 return;
1033#endif
1034 profile_add(self, total);
1035 profile_sub(self, children);
1036}
1037
1038/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001039 * Get the current waittime.
1040 */
1041 void
1042profile_get_wait(tm)
1043 proftime_T *tm;
1044{
1045 *tm = prof_wait_time;
1046}
1047
1048/*
1049 * Subtract the passed waittime since "tm" from "tma".
1050 */
1051 void
1052profile_sub_wait(tm, tma)
1053 proftime_T *tm, *tma;
1054{
1055 proftime_T tm3 = prof_wait_time;
1056
1057 profile_sub(&tm3, tm);
1058 profile_sub(tma, &tm3);
1059}
1060
1061/*
1062 * Return TRUE if "tm1" and "tm2" are equal.
1063 */
1064 int
1065profile_equal(tm1, tm2)
1066 proftime_T *tm1, *tm2;
1067{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001068# ifdef WIN3264
1069 return (tm1->QuadPart == tm2->QuadPart);
1070# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001071 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001072# endif
1073}
1074
1075/*
1076 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1077 */
1078 int
1079profile_cmp(tm1, tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001080 const proftime_T *tm1, *tm2;
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001081{
1082# ifdef WIN3264
1083 return (int)(tm2->QuadPart - tm1->QuadPart);
1084# else
1085 if (tm1->tv_sec == tm2->tv_sec)
1086 return tm2->tv_usec - tm1->tv_usec;
1087 return tm2->tv_sec - tm1->tv_sec;
1088# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001089}
1090
Bram Moolenaar05159a02005-02-26 23:04:13 +00001091static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001092static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001093
1094/*
1095 * ":profile cmd args"
1096 */
1097 void
1098ex_profile(eap)
1099 exarg_T *eap;
1100{
1101 char_u *e;
1102 int len;
1103
1104 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001105 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001106 e = skipwhite(e);
1107
1108 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1109 {
1110 vim_free(profile_fname);
1111 profile_fname = vim_strsave(e);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001112 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001113 profile_zero(&prof_wait_time);
1114 set_vim_var_nr(VV_PROFILING, 1L);
1115 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001116 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001117 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001118 else if (STRCMP(eap->arg, "pause") == 0)
1119 {
1120 if (do_profiling == PROF_YES)
1121 profile_start(&pause_time);
1122 do_profiling = PROF_PAUSED;
1123 }
1124 else if (STRCMP(eap->arg, "continue") == 0)
1125 {
1126 if (do_profiling == PROF_PAUSED)
1127 {
1128 profile_end(&pause_time);
1129 profile_add(&prof_wait_time, &pause_time);
1130 }
1131 do_profiling = PROF_YES;
1132 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001133 else
1134 {
1135 /* The rest is similar to ":breakadd". */
1136 ex_breakadd(eap);
1137 }
1138}
1139
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001140/* Command line expansion for :profile. */
1141static enum
1142{
1143 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001144 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001145} pexpand_what;
1146
1147static char *pexpand_cmds[] = {
1148 "start",
1149#define PROFCMD_START 0
1150 "pause",
1151#define PROFCMD_PAUSE 1
1152 "continue",
1153#define PROFCMD_CONTINUE 2
1154 "func",
1155#define PROFCMD_FUNC 3
1156 "file",
1157#define PROFCMD_FILE 4
1158 NULL
1159#define PROFCMD_LAST 5
1160};
1161
1162/*
1163 * Function given to ExpandGeneric() to obtain the profile command
1164 * specific expansion.
1165 */
1166 char_u *
1167get_profile_name(xp, idx)
1168 expand_T *xp UNUSED;
1169 int idx;
1170{
1171 switch (pexpand_what)
1172 {
1173 case PEXP_SUBCMD:
1174 return (char_u *)pexpand_cmds[idx];
1175 /* case PEXP_FUNC: TODO */
1176 default:
1177 return NULL;
1178 }
1179}
1180
1181/*
1182 * Handle command line completion for :profile command.
1183 */
1184 void
1185set_context_in_profile_cmd(xp, arg)
1186 expand_T *xp;
1187 char_u *arg;
1188{
1189 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001190
1191 /* Default: expand subcommands. */
1192 xp->xp_context = EXPAND_PROFILE;
1193 pexpand_what = PEXP_SUBCMD;
1194 xp->xp_pattern = arg;
1195
1196 end_subcmd = skiptowhite(arg);
1197 if (*end_subcmd == NUL)
1198 return;
1199
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001200 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001201 {
1202 xp->xp_context = EXPAND_FILES;
1203 xp->xp_pattern = skipwhite(end_subcmd);
1204 return;
1205 }
1206
1207 /* TODO: expand function names after "func" */
1208 xp->xp_context = EXPAND_NOTHING;
1209}
1210
Bram Moolenaar05159a02005-02-26 23:04:13 +00001211/*
1212 * Dump the profiling info.
1213 */
1214 void
1215profile_dump()
1216{
1217 FILE *fd;
1218
1219 if (profile_fname != NULL)
1220 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001221 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001222 if (fd == NULL)
1223 EMSG2(_(e_notopen), profile_fname);
1224 else
1225 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001226 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001227 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001228 fclose(fd);
1229 }
1230 }
1231}
1232
1233/*
1234 * Start profiling script "fp".
1235 */
1236 static void
1237script_do_profile(si)
1238 scriptitem_T *si;
1239{
1240 si->sn_pr_count = 0;
1241 profile_zero(&si->sn_pr_total);
1242 profile_zero(&si->sn_pr_self);
1243
1244 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1245 si->sn_prl_idx = -1;
1246 si->sn_prof_on = TRUE;
1247 si->sn_pr_nest = 0;
1248}
1249
1250/*
1251 * save time when starting to invoke another script or function.
1252 */
1253 void
1254script_prof_save(tm)
1255 proftime_T *tm; /* place to store wait time */
1256{
1257 scriptitem_T *si;
1258
1259 if (current_SID > 0 && current_SID <= script_items.ga_len)
1260 {
1261 si = &SCRIPT_ITEM(current_SID);
1262 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1263 profile_start(&si->sn_pr_child);
1264 }
1265 profile_get_wait(tm);
1266}
1267
1268/*
1269 * Count time spent in children after invoking another script or function.
1270 */
1271 void
1272script_prof_restore(tm)
1273 proftime_T *tm;
1274{
1275 scriptitem_T *si;
1276
1277 if (current_SID > 0 && current_SID <= script_items.ga_len)
1278 {
1279 si = &SCRIPT_ITEM(current_SID);
1280 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1281 {
1282 profile_end(&si->sn_pr_child);
1283 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1284 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1285 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1286 }
1287 }
1288}
1289
1290static proftime_T inchar_time;
1291
1292/*
1293 * Called when starting to wait for the user to type a character.
1294 */
1295 void
1296prof_inchar_enter()
1297{
1298 profile_start(&inchar_time);
1299}
1300
1301/*
1302 * Called when finished waiting for the user to type a character.
1303 */
1304 void
1305prof_inchar_exit()
1306{
1307 profile_end(&inchar_time);
1308 profile_add(&prof_wait_time, &inchar_time);
1309}
1310
1311/*
1312 * Dump the profiling results for all scripts in file "fd".
1313 */
1314 static void
1315script_dump_profile(fd)
1316 FILE *fd;
1317{
1318 int id;
1319 scriptitem_T *si;
1320 int i;
1321 FILE *sfd;
1322 sn_prl_T *pp;
1323
1324 for (id = 1; id <= script_items.ga_len; ++id)
1325 {
1326 si = &SCRIPT_ITEM(id);
1327 if (si->sn_prof_on)
1328 {
1329 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1330 if (si->sn_pr_count == 1)
1331 fprintf(fd, "Sourced 1 time\n");
1332 else
1333 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1334 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1335 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1336 fprintf(fd, "\n");
1337 fprintf(fd, "count total (s) self (s)\n");
1338
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001339 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001340 if (sfd == NULL)
1341 fprintf(fd, "Cannot open file!\n");
1342 else
1343 {
1344 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1345 {
1346 if (vim_fgets(IObuff, IOSIZE, sfd))
1347 break;
1348 pp = &PRL_ITEM(si, i);
1349 if (pp->snp_count > 0)
1350 {
1351 fprintf(fd, "%5d ", pp->snp_count);
1352 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1353 fprintf(fd, " ");
1354 else
1355 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1356 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1357 }
1358 else
1359 fprintf(fd, " ");
1360 fprintf(fd, "%s", IObuff);
1361 }
1362 fclose(sfd);
1363 }
1364 fprintf(fd, "\n");
1365 }
1366 }
1367}
1368
1369/*
1370 * Return TRUE when a function defined in the current script should be
1371 * profiled.
1372 */
1373 int
1374prof_def_func()
1375{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001376 if (current_SID > 0)
1377 return SCRIPT_ITEM(current_SID).sn_pr_force;
1378 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001379}
1380
1381# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001382#endif
1383
1384/*
1385 * If 'autowrite' option set, try to write the file.
1386 * Careful: autocommands may make "buf" invalid!
1387 *
1388 * return FAIL for failure, OK otherwise
1389 */
1390 int
1391autowrite(buf, forceit)
1392 buf_T *buf;
1393 int forceit;
1394{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001395 int r;
1396
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397 if (!(p_aw || p_awa) || !p_write
1398#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001399 /* never autowrite a "nofile" or "nowrite" buffer */
1400 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001401#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001402 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001404 r = buf_write_all(buf, forceit);
1405
1406 /* Writing may succeed but the buffer still changed, e.g., when there is a
1407 * conversion error. We do want to return FAIL then. */
1408 if (buf_valid(buf) && bufIsChanged(buf))
1409 r = FAIL;
1410 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411}
1412
1413/*
1414 * flush all buffers, except the ones that are readonly
1415 */
1416 void
1417autowrite_all()
1418{
1419 buf_T *buf;
1420
1421 if (!(p_aw || p_awa) || !p_write)
1422 return;
1423 for (buf = firstbuf; buf; buf = buf->b_next)
1424 if (bufIsChanged(buf) && !buf->b_p_ro)
1425 {
1426 (void)buf_write_all(buf, FALSE);
1427#ifdef FEAT_AUTOCMD
1428 /* an autocommand may have deleted the buffer */
1429 if (!buf_valid(buf))
1430 buf = firstbuf;
1431#endif
1432 }
1433}
1434
1435/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001436 * Return TRUE if buffer was changed and cannot be abandoned.
1437 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001439 int
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001440check_changed(buf, flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001441 buf_T *buf;
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001442 int flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001444 int forceit = (flags & CCGD_FORCEIT);
1445
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446 if ( !forceit
1447 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001448 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1449 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001450 {
1451#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1452 if ((p_confirm || cmdmod.confirm) && p_write)
1453 {
1454 buf_T *buf2;
1455 int count = 0;
1456
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001457 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001458 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1459 if (bufIsChanged(buf2)
1460 && (buf2->b_ffname != NULL
1461# ifdef FEAT_BROWSE
1462 || cmdmod.browse
1463# endif
1464 ))
1465 ++count;
1466# ifdef FEAT_AUTOCMD
1467 if (!buf_valid(buf))
1468 /* Autocommand deleted buffer, oops! It's not changed now. */
1469 return FALSE;
1470# endif
1471 dialog_changed(buf, count > 1);
1472# ifdef FEAT_AUTOCMD
1473 if (!buf_valid(buf))
1474 /* Autocommand deleted buffer, oops! It's not changed now. */
1475 return FALSE;
1476# endif
1477 return bufIsChanged(buf);
1478 }
1479#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001480 if (flags & CCGD_EXCMD)
1481 EMSG(_(e_nowrtmsg));
1482 else
1483 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001484 return TRUE;
1485 }
1486 return FALSE;
1487}
1488
1489#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1490
1491#if defined(FEAT_BROWSE) || defined(PROTO)
1492/*
1493 * When wanting to write a file without a file name, ask the user for a name.
1494 */
1495 void
1496browse_save_fname(buf)
1497 buf_T *buf;
1498{
1499 if (buf->b_fname == NULL)
1500 {
1501 char_u *fname;
1502
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001503 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1504 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001505 if (fname != NULL)
1506 {
1507 if (setfname(buf, fname, NULL, TRUE) == OK)
1508 buf->b_flags |= BF_NOTEDITED;
1509 vim_free(fname);
1510 }
1511 }
1512}
1513#endif
1514
1515/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001516 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517 * Must check 'write' option first!
1518 */
1519 void
1520dialog_changed(buf, checkall)
1521 buf_T *buf;
1522 int checkall; /* may abandon all changed buffers */
1523{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001524 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001525 int ret;
1526 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001527 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001528
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001529 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530 (buf->b_fname != NULL) ?
1531 buf->b_fname : (char_u *)_("Untitled"));
1532 if (checkall)
1533 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1534 else
1535 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1536
Bram Moolenaar8218f602012-04-25 17:32:18 +02001537 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1538 * function. */
1539 ea.append = ea.forceit = FALSE;
1540
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 if (ret == VIM_YES)
1542 {
1543#ifdef FEAT_BROWSE
1544 /* May get file name, when there is none */
1545 browse_save_fname(buf);
1546#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001547 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1548 buf->b_fname, buf->b_ffname, FALSE) == OK)
1549 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550 (void)buf_write_all(buf, FALSE);
1551 }
1552 else if (ret == VIM_NO)
1553 {
1554 unchanged(buf, TRUE);
1555 }
1556 else if (ret == VIM_ALL)
1557 {
1558 /*
1559 * Write all modified files that can be written.
1560 * Skip readonly buffers, these need to be confirmed
1561 * individually.
1562 */
1563 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1564 {
1565 if (bufIsChanged(buf2)
1566 && (buf2->b_ffname != NULL
1567#ifdef FEAT_BROWSE
1568 || cmdmod.browse
1569#endif
1570 )
1571 && !buf2->b_p_ro)
1572 {
1573#ifdef FEAT_BROWSE
1574 /* May get file name, when there is none */
1575 browse_save_fname(buf2);
1576#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001577 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1578 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1579 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580 (void)buf_write_all(buf2, FALSE);
1581#ifdef FEAT_AUTOCMD
1582 /* an autocommand may have deleted the buffer */
1583 if (!buf_valid(buf2))
1584 buf2 = firstbuf;
1585#endif
1586 }
1587 }
1588 }
1589 else if (ret == VIM_DISCARDALL)
1590 {
1591 /*
1592 * mark all buffers as unchanged
1593 */
1594 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1595 unchanged(buf2, TRUE);
1596 }
1597}
1598#endif
1599
1600/*
1601 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1602 * hidden, autowriting it or unloading it.
1603 */
1604 int
1605can_abandon(buf, forceit)
1606 buf_T *buf;
1607 int forceit;
1608{
1609 return ( P_HID(buf)
1610 || !bufIsChanged(buf)
1611 || buf->b_nwindows > 1
1612 || autowrite(buf, forceit) == OK
1613 || forceit);
1614}
1615
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001616static void add_bufnum __ARGS((int *bufnrs, int *bufnump, int nr));
1617
1618/*
1619 * Add a buffer number to "bufnrs", unless it's already there.
1620 */
1621 static void
1622add_bufnum(bufnrs, bufnump, nr)
1623 int *bufnrs;
1624 int *bufnump;
1625 int nr;
1626{
1627 int i;
1628
1629 for (i = 0; i < *bufnump; ++i)
1630 if (bufnrs[i] == nr)
1631 return;
1632 bufnrs[*bufnump] = nr;
1633 *bufnump = *bufnump + 1;
1634}
1635
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636/*
1637 * Return TRUE if any buffer was changed and cannot be abandoned.
1638 * That changed buffer becomes the current buffer.
1639 */
1640 int
1641check_changed_any(hidden)
1642 int hidden; /* Only check hidden buffers */
1643{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001644 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 buf_T *buf;
1646 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001647 int i;
1648 int bufnum = 0;
1649 int bufcount = 0;
1650 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001652 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653 win_T *wp;
1654#endif
1655
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001656 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1657 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001659 if (bufcount == 0)
1660 return FALSE;
1661
1662 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1663 if (bufnrs == NULL)
1664 return FALSE;
1665
1666 /* curbuf */
1667 bufnrs[bufnum++] = curbuf->b_fnum;
1668#ifdef FEAT_WINDOWS
1669 /* buf in curtab */
1670 FOR_ALL_WINDOWS(wp)
1671 if (wp->w_buffer != curbuf)
1672 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1673
1674 /* buf in other tab */
1675 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1676 if (tp != curtab)
1677 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1678 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1679#endif
1680 /* any other buf */
1681 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1682 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1683
1684 for (i = 0; i < bufnum; ++i)
1685 {
1686 buf = buflist_findnr(bufnrs[i]);
1687 if (buf == NULL)
1688 continue;
1689 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1690 {
1691 /* Try auto-writing the buffer. If this fails but the buffer no
1692 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001693 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1694 | CCGD_MULTWIN
1695 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001696 break; /* didn't save - still changes */
1697 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698 }
1699
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001700 if (i >= bufnum)
1701 goto theend;
1702
1703 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704 exiting = FALSE;
1705#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1706 /*
1707 * When ":confirm" used, don't give an error message.
1708 */
1709 if (!(p_confirm || cmdmod.confirm))
1710#endif
1711 {
1712 /* There must be a wait_return for this message, do_buffer()
1713 * may cause a redraw. But wait_return() is a no-op when vgetc()
1714 * is busy (Quit used from window menu), then make sure we don't
1715 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001716 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717 {
1718 msg_row = cmdline_row;
1719 msg_col = 0;
1720 msg_didout = FALSE;
1721 }
1722 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001723 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724 {
1725 save = no_wait_return;
1726 no_wait_return = FALSE;
1727 wait_return(FALSE);
1728 no_wait_return = save;
1729 }
1730 }
1731
1732#ifdef FEAT_WINDOWS
1733 /* Try to find a window that contains the buffer. */
1734 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001735 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 if (wp->w_buffer == buf)
1737 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001738 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739# ifdef FEAT_AUTOCMD
1740 /* Paranoia: did autocms wipe out the buffer with changes? */
1741 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001742 {
1743 goto theend;
1744 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001746 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001748buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749#endif
1750
1751 /* Open the changed buffer in the current window. */
1752 if (buf != curbuf)
1753 set_curbuf(buf, DOBUF_GOTO);
1754
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001755theend:
1756 vim_free(bufnrs);
1757 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001758}
1759
1760/*
1761 * return FAIL if there is no file name, OK if there is one
1762 * give error message for FAIL
1763 */
1764 int
1765check_fname()
1766{
1767 if (curbuf->b_ffname == NULL)
1768 {
1769 EMSG(_(e_noname));
1770 return FAIL;
1771 }
1772 return OK;
1773}
1774
1775/*
1776 * flush the contents of a buffer, unless it has no file name
1777 *
1778 * return FAIL for failure, OK otherwise
1779 */
1780 int
1781buf_write_all(buf, forceit)
1782 buf_T *buf;
1783 int forceit;
1784{
1785 int retval;
1786#ifdef FEAT_AUTOCMD
1787 buf_T *old_curbuf = curbuf;
1788#endif
1789
1790 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1791 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1792 FALSE, forceit, TRUE, FALSE));
1793#ifdef FEAT_AUTOCMD
1794 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001795 {
1796 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001798 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001799#endif
1800 return retval;
1801}
1802
1803/*
1804 * Code to handle the argument list.
1805 */
1806
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001807static char_u *do_one_arg __ARGS((char_u *str));
1808static int do_arglist __ARGS((char_u *str, int what, int after));
1809static void alist_check_arg_idx __ARGS((void));
1810static int editing_arg_idx __ARGS((win_T *win));
1811#ifdef FEAT_LISTCMDS
1812static int alist_add_list __ARGS((int count, char_u **files, int after));
1813#endif
1814#define AL_SET 1
1815#define AL_ADD 2
1816#define AL_DEL 3
1817
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001819 * Isolate one argument, taking backticks.
1820 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821 * Return a pointer to the start of the next argument.
1822 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001823 static char_u *
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824do_one_arg(str)
1825 char_u *str;
1826{
1827 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828 int inbacktick;
1829
Bram Moolenaar071d4272004-06-13 20:20:40 +00001830 inbacktick = FALSE;
1831 for (p = str; *str; ++str)
1832 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001833 /* When the backslash is used for escaping the special meaning of a
1834 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835 if (rem_backslash(str))
1836 {
1837 *p++ = *str++;
1838 *p++ = *str;
1839 }
1840 else
1841 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001842 /* An item ends at a space not in backticks */
1843 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001845 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001847 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 }
1849 }
1850 str = skipwhite(str);
1851 *p = NUL;
1852
1853 return str;
1854}
1855
Bram Moolenaar86b68352004-12-27 21:59:20 +00001856/*
1857 * Separate the arguments in "str" and return a list of pointers in the
1858 * growarray "gap".
1859 */
1860 int
1861get_arglist(gap, str)
1862 garray_T *gap;
1863 char_u *str;
1864{
1865 ga_init2(gap, (int)sizeof(char_u *), 20);
1866 while (*str != NUL)
1867 {
1868 if (ga_grow(gap, 1) == FAIL)
1869 {
1870 ga_clear(gap);
1871 return FAIL;
1872 }
1873 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1874
1875 /* Isolate one argument, change it in-place, put a NUL after it. */
1876 str = do_one_arg(str);
1877 }
1878 return OK;
1879}
1880
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001881#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001882/*
1883 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001884 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001885 * Return FAIL or OK.
1886 */
1887 int
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001888get_arglist_exp(str, fcountp, fnamesp, wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001889 char_u *str;
1890 int *fcountp;
1891 char_u ***fnamesp;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001892 int wig;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001893{
1894 garray_T ga;
1895 int i;
1896
1897 if (get_arglist(&ga, str) == FAIL)
1898 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001899 if (wig == TRUE)
1900 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1901 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1902 else
1903 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
1904 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
1905
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001906 ga_clear(&ga);
1907 return i;
1908}
1909#endif
1910
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
1912/*
1913 * Redefine the argument list.
1914 */
1915 void
1916set_arglist(str)
1917 char_u *str;
1918{
1919 do_arglist(str, AL_SET, 0);
1920}
1921#endif
1922
1923/*
1924 * "what" == AL_SET: Redefine the argument list to 'str'.
1925 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
1926 * "what" == AL_DEL: remove files in 'str' from the argument list.
1927 *
1928 * Return FAIL for failure, OK otherwise.
1929 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930 static int
1931do_arglist(str, what, after)
1932 char_u *str;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00001933 int what UNUSED;
1934 int after UNUSED; /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935{
1936 garray_T new_ga;
1937 int exp_count;
1938 char_u **exp_files;
1939 int i;
1940#ifdef FEAT_LISTCMDS
1941 char_u *p;
1942 int match;
1943#endif
1944
1945 /*
1946 * Collect all file name arguments in "new_ga".
1947 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00001948 if (get_arglist(&new_ga, str) == FAIL)
1949 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950
1951#ifdef FEAT_LISTCMDS
1952 if (what == AL_DEL)
1953 {
1954 regmatch_T regmatch;
1955 int didone;
1956
1957 /*
1958 * Delete the items: use each item as a regexp and find a match in the
1959 * argument list.
1960 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01001961 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
1963 {
1964 p = ((char_u **)new_ga.ga_data)[i];
1965 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
1966 if (p == NULL)
1967 break;
1968 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
1969 if (regmatch.regprog == NULL)
1970 {
1971 vim_free(p);
1972 break;
1973 }
1974
1975 didone = FALSE;
1976 for (match = 0; match < ARGCOUNT; ++match)
1977 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
1978 (colnr_T)0))
1979 {
1980 didone = TRUE;
1981 vim_free(ARGLIST[match].ae_fname);
1982 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
1983 (ARGCOUNT - match - 1) * sizeof(aentry_T));
1984 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 if (curwin->w_arg_idx > match)
1986 --curwin->w_arg_idx;
1987 --match;
1988 }
1989
Bram Moolenaar473de612013-06-08 18:19:48 +02001990 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001991 vim_free(p);
1992 if (!didone)
1993 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
1994 }
1995 ga_clear(&new_ga);
1996 }
1997 else
1998#endif
1999 {
2000 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2001 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2002 ga_clear(&new_ga);
2003 if (i == FAIL)
2004 return FAIL;
2005 if (exp_count == 0)
2006 {
2007 EMSG(_(e_nomatch));
2008 return FAIL;
2009 }
2010
2011#ifdef FEAT_LISTCMDS
2012 if (what == AL_ADD)
2013 {
2014 (void)alist_add_list(exp_count, exp_files, after);
2015 vim_free(exp_files);
2016 }
2017 else /* what == AL_SET */
2018#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002019 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020 }
2021
2022 alist_check_arg_idx();
2023
2024 return OK;
2025}
2026
2027/*
2028 * Check the validity of the arg_idx for each other window.
2029 */
2030 static void
2031alist_check_arg_idx()
2032{
2033#ifdef FEAT_WINDOWS
2034 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002035 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002036
Bram Moolenaarf740b292006-02-16 22:11:02 +00002037 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 if (win->w_alist == curwin->w_alist)
2039 check_arg_idx(win);
2040#else
2041 check_arg_idx(curwin);
2042#endif
2043}
2044
2045/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002046 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002047 * index.
2048 */
2049 static int
2050editing_arg_idx(win)
2051 win_T *win;
2052{
2053 return !(win->w_arg_idx >= WARGCOUNT(win)
2054 || (win->w_buffer->b_fnum
2055 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2056 && (win->w_buffer->b_ffname == NULL
2057 || !(fullpathcmp(
2058 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2059 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2060}
2061
2062/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063 * Check if window "win" is editing the w_arg_idx file in its argument list.
2064 */
2065 void
2066check_arg_idx(win)
2067 win_T *win;
2068{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002069 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002070 {
2071 /* We are not editing the current entry in the argument list.
2072 * Set "arg_had_last" if we are editing the last one. */
2073 win->w_arg_idx_invalid = TRUE;
2074 if (win->w_arg_idx != WARGCOUNT(win) - 1
2075 && arg_had_last == FALSE
2076#ifdef FEAT_WINDOWS
2077 && ALIST(win) == &global_alist
2078#endif
2079 && GARGCOUNT > 0
2080 && win->w_arg_idx < GARGCOUNT
2081 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2082 || (win->w_buffer->b_ffname != NULL
2083 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2084 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2085 arg_had_last = TRUE;
2086 }
2087 else
2088 {
2089 /* We are editing the current entry in the argument list.
2090 * Set "arg_had_last" if it's also the last one */
2091 win->w_arg_idx_invalid = FALSE;
2092 if (win->w_arg_idx == WARGCOUNT(win) - 1
2093#ifdef FEAT_WINDOWS
2094 && win->w_alist == &global_alist
2095#endif
2096 )
2097 arg_had_last = TRUE;
2098 }
2099}
2100
2101/*
2102 * ":args", ":argslocal" and ":argsglobal".
2103 */
2104 void
2105ex_args(eap)
2106 exarg_T *eap;
2107{
2108 int i;
2109
2110 if (eap->cmdidx != CMD_args)
2111 {
2112#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2113 alist_unlink(ALIST(curwin));
2114 if (eap->cmdidx == CMD_argglobal)
2115 ALIST(curwin) = &global_alist;
2116 else /* eap->cmdidx == CMD_arglocal */
2117 alist_new();
2118#else
2119 ex_ni(eap);
2120 return;
2121#endif
2122 }
2123
2124 if (!ends_excmd(*eap->arg))
2125 {
2126 /*
2127 * ":args file ..": define new argument list, handle like ":next"
2128 * Also for ":argslocal file .." and ":argsglobal file ..".
2129 */
2130 ex_next(eap);
2131 }
2132 else
2133#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2134 if (eap->cmdidx == CMD_args)
2135#endif
2136 {
2137 /*
2138 * ":args": list arguments.
2139 */
2140 if (ARGCOUNT > 0)
2141 {
2142 /* Overwrite the command, for a short list there is no scrolling
2143 * required and no wait_return(). */
2144 gotocmdline(TRUE);
2145 for (i = 0; i < ARGCOUNT; ++i)
2146 {
2147 if (i == curwin->w_arg_idx)
2148 msg_putchar('[');
2149 msg_outtrans(alist_name(&ARGLIST[i]));
2150 if (i == curwin->w_arg_idx)
2151 msg_putchar(']');
2152 msg_putchar(' ');
2153 }
2154 }
2155 }
2156#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2157 else if (eap->cmdidx == CMD_arglocal)
2158 {
2159 garray_T *gap = &curwin->w_alist->al_ga;
2160
2161 /*
2162 * ":argslocal": make a local copy of the global argument list.
2163 */
2164 if (ga_grow(gap, GARGCOUNT) == OK)
2165 for (i = 0; i < GARGCOUNT; ++i)
2166 if (GARGLIST[i].ae_fname != NULL)
2167 {
2168 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2169 vim_strsave(GARGLIST[i].ae_fname);
2170 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2171 GARGLIST[i].ae_fnum;
2172 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002173 }
2174 }
2175#endif
2176}
2177
2178/*
2179 * ":previous", ":sprevious", ":Next" and ":sNext".
2180 */
2181 void
2182ex_previous(eap)
2183 exarg_T *eap;
2184{
2185 /* If past the last one already, go to the last one. */
2186 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2187 do_argfile(eap, ARGCOUNT - 1);
2188 else
2189 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2190}
2191
2192/*
2193 * ":rewind", ":first", ":sfirst" and ":srewind".
2194 */
2195 void
2196ex_rewind(eap)
2197 exarg_T *eap;
2198{
2199 do_argfile(eap, 0);
2200}
2201
2202/*
2203 * ":last" and ":slast".
2204 */
2205 void
2206ex_last(eap)
2207 exarg_T *eap;
2208{
2209 do_argfile(eap, ARGCOUNT - 1);
2210}
2211
2212/*
2213 * ":argument" and ":sargument".
2214 */
2215 void
2216ex_argument(eap)
2217 exarg_T *eap;
2218{
2219 int i;
2220
2221 if (eap->addr_count > 0)
2222 i = eap->line2 - 1;
2223 else
2224 i = curwin->w_arg_idx;
2225 do_argfile(eap, i);
2226}
2227
2228/*
2229 * Edit file "argn" of the argument lists.
2230 */
2231 void
2232do_argfile(eap, argn)
2233 exarg_T *eap;
2234 int argn;
2235{
2236 int other;
2237 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002238 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239
2240 if (argn < 0 || argn >= ARGCOUNT)
2241 {
2242 if (ARGCOUNT <= 1)
2243 EMSG(_("E163: There is only one file to edit"));
2244 else if (argn < 0)
2245 EMSG(_("E164: Cannot go before first file"));
2246 else
2247 EMSG(_("E165: Cannot go beyond last file"));
2248 }
2249 else
2250 {
2251 setpcmark();
2252#ifdef FEAT_GUI
2253 need_mouse_correct = TRUE;
2254#endif
2255
2256#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002257 /* split window or create new tab page first */
2258 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002259 {
2260 if (win_split(0, 0) == FAIL)
2261 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002262 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 }
2264 else
2265#endif
2266 {
2267 /*
2268 * if 'hidden' set, only check for changed file when re-editing
2269 * the same buffer
2270 */
2271 other = TRUE;
2272 if (P_HID(curbuf))
2273 {
2274 p = fix_fname(alist_name(&ARGLIST[argn]));
2275 other = otherfile(p);
2276 vim_free(p);
2277 }
2278 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002279 && check_changed(curbuf, CCGD_AW
2280 | (other ? 0 : CCGD_MULTWIN)
2281 | (eap->forceit ? CCGD_FORCEIT : 0)
2282 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 return;
2284 }
2285
2286 curwin->w_arg_idx = argn;
2287 if (argn == ARGCOUNT - 1
2288#ifdef FEAT_WINDOWS
2289 && curwin->w_alist == &global_alist
2290#endif
2291 )
2292 arg_had_last = TRUE;
2293
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002294 /* Edit the file; always use the last known line number.
2295 * When it fails (e.g. Abort for already edited file) restore the
2296 * argument index. */
2297 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002298 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002299 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2300 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002301 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002302 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002303 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304 setmark('\'');
2305 }
2306}
2307
2308/*
2309 * ":next", and commands that behave like it.
2310 */
2311 void
2312ex_next(eap)
2313 exarg_T *eap;
2314{
2315 int i;
2316
2317 /*
2318 * check for changed buffer now, if this fails the argument list is not
2319 * redefined.
2320 */
2321 if ( P_HID(curbuf)
2322 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002323 || !check_changed(curbuf, CCGD_AW
2324 | (eap->forceit ? CCGD_FORCEIT : 0)
2325 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 {
2327 if (*eap->arg != NUL) /* redefine file list */
2328 {
2329 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2330 return;
2331 i = 0;
2332 }
2333 else
2334 i = curwin->w_arg_idx + (int)eap->line2;
2335 do_argfile(eap, i);
2336 }
2337}
2338
2339#ifdef FEAT_LISTCMDS
2340/*
2341 * ":argedit"
2342 */
2343 void
2344ex_argedit(eap)
2345 exarg_T *eap;
2346{
2347 int fnum;
2348 int i;
2349 char_u *s;
2350
2351 /* Add the argument to the buffer list and get the buffer number. */
2352 fnum = buflist_add(eap->arg, BLN_LISTED);
2353
2354 /* Check if this argument is already in the argument list. */
2355 for (i = 0; i < ARGCOUNT; ++i)
2356 if (ARGLIST[i].ae_fnum == fnum)
2357 break;
2358 if (i == ARGCOUNT)
2359 {
2360 /* Can't find it, add it to the argument list. */
2361 s = vim_strsave(eap->arg);
2362 if (s == NULL)
2363 return;
2364 i = alist_add_list(1, &s,
2365 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2366 if (i < 0)
2367 return;
2368 curwin->w_arg_idx = i;
2369 }
2370
2371 alist_check_arg_idx();
2372
2373 /* Edit the argument. */
2374 do_argfile(eap, i);
2375}
2376
2377/*
2378 * ":argadd"
2379 */
2380 void
2381ex_argadd(eap)
2382 exarg_T *eap;
2383{
2384 do_arglist(eap->arg, AL_ADD,
2385 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2386#ifdef FEAT_TITLE
2387 maketitle();
2388#endif
2389}
2390
2391/*
2392 * ":argdelete"
2393 */
2394 void
2395ex_argdelete(eap)
2396 exarg_T *eap;
2397{
2398 int i;
2399 int n;
2400
2401 if (eap->addr_count > 0)
2402 {
2403 /* ":1,4argdel": Delete all arguments in the range. */
2404 if (eap->line2 > ARGCOUNT)
2405 eap->line2 = ARGCOUNT;
2406 n = eap->line2 - eap->line1 + 1;
2407 if (*eap->arg != NUL || n <= 0)
2408 EMSG(_(e_invarg));
2409 else
2410 {
2411 for (i = eap->line1; i <= eap->line2; ++i)
2412 vim_free(ARGLIST[i - 1].ae_fname);
2413 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2414 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2415 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 if (curwin->w_arg_idx >= eap->line2)
2417 curwin->w_arg_idx -= n;
2418 else if (curwin->w_arg_idx > eap->line1)
2419 curwin->w_arg_idx = eap->line1;
2420 }
2421 }
2422 else if (*eap->arg == NUL)
2423 EMSG(_(e_argreq));
2424 else
2425 do_arglist(eap->arg, AL_DEL, 0);
2426#ifdef FEAT_TITLE
2427 maketitle();
2428#endif
2429}
2430
2431/*
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002432 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 */
2434 void
2435ex_listdo(eap)
2436 exarg_T *eap;
2437{
2438 int i;
2439#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002440 win_T *wp;
2441 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442#endif
2443 buf_T *buf;
2444 int next_fnum = 0;
2445#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2446 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002447#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002448 char_u *p_shm_save;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449
2450#ifndef FEAT_WINDOWS
2451 if (eap->cmdidx == CMD_windo)
2452 {
2453 ex_ni(eap);
2454 return;
2455 }
2456#endif
2457
2458#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002459 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002460 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2461 * great speed improvement. */
2462 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002464#ifdef FEAT_CLIPBOARD
2465 start_global_changes();
2466#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467
2468 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002469 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002471 || !check_changed(curbuf, CCGD_AW
2472 | (eap->forceit ? CCGD_FORCEIT : 0)
2473 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 {
2475 /* start at the first argument/window/buffer */
2476 i = 0;
2477#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002478 wp = firstwin;
2479 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480#endif
2481 /* set pcmark now */
2482 if (eap->cmdidx == CMD_bufdo)
2483 goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
2484 else
2485 setpcmark();
2486 listcmd_busy = TRUE; /* avoids setting pcmark below */
2487
2488 while (!got_int)
2489 {
2490 if (eap->cmdidx == CMD_argdo)
2491 {
2492 /* go to argument "i" */
2493 if (i == ARGCOUNT)
2494 break;
2495 /* Don't call do_argfile() when already there, it will try
2496 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002497 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002498 {
2499 /* Clear 'shm' to avoid that the file message overwrites
2500 * any output from the command. */
2501 p_shm_save = vim_strsave(p_shm);
2502 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002504 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2505 vim_free(p_shm_save);
2506 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 if (curwin->w_arg_idx != i)
2508 break;
2509 ++i;
2510 }
2511#ifdef FEAT_WINDOWS
2512 else if (eap->cmdidx == CMD_windo)
2513 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002514 /* go to window "wp" */
2515 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002517 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002518 if (curwin != wp)
2519 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002520 wp = curwin->w_next;
2521 }
2522 else if (eap->cmdidx == CMD_tabdo)
2523 {
2524 /* go to window "tp" */
2525 if (!valid_tabpage(tp))
2526 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002527 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002528 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529 }
2530#endif
2531 else if (eap->cmdidx == CMD_bufdo)
2532 {
2533 /* Remember the number of the next listed buffer, in case
2534 * ":bwipe" is used or autocommands do something strange. */
2535 next_fnum = -1;
2536 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2537 if (buf->b_p_bl)
2538 {
2539 next_fnum = buf->b_fnum;
2540 break;
2541 }
2542 }
2543
2544 /* execute the command */
2545 do_cmdline(eap->arg, eap->getline, eap->cookie,
2546 DOCMD_VERBOSE + DOCMD_NOWAIT);
2547
2548 if (eap->cmdidx == CMD_bufdo)
2549 {
2550 /* Done? */
2551 if (next_fnum < 0)
2552 break;
2553 /* Check if the buffer still exists. */
2554 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2555 if (buf->b_fnum == next_fnum)
2556 break;
2557 if (buf == NULL)
2558 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002559
2560 /* Go to the next buffer. Clear 'shm' to avoid that the file
2561 * message overwrites any output from the command. */
2562 p_shm_save = vim_strsave(p_shm);
2563 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002565 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2566 vim_free(p_shm_save);
2567
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 /* If autocommands took us elsewhere, quit here */
2569 if (curbuf->b_fnum != next_fnum)
2570 break;
2571 }
2572
2573 if (eap->cmdidx == CMD_windo)
2574 {
2575 validate_cursor(); /* cursor may have moved */
2576#ifdef FEAT_SCROLLBIND
2577 /* required when 'scrollbind' has been set */
2578 if (curwin->w_p_scb)
2579 do_check_scrollbind(TRUE);
2580#endif
2581 }
2582 }
2583 listcmd_busy = FALSE;
2584 }
2585
2586#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002587 if (save_ei != NULL)
2588 {
2589 au_event_restore(save_ei);
2590 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2591 curbuf->b_fname, TRUE, curbuf);
2592 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002594#ifdef FEAT_CLIPBOARD
2595 end_global_changes();
2596#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597}
2598
2599/*
2600 * Add files[count] to the arglist of the current window after arg "after".
2601 * The file names in files[count] must have been allocated and are taken over.
2602 * Files[] itself is not taken over.
2603 * Returns index of first added argument. Returns -1 when failed (out of mem).
2604 */
2605 static int
2606alist_add_list(count, files, after)
2607 int count;
2608 char_u **files;
2609 int after; /* where to add: 0 = before first one */
2610{
2611 int i;
2612
2613 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2614 {
2615 if (after < 0)
2616 after = 0;
2617 if (after > ARGCOUNT)
2618 after = ARGCOUNT;
2619 if (after < ARGCOUNT)
2620 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2621 (ARGCOUNT - after) * sizeof(aentry_T));
2622 for (i = 0; i < count; ++i)
2623 {
2624 ARGLIST[after + i].ae_fname = files[i];
2625 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2626 }
2627 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 if (curwin->w_arg_idx >= after)
2629 ++curwin->w_arg_idx;
2630 return after;
2631 }
2632
2633 for (i = 0; i < count; ++i)
2634 vim_free(files[i]);
2635 return -1;
2636}
2637
2638#endif /* FEAT_LISTCMDS */
2639
2640#ifdef FEAT_EVAL
2641/*
2642 * ":compiler[!] {name}"
2643 */
2644 void
2645ex_compiler(eap)
2646 exarg_T *eap;
2647{
2648 char_u *buf;
2649 char_u *old_cur_comp = NULL;
2650 char_u *p;
2651
2652 if (*eap->arg == NUL)
2653 {
2654 /* List all compiler scripts. */
2655 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2656 /* ) keep the indenter happy... */
2657 }
2658 else
2659 {
2660 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2661 if (buf != NULL)
2662 {
2663 if (eap->forceit)
2664 {
2665 /* ":compiler! {name}" sets global options */
2666 do_cmdline_cmd((char_u *)
2667 "command -nargs=* CompilerSet set <args>");
2668 }
2669 else
2670 {
2671 /* ":compiler! {name}" sets local options.
2672 * To remain backwards compatible "current_compiler" is always
2673 * used. A user's compiler plugin may set it, the distributed
2674 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002675 * "b:current_compiler" and restore "current_compiler".
2676 * Explicitly prepend "g:" to make it work in a function. */
2677 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678 if (old_cur_comp != NULL)
2679 old_cur_comp = vim_strsave(old_cur_comp);
2680 do_cmdline_cmd((char_u *)
2681 "command -nargs=* CompilerSet setlocal <args>");
2682 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002683 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002684 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685
2686 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002687 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002688 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2689 vim_free(buf);
2690
2691 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2692
2693 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002694 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 if (p != NULL)
2696 set_internal_string_var((char_u *)"b:current_compiler", p);
2697
2698 /* Restore "current_compiler" for ":compiler {name}". */
2699 if (!eap->forceit)
2700 {
2701 if (old_cur_comp != NULL)
2702 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002703 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002704 old_cur_comp);
2705 vim_free(old_cur_comp);
2706 }
2707 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002708 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709 }
2710 }
2711 }
2712}
2713#endif
2714
2715/*
2716 * ":runtime {name}"
2717 */
2718 void
2719ex_runtime(eap)
2720 exarg_T *eap;
2721{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002722 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723}
2724
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002725static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726
2727 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002728source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002729 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002730 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002731{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002732 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733}
2734
2735/*
2736 * Source the file "name" from all directories in 'runtimepath'.
2737 * "name" can contain wildcards.
2738 * When "all" is TRUE, source all files, otherwise only the first one.
2739 * return FAIL when no file could be sourced, OK otherwise.
2740 */
2741 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002742source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 char_u *name;
2744 int all;
2745{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002746 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747}
2748
2749/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002750 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2751 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2753 * used.
2754 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002755 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002756 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2757 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002758 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 */
2760 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002761do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762 char_u *name;
2763 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002764 void (*callback)__ARGS((char_u *fname, void *ck));
2765 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766{
2767 char_u *rtp;
2768 char_u *np;
2769 char_u *buf;
2770 char_u *rtp_copy;
2771 char_u *tail;
2772 int num_files;
2773 char_u **files;
2774 int i;
2775 int did_one = FALSE;
2776#ifdef AMIGA
2777 struct Process *proc = (struct Process *)FindTask(0L);
2778 APTR save_winptr = proc->pr_WindowPtr;
2779
2780 /* Avoid a requester here for a volume that doesn't exist. */
2781 proc->pr_WindowPtr = (APTR)-1L;
2782#endif
2783
2784 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2785 * value. */
2786 rtp_copy = vim_strsave(p_rtp);
2787 buf = alloc(MAXPATHL);
2788 if (buf != NULL && rtp_copy != NULL)
2789 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002790 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002791 {
2792 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002793 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002795 verbose_leave();
2796 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002797
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798 /* Loop over all entries in 'runtimepath'. */
2799 rtp = rtp_copy;
2800 while (*rtp != NUL && (all || !did_one))
2801 {
2802 /* Copy the path from 'runtimepath' to buf[]. */
2803 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002804 if (name == NULL)
2805 {
2806 (*callback)(buf, (void *) &cookie);
2807 if (!did_one)
2808 did_one = (cookie == NULL);
2809 }
2810 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811 {
2812 add_pathsep(buf);
2813 tail = buf + STRLEN(buf);
2814
2815 /* Loop over all patterns in "name" */
2816 np = name;
2817 while (*np != NUL && (all || !did_one))
2818 {
2819 /* Append the pattern from "name" to buf[]. */
2820 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2821 "\t ");
2822
2823 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002824 {
2825 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002826 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002827 verbose_leave();
2828 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829
2830 /* Expand wildcards, invoke the callback for each match. */
2831 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2832 EW_FILE) == OK)
2833 {
2834 for (i = 0; i < num_files; ++i)
2835 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002836 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 did_one = TRUE;
2838 if (!all)
2839 break;
2840 }
2841 FreeWild(num_files, files);
2842 }
2843 }
2844 }
2845 }
2846 }
2847 vim_free(buf);
2848 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002849 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002850 {
2851 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002852 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002853 verbose_leave();
2854 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855
2856#ifdef AMIGA
2857 proc->pr_WindowPtr = save_winptr;
2858#endif
2859
2860 return did_one ? OK : FAIL;
2861}
2862
2863#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2864/*
2865 * ":options"
2866 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867 void
2868ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002869 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002870{
2871 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2872}
2873#endif
2874
2875/*
2876 * ":source {fname}"
2877 */
2878 void
2879ex_source(eap)
2880 exarg_T *eap;
2881{
2882#ifdef FEAT_BROWSE
2883 if (cmdmod.browse)
2884 {
2885 char_u *fname = NULL;
2886
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002887 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2889 if (fname != NULL)
2890 {
2891 cmd_source(fname, eap);
2892 vim_free(fname);
2893 }
2894 }
2895 else
2896#endif
2897 cmd_source(eap->arg, eap);
2898}
2899
2900 static void
2901cmd_source(fname, eap)
2902 char_u *fname;
2903 exarg_T *eap;
2904{
2905 if (*fname == NUL)
2906 EMSG(_(e_argreq));
2907
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002909 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002910 * Need to execute the commands directly. This is required at least
2911 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 * - ":g" command busy
2913 * - after ":argdo", ":windo" or ":bufdo"
2914 * - another command follows
2915 * - inside a loop
2916 */
2917 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2918#ifdef FEAT_EVAL
2919 || eap->cstack->cs_idx >= 0
2920#endif
2921 );
2922
2923 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002924 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 EMSG2(_(e_notopen), fname);
2926}
2927
2928/*
2929 * ":source" and associated commands.
2930 */
2931/*
2932 * Structure used to store info for each sourced file.
2933 * It is shared between do_source() and getsourceline().
2934 * This is required, because it needs to be handed to do_cmdline() and
2935 * sourcing can be done recursively.
2936 */
2937struct source_cookie
2938{
2939 FILE *fp; /* opened file for sourcing */
2940 char_u *nextline; /* if not NULL: line that was read ahead */
2941 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002942#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2944 int error; /* TRUE if LF found after CR-LF */
2945#endif
2946#ifdef FEAT_EVAL
2947 linenr_T breakpoint; /* next line with breakpoint or zero */
2948 char_u *fname; /* name of sourced file */
2949 int dbg_tick; /* debug_tick when breakpoint was set */
2950 int level; /* top nesting level of sourced file */
2951#endif
2952#ifdef FEAT_MBYTE
2953 vimconv_T conv; /* type of conversion */
2954#endif
2955};
2956
2957#ifdef FEAT_EVAL
2958/*
2959 * Return the address holding the next breakpoint line for a source cookie.
2960 */
2961 linenr_T *
2962source_breakpoint(cookie)
2963 void *cookie;
2964{
2965 return &((struct source_cookie *)cookie)->breakpoint;
2966}
2967
2968/*
2969 * Return the address holding the debug tick for a source cookie.
2970 */
2971 int *
2972source_dbg_tick(cookie)
2973 void *cookie;
2974{
2975 return &((struct source_cookie *)cookie)->dbg_tick;
2976}
2977
2978/*
2979 * Return the nesting level for a source cookie.
2980 */
2981 int
2982source_level(cookie)
2983 void *cookie;
2984{
2985 return ((struct source_cookie *)cookie)->level;
2986}
2987#endif
2988
2989static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
2990
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002991#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
2992# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993static FILE *fopen_noinh_readbin __ARGS((char *filename));
2994
2995/*
2996 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01002997 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998 */
2999 static FILE *
3000fopen_noinh_readbin(filename)
3001 char *filename;
3002{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003003# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003004 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3005# else
3006 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003007# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008
3009 if (fd_tmp == -1)
3010 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003011
3012# ifdef HAVE_FD_CLOEXEC
3013 {
3014 int fdflags = fcntl(fd_tmp, F_GETFD);
3015 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
3016 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
3017 }
3018# endif
3019
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 return fdopen(fd_tmp, READBIN);
3021}
3022#endif
3023
3024
3025/*
3026 * do_source: Read the file "fname" and execute its lines as EX commands.
3027 *
3028 * This function may be called recursively!
3029 *
3030 * return FAIL if file could not be opened, OK otherwise
3031 */
3032 int
3033do_source(fname, check_other, is_vimrc)
3034 char_u *fname;
3035 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003036 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003037{
3038 struct source_cookie cookie;
3039 char_u *save_sourcing_name;
3040 linenr_T save_sourcing_lnum;
3041 char_u *p;
3042 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003043 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044 int retval = FAIL;
3045#ifdef FEAT_EVAL
3046 scid_T save_current_SID;
3047 static scid_T last_current_SID = 0;
3048 void *save_funccalp;
3049 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003050 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051# ifdef UNIX
3052 struct stat st;
3053 int stat_ok;
3054# endif
3055#endif
3056#ifdef STARTUPTIME
3057 struct timeval tv_rel;
3058 struct timeval tv_start;
3059#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003060#ifdef FEAT_PROFILE
3061 proftime_T wait_start;
3062#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065 if (p == NULL)
3066 return retval;
3067 fname_exp = fix_fname(p);
3068 vim_free(p);
3069 if (fname_exp == NULL)
3070 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 if (mch_isdir(fname_exp))
3072 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003073 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 goto theend;
3075 }
3076
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003077#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003078 /* Apply SourceCmd autocommands, they should get the file and source it. */
3079 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3080 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3081 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003082 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003083# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003084 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003085# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003086 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003087# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003088 goto theend;
3089 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003090
3091 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003092 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3093#endif
3094
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003095#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3097#else
3098 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3099#endif
3100 if (cookie.fp == NULL && check_other)
3101 {
3102 /*
3103 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3104 * and ".exrc" by "_exrc" or vice versa.
3105 */
3106 p = gettail(fname_exp);
3107 if ((*p == '.' || *p == '_')
3108 && (STRICMP(p + 1, "vimrc") == 0
3109 || STRICMP(p + 1, "gvimrc") == 0
3110 || STRICMP(p + 1, "exrc") == 0))
3111 {
3112 if (*p == '_')
3113 *p = '.';
3114 else
3115 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003116#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3118#else
3119 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3120#endif
3121 }
3122 }
3123
3124 if (cookie.fp == NULL)
3125 {
3126 if (p_verbose > 0)
3127 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003128 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003130 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003131 else
3132 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003133 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003134 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 }
3136 goto theend;
3137 }
3138
3139 /*
3140 * The file exists.
3141 * - In verbose mode, give a message.
3142 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3143 */
3144 if (p_verbose > 1)
3145 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003146 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003148 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 else
3150 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003151 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003152 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003154 if (is_vimrc == DOSO_VIMRC)
3155 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3156 else if (is_vimrc == DOSO_GVIMRC)
3157 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158
3159#ifdef USE_CRNL
3160 /* If no automatic file format: Set default to CR-NL. */
3161 if (*p_ffs == NUL)
3162 cookie.fileformat = EOL_DOS;
3163 else
3164 cookie.fileformat = EOL_UNKNOWN;
3165 cookie.error = FALSE;
3166#endif
3167
3168#ifdef USE_CR
3169 /* If no automatic file format: Set default to CR. */
3170 if (*p_ffs == NUL)
3171 cookie.fileformat = EOL_MAC;
3172 else
3173 cookie.fileformat = EOL_UNKNOWN;
3174 cookie.error = FALSE;
3175#endif
3176
3177 cookie.nextline = NULL;
3178 cookie.finished = FALSE;
3179
3180#ifdef FEAT_EVAL
3181 /*
3182 * Check if this script has a breakpoint.
3183 */
3184 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3185 cookie.fname = fname_exp;
3186 cookie.dbg_tick = debug_tick;
3187
3188 cookie.level = ex_nesting_level;
3189#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003190
3191 /*
3192 * Keep the sourcing name/lnum, for recursive calls.
3193 */
3194 save_sourcing_name = sourcing_name;
3195 sourcing_name = fname_exp;
3196 save_sourcing_lnum = sourcing_lnum;
3197 sourcing_lnum = 0;
3198
Bram Moolenaar73881402009-02-04 16:50:47 +00003199#ifdef FEAT_MBYTE
3200 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3201
3202 /* Read the first line so we can check for a UTF-8 BOM. */
3203 firstline = getsourceline(0, (void *)&cookie, 0);
3204 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3205 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3206 {
3207 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3208 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3209 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003210 if (p == NULL)
3211 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003212 if (p != NULL)
3213 {
3214 vim_free(firstline);
3215 firstline = p;
3216 }
3217 }
3218#endif
3219
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003221 if (time_fd != NULL)
3222 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003223#endif
3224
3225#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003226# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003227 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003228 prof_child_enter(&wait_start); /* entering a child now */
3229# endif
3230
3231 /* Don't use local function variables, if called from a function.
3232 * Also starts profiling timer for nested script. */
3233 save_funccalp = save_funccal();
3234
Bram Moolenaar071d4272004-06-13 20:20:40 +00003235 /*
3236 * Check if this script was sourced before to finds its SID.
3237 * If it's new, generate a new SID.
3238 */
3239 save_current_SID = current_SID;
3240# ifdef UNIX
3241 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3242# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003243 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3244 {
3245 si = &SCRIPT_ITEM(current_SID);
3246 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247 && (
3248# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003249 /* Compare dev/ino when possible, it catches symbolic
3250 * links. Also compare file names, the inode may change
3251 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003252 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003253 && (si->sn_dev == st.st_dev
3254 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003256 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003258 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259 if (current_SID == 0)
3260 {
3261 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003262 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3263 == FAIL)
3264 goto almosttheend;
3265 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003267 ++script_items.ga_len;
3268 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3269# ifdef FEAT_PROFILE
3270 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003273 si = &SCRIPT_ITEM(current_SID);
3274 si->sn_name = fname_exp;
3275 fname_exp = NULL;
3276# ifdef UNIX
3277 if (stat_ok)
3278 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003279 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003280 si->sn_dev = st.st_dev;
3281 si->sn_ino = st.st_ino;
3282 }
3283 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003284 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003285# endif
3286
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 /* Allocate the local script variables to use for this script. */
3288 new_script_vars(current_SID);
3289 }
3290
Bram Moolenaar05159a02005-02-26 23:04:13 +00003291# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003292 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003293 {
3294 int forceit;
3295
3296 /* Check if we do profiling for this script. */
3297 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3298 {
3299 script_do_profile(si);
3300 si->sn_pr_force = forceit;
3301 }
3302 if (si->sn_prof_on)
3303 {
3304 ++si->sn_pr_count;
3305 profile_start(&si->sn_pr_start);
3306 profile_zero(&si->sn_pr_children);
3307 }
3308 }
3309# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310#endif
3311
3312 /*
3313 * Call do_cmdline, which will call getsourceline() to get the lines.
3314 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003315 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003318
3319#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003320 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003321 {
3322 /* Get "si" again, "script_items" may have been reallocated. */
3323 si = &SCRIPT_ITEM(current_SID);
3324 if (si->sn_prof_on)
3325 {
3326 profile_end(&si->sn_pr_start);
3327 profile_sub_wait(&wait_start, &si->sn_pr_start);
3328 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003329 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3330 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003331 }
3332 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333#endif
3334
3335 if (got_int)
3336 EMSG(_(e_interr));
3337 sourcing_name = save_sourcing_name;
3338 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 if (p_verbose > 1)
3340 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003341 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003342 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003344 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003345 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 }
3347#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003348 if (time_fd != NULL)
3349 {
3350 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3351 time_msg((char *)IObuff, &tv_start);
3352 time_pop(&tv_rel);
3353 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354#endif
3355
3356#ifdef FEAT_EVAL
3357 /*
3358 * After a "finish" in debug mode, need to break at first command of next
3359 * sourced file.
3360 */
3361 if (save_debug_break_level > ex_nesting_level
3362 && debug_break_level == ex_nesting_level)
3363 ++debug_break_level;
3364#endif
3365
Bram Moolenaar05159a02005-02-26 23:04:13 +00003366#ifdef FEAT_EVAL
3367almosttheend:
3368 current_SID = save_current_SID;
3369 restore_funccal(save_funccalp);
3370# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003371 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003372 prof_child_exit(&wait_start); /* leaving a child now */
3373# endif
3374#endif
3375 fclose(cookie.fp);
3376 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003377 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003378#ifdef FEAT_MBYTE
3379 convert_setup(&cookie.conv, NULL, NULL);
3380#endif
3381
Bram Moolenaar071d4272004-06-13 20:20:40 +00003382theend:
3383 vim_free(fname_exp);
3384 return retval;
3385}
3386
3387#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003388
Bram Moolenaar071d4272004-06-13 20:20:40 +00003389/*
3390 * ":scriptnames"
3391 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 void
3393ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003394 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395{
3396 int i;
3397
Bram Moolenaar05159a02005-02-26 23:04:13 +00003398 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3399 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003400 {
3401 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3402 NameBuff, MAXPATHL, TRUE);
3403 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003404 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405}
3406
3407# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3408/*
3409 * Fix slashes in the list of script names for 'shellslash'.
3410 */
3411 void
3412scriptnames_slash_adjust()
3413{
3414 int i;
3415
Bram Moolenaar05159a02005-02-26 23:04:13 +00003416 for (i = 1; i <= script_items.ga_len; ++i)
3417 if (SCRIPT_ITEM(i).sn_name != NULL)
3418 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419}
3420# endif
3421
3422/*
3423 * Get a pointer to a script name. Used for ":verbose set".
3424 */
3425 char_u *
3426get_scriptname(id)
3427 scid_T id;
3428{
3429 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003430 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003432 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003434 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003436 return (char_u *)_("environment variable");
3437 if (id == SID_ERROR)
3438 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003439 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003441
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003442# if defined(EXITFREE) || defined(PROTO)
3443 void
3444free_scriptnames()
3445{
3446 int i;
3447
3448 for (i = script_items.ga_len; i > 0; --i)
3449 vim_free(SCRIPT_ITEM(i).sn_name);
3450 ga_clear(&script_items);
3451}
3452# endif
3453
Bram Moolenaar071d4272004-06-13 20:20:40 +00003454#endif
3455
3456#if defined(USE_CR) || defined(PROTO)
3457
3458# if defined(__MSL__) && (__MSL__ >= 22)
3459/*
3460 * Newer version of the Metrowerks library handle DOS and UNIX files
3461 * without help.
3462 * Test with earlier versions, MSL 2.2 is the library supplied with
3463 * Codewarrior Pro 2.
3464 */
3465 char *
3466fgets_cr(s, n, stream)
3467 char *s;
3468 int n;
3469 FILE *stream;
3470{
3471 return fgets(s, n, stream);
3472}
3473# else
3474/*
3475 * Version of fgets() which also works for lines ending in a <CR> only
3476 * (Macintosh format).
3477 * For older versions of the Metrowerks library.
3478 * At least CodeWarrior 9 needed this code.
3479 */
3480 char *
3481fgets_cr(s, n, stream)
3482 char *s;
3483 int n;
3484 FILE *stream;
3485{
3486 int c = 0;
3487 int char_read = 0;
3488
3489 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3490 {
3491 c = fgetc(stream);
3492 s[char_read++] = c;
3493 /* If the file is in DOS format, we need to skip a NL after a CR. I
3494 * thought it was the other way around, but this appears to work... */
3495 if (c == '\n')
3496 {
3497 c = fgetc(stream);
3498 if (c != '\r')
3499 ungetc(c, stream);
3500 }
3501 }
3502
3503 s[char_read] = 0;
3504 if (char_read == 0)
3505 return NULL;
3506
3507 if (feof(stream) && char_read == 1)
3508 return NULL;
3509
3510 return s;
3511}
3512# endif
3513#endif
3514
3515/*
3516 * Get one full line from a sourced file.
3517 * Called by do_cmdline() when it's called from do_source().
3518 *
3519 * Return a pointer to the line in allocated memory.
3520 * Return NULL for end-of-file or some error.
3521 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522 char_u *
3523getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003524 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003526 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527{
3528 struct source_cookie *sp = (struct source_cookie *)cookie;
3529 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003530 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531
3532#ifdef FEAT_EVAL
3533 /* If breakpoints have been added/deleted need to check for it. */
3534 if (sp->dbg_tick < debug_tick)
3535 {
3536 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3537 sp->dbg_tick = debug_tick;
3538 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003539# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003540 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003541 script_line_end();
3542# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543#endif
3544 /*
3545 * Get current line. If there is a read-ahead line, use it, otherwise get
3546 * one now.
3547 */
3548 if (sp->finished)
3549 line = NULL;
3550 else if (sp->nextline == NULL)
3551 line = get_one_sourceline(sp);
3552 else
3553 {
3554 line = sp->nextline;
3555 sp->nextline = NULL;
3556 ++sourcing_lnum;
3557 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003558#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003559 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003560 script_line_start();
3561#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003562
3563 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3564 * contain the 'C' flag. */
3565 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3566 {
3567 /* compensate for the one line read-ahead */
3568 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003569
3570 /* Get the next line and concatenate it when it starts with a
3571 * backslash. We always need to read the next line, keep it in
3572 * sp->nextline. */
3573 sp->nextline = get_one_sourceline(sp);
3574 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003576 garray_T ga;
3577
Bram Moolenaarb549a732012-02-22 18:29:33 +01003578 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003579 ga_concat(&ga, line);
3580 ga_concat(&ga, p + 1);
3581 for (;;)
3582 {
3583 vim_free(sp->nextline);
3584 sp->nextline = get_one_sourceline(sp);
3585 if (sp->nextline == NULL)
3586 break;
3587 p = skipwhite(sp->nextline);
3588 if (*p != '\\')
3589 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003590 /* Adjust the growsize to the current length to speed up
3591 * concatenating many lines. */
3592 if (ga.ga_len > 400)
3593 {
3594 if (ga.ga_len > 8000)
3595 ga.ga_growsize = 8000;
3596 else
3597 ga.ga_growsize = ga.ga_len;
3598 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003599 ga_concat(&ga, p + 1);
3600 }
3601 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003603 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604 }
3605 }
3606
3607#ifdef FEAT_MBYTE
3608 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3609 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003610 char_u *s;
3611
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612 /* Convert the encoding of the script line. */
3613 s = string_convert(&sp->conv, line, NULL);
3614 if (s != NULL)
3615 {
3616 vim_free(line);
3617 line = s;
3618 }
3619 }
3620#endif
3621
3622#ifdef FEAT_EVAL
3623 /* Did we encounter a breakpoint? */
3624 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3625 {
3626 dbg_breakpoint(sp->fname, sourcing_lnum);
3627 /* Find next breakpoint. */
3628 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3629 sp->dbg_tick = debug_tick;
3630 }
3631#endif
3632
3633 return line;
3634}
3635
3636 static char_u *
3637get_one_sourceline(sp)
3638 struct source_cookie *sp;
3639{
3640 garray_T ga;
3641 int len;
3642 int c;
3643 char_u *buf;
3644#ifdef USE_CRNL
3645 int has_cr; /* CR-LF found */
3646#endif
3647#ifdef USE_CR
3648 char_u *scan;
3649#endif
3650 int have_read = FALSE;
3651
3652 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003653 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654
3655 /*
3656 * Loop until there is a finished line (or end-of-file).
3657 */
3658 sourcing_lnum++;
3659 for (;;)
3660 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003661 /* make room to read at least 120 (more) characters */
3662 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 break;
3664 buf = (char_u *)ga.ga_data;
3665
3666#ifdef USE_CR
3667 if (sp->fileformat == EOL_MAC)
3668 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003669 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3670 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 break;
3672 }
3673 else
3674#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003675 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3676 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003678 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679#ifdef USE_CRNL
3680 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3681 * CTRL-Z by its own, or after a NL. */
3682 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3683 && sp->fileformat == EOL_DOS
3684 && buf[len - 1] == Ctrl_Z)
3685 {
3686 buf[len - 1] = NUL;
3687 break;
3688 }
3689#endif
3690
3691#ifdef USE_CR
3692 /* If the read doesn't stop on a new line, and there's
3693 * some CR then we assume a Mac format */
3694 if (sp->fileformat == EOL_UNKNOWN)
3695 {
3696 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3697 sp->fileformat = EOL_MAC;
3698 else
3699 sp->fileformat = EOL_UNIX;
3700 }
3701
3702 if (sp->fileformat == EOL_MAC)
3703 {
3704 scan = vim_strchr(buf, '\r');
3705
3706 if (scan != NULL)
3707 {
3708 *scan = '\n';
3709 if (*(scan + 1) != 0)
3710 {
3711 *(scan + 1) = 0;
3712 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3713 }
3714 }
3715 len = STRLEN(buf);
3716 }
3717#endif
3718
3719 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720 ga.ga_len = len;
3721
3722 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003723 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 continue;
3725
3726 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3727 {
3728#ifdef USE_CRNL
3729 has_cr = (len >= 2 && buf[len - 2] == '\r');
3730 if (sp->fileformat == EOL_UNKNOWN)
3731 {
3732 if (has_cr)
3733 sp->fileformat = EOL_DOS;
3734 else
3735 sp->fileformat = EOL_UNIX;
3736 }
3737
3738 if (sp->fileformat == EOL_DOS)
3739 {
3740 if (has_cr) /* replace trailing CR */
3741 {
3742 buf[len - 2] = '\n';
3743 --len;
3744 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 }
3746 else /* lines like ":map xx yy^M" will have failed */
3747 {
3748 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003749 {
3750 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003752 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 sp->error = TRUE;
3754 sp->fileformat = EOL_UNIX;
3755 }
3756 }
3757#endif
3758 /* The '\n' is escaped if there is an odd number of ^V's just
3759 * before it, first set "c" just before the 'V's and then check
3760 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3761 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3762 ;
3763 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3764 {
3765 sourcing_lnum++;
3766 continue;
3767 }
3768
3769 buf[len - 1] = NUL; /* remove the NL */
3770 }
3771
3772 /*
3773 * Check for ^C here now and then, so recursive :so can be broken.
3774 */
3775 line_breakcheck();
3776 break;
3777 }
3778
3779 if (have_read)
3780 return (char_u *)ga.ga_data;
3781
3782 vim_free(ga.ga_data);
3783 return NULL;
3784}
3785
Bram Moolenaar05159a02005-02-26 23:04:13 +00003786#if defined(FEAT_PROFILE) || defined(PROTO)
3787/*
3788 * Called when starting to read a script line.
3789 * "sourcing_lnum" must be correct!
3790 * When skipping lines it may not actually be executed, but we won't find out
3791 * until later and we need to store the time now.
3792 */
3793 void
3794script_line_start()
3795{
3796 scriptitem_T *si;
3797 sn_prl_T *pp;
3798
3799 if (current_SID <= 0 || current_SID > script_items.ga_len)
3800 return;
3801 si = &SCRIPT_ITEM(current_SID);
3802 if (si->sn_prof_on && sourcing_lnum >= 1)
3803 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003804 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003805 * here isn't counted. */
3806 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3807 si->sn_prl_idx = sourcing_lnum - 1;
3808 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3809 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3810 {
3811 /* Zero counters for a line that was not used before. */
3812 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3813 pp->snp_count = 0;
3814 profile_zero(&pp->sn_prl_total);
3815 profile_zero(&pp->sn_prl_self);
3816 ++si->sn_prl_ga.ga_len;
3817 }
3818 si->sn_prl_execed = FALSE;
3819 profile_start(&si->sn_prl_start);
3820 profile_zero(&si->sn_prl_children);
3821 profile_get_wait(&si->sn_prl_wait);
3822 }
3823}
3824
3825/*
3826 * Called when actually executing a function line.
3827 */
3828 void
3829script_line_exec()
3830{
3831 scriptitem_T *si;
3832
3833 if (current_SID <= 0 || current_SID > script_items.ga_len)
3834 return;
3835 si = &SCRIPT_ITEM(current_SID);
3836 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3837 si->sn_prl_execed = TRUE;
3838}
3839
3840/*
3841 * Called when done with a function line.
3842 */
3843 void
3844script_line_end()
3845{
3846 scriptitem_T *si;
3847 sn_prl_T *pp;
3848
3849 if (current_SID <= 0 || current_SID > script_items.ga_len)
3850 return;
3851 si = &SCRIPT_ITEM(current_SID);
3852 if (si->sn_prof_on && si->sn_prl_idx >= 0
3853 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3854 {
3855 if (si->sn_prl_execed)
3856 {
3857 pp = &PRL_ITEM(si, si->sn_prl_idx);
3858 ++pp->snp_count;
3859 profile_end(&si->sn_prl_start);
3860 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003861 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003862 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3863 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003864 }
3865 si->sn_prl_idx = -1;
3866 }
3867}
3868#endif
3869
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870/*
3871 * ":scriptencoding": Set encoding conversion for a sourced script.
3872 * Without the multi-byte feature it's simply ignored.
3873 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 void
3875ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003876 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877{
3878#ifdef FEAT_MBYTE
3879 struct source_cookie *sp;
3880 char_u *name;
3881
3882 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3883 {
3884 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3885 return;
3886 }
3887
3888 if (*eap->arg != NUL)
3889 {
3890 name = enc_canonize(eap->arg);
3891 if (name == NULL) /* out of memory */
3892 return;
3893 }
3894 else
3895 name = eap->arg;
3896
3897 /* Setup for conversion from the specified encoding to 'encoding'. */
3898 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3899 convert_setup(&sp->conv, name, p_enc);
3900
3901 if (name != eap->arg)
3902 vim_free(name);
3903#endif
3904}
3905
3906#if defined(FEAT_EVAL) || defined(PROTO)
3907/*
3908 * ":finish": Mark a sourced file as finished.
3909 */
3910 void
3911ex_finish(eap)
3912 exarg_T *eap;
3913{
3914 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3915 do_finish(eap, FALSE);
3916 else
3917 EMSG(_("E168: :finish used outside of a sourced file"));
3918}
3919
3920/*
3921 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3922 * Also called for a pending finish at the ":endtry" or after returning from
3923 * an extra do_cmdline(). "reanimate" is used in the latter case.
3924 */
3925 void
3926do_finish(eap, reanimate)
3927 exarg_T *eap;
3928 int reanimate;
3929{
3930 int idx;
3931
3932 if (reanimate)
3933 ((struct source_cookie *)getline_cookie(eap->getline,
3934 eap->cookie))->finished = FALSE;
3935
3936 /*
3937 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3938 * not in its finally clause (which then is to be executed next) is found.
3939 * In this case, make the ":finish" pending for execution at the ":endtry".
3940 * Otherwise, finish normally.
3941 */
3942 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3943 if (idx >= 0)
3944 {
3945 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3946 report_make_pending(CSTP_FINISH, NULL);
3947 }
3948 else
3949 ((struct source_cookie *)getline_cookie(eap->getline,
3950 eap->cookie))->finished = TRUE;
3951}
3952
3953
3954/*
3955 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3956 * message for missing ":endif".
3957 * Return FALSE when not sourcing a file.
3958 */
3959 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003960source_finished(fgetline, cookie)
3961 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962 void *cookie;
3963{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003964 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003966 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003967}
3968#endif
3969
3970#if defined(FEAT_LISTCMDS) || defined(PROTO)
3971/*
3972 * ":checktime [buffer]"
3973 */
3974 void
3975ex_checktime(eap)
3976 exarg_T *eap;
3977{
3978 buf_T *buf;
3979 int save_no_check_timestamps = no_check_timestamps;
3980
3981 no_check_timestamps = 0;
3982 if (eap->addr_count == 0) /* default is all buffers */
3983 check_timestamps(FALSE);
3984 else
3985 {
3986 buf = buflist_findnr((int)eap->line2);
3987 if (buf != NULL) /* cannot happen? */
3988 (void)buf_check_timestamp(buf, FALSE);
3989 }
3990 no_check_timestamps = save_no_check_timestamps;
3991}
3992#endif
3993
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
3995 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02003996# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997static char *get_locale_val __ARGS((int what));
3998
3999 static char *
4000get_locale_val(what)
4001 int what;
4002{
4003 char *loc;
4004
4005 /* Obtain the locale value from the libraries. For DJGPP this is
4006 * redefined and it doesn't use the arguments. */
4007 loc = setlocale(what, NULL);
4008
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004009# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010 if (loc != NULL)
4011 {
4012 char_u *p;
4013
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004014 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4015 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 p = vim_strchr(loc, '=');
4017 if (p != NULL)
4018 {
4019 loc = ++p;
4020 while (*p != NUL) /* remove trailing newline */
4021 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004022 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 {
4024 *p = NUL;
4025 break;
4026 }
4027 ++p;
4028 }
4029 }
4030 }
4031# endif
4032
4033 return loc;
4034}
4035#endif
4036
4037
4038#ifdef WIN32
4039/*
4040 * On MS-Windows locale names are strings like "German_Germany.1252", but
4041 * gettext expects "de". Try to translate one into another here for a few
4042 * supported languages.
4043 */
4044 static char_u *
4045gettext_lang(char_u *name)
4046{
4047 int i;
4048 static char *(mtable[]) = {
4049 "afrikaans", "af",
4050 "czech", "cs",
4051 "dutch", "nl",
4052 "german", "de",
4053 "english_united kingdom", "en_GB",
4054 "spanish", "es",
4055 "french", "fr",
4056 "italian", "it",
4057 "japanese", "ja",
4058 "korean", "ko",
4059 "norwegian", "no",
4060 "polish", "pl",
4061 "russian", "ru",
4062 "slovak", "sk",
4063 "swedish", "sv",
4064 "ukrainian", "uk",
4065 "chinese_china", "zh_CN",
4066 "chinese_taiwan", "zh_TW",
4067 NULL};
4068
4069 for (i = 0; mtable[i] != NULL; i += 2)
4070 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4071 return mtable[i + 1];
4072 return name;
4073}
4074#endif
4075
4076#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4077/*
4078 * Obtain the current messages language. Used to set the default for
4079 * 'helplang'. May return NULL or an empty string.
4080 */
4081 char_u *
4082get_mess_lang()
4083{
4084 char_u *p;
4085
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004086# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087# if defined(LC_MESSAGES)
4088 p = (char_u *)get_locale_val(LC_MESSAGES);
4089# else
4090 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004091 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4092 * and LC_MONETARY may be set differently for a Japanese working in the
4093 * US. */
4094 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095# endif
4096# else
4097 p = mch_getenv((char_u *)"LC_ALL");
4098 if (p == NULL || *p == NUL)
4099 {
4100 p = mch_getenv((char_u *)"LC_MESSAGES");
4101 if (p == NULL || *p == NUL)
4102 p = mch_getenv((char_u *)"LANG");
4103 }
4104# endif
4105# ifdef WIN32
4106 p = gettext_lang(p);
4107# endif
4108 return p;
4109}
4110#endif
4111
Bram Moolenaardef9e822004-12-31 20:58:58 +00004112/* Complicated #if; matches with where get_mess_env() is used below. */
4113#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4114 && defined(LC_MESSAGES))) \
4115 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4116 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4117 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118static char_u *get_mess_env __ARGS((void));
4119
4120/*
4121 * Get the language used for messages from the environment.
4122 */
4123 static char_u *
4124get_mess_env()
4125{
4126 char_u *p;
4127
4128 p = mch_getenv((char_u *)"LC_ALL");
4129 if (p == NULL || *p == NUL)
4130 {
4131 p = mch_getenv((char_u *)"LC_MESSAGES");
4132 if (p == NULL || *p == NUL)
4133 {
4134 p = mch_getenv((char_u *)"LANG");
4135 if (p != NULL && VIM_ISDIGIT(*p))
4136 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004137# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 if (p == NULL || *p == NUL)
4139 p = (char_u *)get_locale_val(LC_CTYPE);
4140# endif
4141 }
4142 }
4143 return p;
4144}
4145#endif
4146
4147#if defined(FEAT_EVAL) || defined(PROTO)
4148
4149/*
4150 * Set the "v:lang" variable according to the current locale setting.
4151 * Also do "v:lc_time"and "v:ctype".
4152 */
4153 void
4154set_lang_var()
4155{
4156 char_u *loc;
4157
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004158# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 loc = (char_u *)get_locale_val(LC_CTYPE);
4160# else
4161 /* setlocale() not supported: use the default value */
4162 loc = (char_u *)"C";
4163# endif
4164 set_vim_var_string(VV_CTYPE, loc, -1);
4165
4166 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4167 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004168# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 loc = (char_u *)get_locale_val(LC_MESSAGES);
4170# else
4171 loc = get_mess_env();
4172# endif
4173 set_vim_var_string(VV_LANG, loc, -1);
4174
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004175# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 loc = (char_u *)get_locale_val(LC_TIME);
4177# endif
4178 set_vim_var_string(VV_LC_TIME, loc, -1);
4179}
4180#endif
4181
4182#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4183 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4184/*
4185 * ":language": Set the language (locale).
4186 */
4187 void
4188ex_language(eap)
4189 exarg_T *eap;
4190{
4191 char *loc;
4192 char_u *p;
4193 char_u *name;
4194 int what = LC_ALL;
4195 char *whatstr = "";
4196#ifdef LC_MESSAGES
4197# define VIM_LC_MESSAGES LC_MESSAGES
4198#else
4199# define VIM_LC_MESSAGES 6789
4200#endif
4201
4202 name = eap->arg;
4203
4204 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4205 * Allow abbreviation, but require at least 3 characters to avoid
4206 * confusion with a two letter language name "me" or "ct". */
4207 p = skiptowhite(eap->arg);
4208 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4209 {
4210 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4211 {
4212 what = VIM_LC_MESSAGES;
4213 name = skipwhite(p);
4214 whatstr = "messages ";
4215 }
4216 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4217 {
4218 what = LC_CTYPE;
4219 name = skipwhite(p);
4220 whatstr = "ctype ";
4221 }
4222 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4223 {
4224 what = LC_TIME;
4225 name = skipwhite(p);
4226 whatstr = "time ";
4227 }
4228 }
4229
4230 if (*name == NUL)
4231 {
4232#ifndef LC_MESSAGES
4233 if (what == VIM_LC_MESSAGES)
4234 p = get_mess_env();
4235 else
4236#endif
4237 p = (char_u *)setlocale(what, NULL);
4238 if (p == NULL || *p == NUL)
4239 p = (char_u *)"Unknown";
4240 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4241 }
4242 else
4243 {
4244#ifndef LC_MESSAGES
4245 if (what == VIM_LC_MESSAGES)
4246 loc = "";
4247 else
4248#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004249 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004251#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4252 /* Make sure strtod() uses a decimal point, not a comma. */
4253 setlocale(LC_NUMERIC, "C");
4254#endif
4255 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256 if (loc == NULL)
4257 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4258 else
4259 {
4260#ifdef HAVE_NL_MSG_CAT_CNTR
4261 /* Need to do this for GNU gettext, otherwise cached translations
4262 * will be used again. */
4263 extern int _nl_msg_cat_cntr;
4264
4265 ++_nl_msg_cat_cntr;
4266#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004267 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4269
4270 if (what != LC_TIME)
4271 {
4272 /* Tell gettext() what to translate to. It apparently doesn't
4273 * use the currently effective locale. Also do this when
4274 * FEAT_GETTEXT isn't defined, so that shell commands use this
4275 * value. */
4276 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004277 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004279
4280 /* Clear $LANGUAGE because GNU gettext uses it. */
4281 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004282# ifdef WIN32
4283 /* Apparently MS-Windows printf() may cause a crash when
4284 * we give it 8-bit text while it's expecting text in the
4285 * current locale. This call avoids that. */
4286 setlocale(LC_CTYPE, "C");
4287# endif
4288 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 if (what != LC_CTYPE)
4290 {
4291 char_u *mname;
4292#ifdef WIN32
4293 mname = gettext_lang(name);
4294#else
4295 mname = name;
4296#endif
4297 vim_setenv((char_u *)"LC_MESSAGES", mname);
4298#ifdef FEAT_MULTI_LANG
4299 set_helplang_default(mname);
4300#endif
4301 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302 }
4303
4304# ifdef FEAT_EVAL
4305 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4306 set_lang_var();
4307# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004308# ifdef FEAT_TITLE
4309 maketitle();
4310# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311 }
4312 }
4313}
4314
4315# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004316
4317static char_u **locales = NULL; /* Array of all available locales */
4318static int did_init_locales = FALSE;
4319
4320static void init_locales __ARGS((void));
4321static char_u **find_locales __ARGS((void));
4322
4323/*
4324 * Lazy initialization of all available locales.
4325 */
4326 static void
4327init_locales()
4328{
4329 if (!did_init_locales)
4330 {
4331 did_init_locales = TRUE;
4332 locales = find_locales();
4333 }
4334}
4335
4336/* Return an array of strings for all available locales + NULL for the
4337 * last element. Return NULL in case of error. */
4338 static char_u **
4339find_locales()
4340{
4341 garray_T locales_ga;
4342 char_u *loc;
4343
4344 /* Find all available locales by running command "locale -a". If this
4345 * doesn't work we won't have completion. */
4346 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004347 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004348 if (locale_a == NULL)
4349 return NULL;
4350 ga_init2(&locales_ga, sizeof(char_u *), 20);
4351
4352 /* Transform locale_a string where each locale is separated by "\n"
4353 * into an array of locale strings. */
4354 loc = (char_u *)strtok((char *)locale_a, "\n");
4355
4356 while (loc != NULL)
4357 {
4358 if (ga_grow(&locales_ga, 1) == FAIL)
4359 break;
4360 loc = vim_strsave(loc);
4361 if (loc == NULL)
4362 break;
4363
4364 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4365 loc = (char_u *)strtok(NULL, "\n");
4366 }
4367 vim_free(locale_a);
4368 if (ga_grow(&locales_ga, 1) == FAIL)
4369 {
4370 ga_clear(&locales_ga);
4371 return NULL;
4372 }
4373 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4374 return (char_u **)locales_ga.ga_data;
4375}
4376
4377# if defined(EXITFREE) || defined(PROTO)
4378 void
4379free_locales()
4380{
4381 int i;
4382 if (locales != NULL)
4383 {
4384 for (i = 0; locales[i] != NULL; i++)
4385 vim_free(locales[i]);
4386 vim_free(locales);
4387 locales = NULL;
4388 }
4389}
4390# endif
4391
Bram Moolenaar071d4272004-06-13 20:20:40 +00004392/*
4393 * Function given to ExpandGeneric() to obtain the possible arguments of the
4394 * ":language" command.
4395 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396 char_u *
4397get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004398 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399 int idx;
4400{
4401 if (idx == 0)
4402 return (char_u *)"messages";
4403 if (idx == 1)
4404 return (char_u *)"ctype";
4405 if (idx == 2)
4406 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004407
4408 init_locales();
4409 if (locales == NULL)
4410 return NULL;
4411 return locales[idx - 3];
4412}
4413
4414/*
4415 * Function given to ExpandGeneric() to obtain the available locales.
4416 */
4417 char_u *
4418get_locales(xp, idx)
4419 expand_T *xp UNUSED;
4420 int idx;
4421{
4422 init_locales();
4423 if (locales == NULL)
4424 return NULL;
4425 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426}
4427# endif
4428
4429#endif