blob: 48badeb93fbcfbf4f29acc46bff37881ef8da7be [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 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002476 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477#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
Bram Moolenaara162bc52015-01-07 16:54:21 +01002481 switch (eap->cmdidx)
2482 {
2483#ifdef FEAT_WINDOWS
2484 case CMD_windo:
2485 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2486 i++;
2487 break;
2488 case CMD_tabdo:
2489 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2490 i++;
2491 break;
2492#endif
2493 case CMD_argdo:
2494 i = eap->line1 - 1;
2495 break;
2496 case CMD_bufdo:
2497 i = eap->line1;
2498 break;
2499 default:
2500 break;
2501 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 /* set pcmark now */
2503 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaara162bc52015-01-07 16:54:21 +01002504 goto_buffer(eap, DOBUF_FIRST, FORWARD, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505 else
2506 setpcmark();
2507 listcmd_busy = TRUE; /* avoids setting pcmark below */
2508
2509 while (!got_int)
2510 {
2511 if (eap->cmdidx == CMD_argdo)
2512 {
2513 /* go to argument "i" */
2514 if (i == ARGCOUNT)
2515 break;
2516 /* Don't call do_argfile() when already there, it will try
2517 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002518 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002519 {
2520 /* Clear 'shm' to avoid that the file message overwrites
2521 * any output from the command. */
2522 p_shm_save = vim_strsave(p_shm);
2523 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002524 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002525 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2526 vim_free(p_shm_save);
2527 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528 if (curwin->w_arg_idx != i)
2529 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530 }
2531#ifdef FEAT_WINDOWS
2532 else if (eap->cmdidx == CMD_windo)
2533 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002534 /* go to window "wp" */
2535 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002537 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002538 if (curwin != wp)
2539 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002540 wp = curwin->w_next;
2541 }
2542 else if (eap->cmdidx == CMD_tabdo)
2543 {
2544 /* go to window "tp" */
2545 if (!valid_tabpage(tp))
2546 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002547 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002548 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002549 }
2550#endif
2551 else if (eap->cmdidx == CMD_bufdo)
2552 {
2553 /* Remember the number of the next listed buffer, in case
2554 * ":bwipe" is used or autocommands do something strange. */
2555 next_fnum = -1;
2556 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2557 if (buf->b_p_bl)
2558 {
2559 next_fnum = buf->b_fnum;
2560 break;
2561 }
2562 }
2563
Bram Moolenaara162bc52015-01-07 16:54:21 +01002564 ++i;
2565
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 /* execute the command */
2567 do_cmdline(eap->arg, eap->getline, eap->cookie,
2568 DOCMD_VERBOSE + DOCMD_NOWAIT);
2569
2570 if (eap->cmdidx == CMD_bufdo)
2571 {
2572 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002573 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 break;
2575 /* Check if the buffer still exists. */
2576 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2577 if (buf->b_fnum == next_fnum)
2578 break;
2579 if (buf == NULL)
2580 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002581
2582 /* Go to the next buffer. Clear 'shm' to avoid that the file
2583 * message overwrites any output from the command. */
2584 p_shm_save = vim_strsave(p_shm);
2585 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002587 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2588 vim_free(p_shm_save);
2589
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 /* If autocommands took us elsewhere, quit here */
2591 if (curbuf->b_fnum != next_fnum)
2592 break;
2593 }
2594
2595 if (eap->cmdidx == CMD_windo)
2596 {
2597 validate_cursor(); /* cursor may have moved */
2598#ifdef FEAT_SCROLLBIND
2599 /* required when 'scrollbind' has been set */
2600 if (curwin->w_p_scb)
2601 do_check_scrollbind(TRUE);
2602#endif
2603 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002604
2605#ifdef FEAT_WINDOWS
2606 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2607 if (i+1 > eap->line2)
2608 break;
2609#endif
2610 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2611 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002612 }
2613 listcmd_busy = FALSE;
2614 }
2615
2616#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002617 if (save_ei != NULL)
2618 {
2619 au_event_restore(save_ei);
2620 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2621 curbuf->b_fname, TRUE, curbuf);
2622 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002624#ifdef FEAT_CLIPBOARD
2625 end_global_changes();
2626#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002627}
2628
2629/*
2630 * Add files[count] to the arglist of the current window after arg "after".
2631 * The file names in files[count] must have been allocated and are taken over.
2632 * Files[] itself is not taken over.
2633 * Returns index of first added argument. Returns -1 when failed (out of mem).
2634 */
2635 static int
2636alist_add_list(count, files, after)
2637 int count;
2638 char_u **files;
2639 int after; /* where to add: 0 = before first one */
2640{
2641 int i;
2642
2643 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2644 {
2645 if (after < 0)
2646 after = 0;
2647 if (after > ARGCOUNT)
2648 after = ARGCOUNT;
2649 if (after < ARGCOUNT)
2650 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2651 (ARGCOUNT - after) * sizeof(aentry_T));
2652 for (i = 0; i < count; ++i)
2653 {
2654 ARGLIST[after + i].ae_fname = files[i];
2655 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2656 }
2657 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002658 if (curwin->w_arg_idx >= after)
2659 ++curwin->w_arg_idx;
2660 return after;
2661 }
2662
2663 for (i = 0; i < count; ++i)
2664 vim_free(files[i]);
2665 return -1;
2666}
2667
2668#endif /* FEAT_LISTCMDS */
2669
2670#ifdef FEAT_EVAL
2671/*
2672 * ":compiler[!] {name}"
2673 */
2674 void
2675ex_compiler(eap)
2676 exarg_T *eap;
2677{
2678 char_u *buf;
2679 char_u *old_cur_comp = NULL;
2680 char_u *p;
2681
2682 if (*eap->arg == NUL)
2683 {
2684 /* List all compiler scripts. */
2685 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2686 /* ) keep the indenter happy... */
2687 }
2688 else
2689 {
2690 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2691 if (buf != NULL)
2692 {
2693 if (eap->forceit)
2694 {
2695 /* ":compiler! {name}" sets global options */
2696 do_cmdline_cmd((char_u *)
2697 "command -nargs=* CompilerSet set <args>");
2698 }
2699 else
2700 {
2701 /* ":compiler! {name}" sets local options.
2702 * To remain backwards compatible "current_compiler" is always
2703 * used. A user's compiler plugin may set it, the distributed
2704 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002705 * "b:current_compiler" and restore "current_compiler".
2706 * Explicitly prepend "g:" to make it work in a function. */
2707 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 if (old_cur_comp != NULL)
2709 old_cur_comp = vim_strsave(old_cur_comp);
2710 do_cmdline_cmd((char_u *)
2711 "command -nargs=* CompilerSet setlocal <args>");
2712 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002713 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002714 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715
2716 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002717 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2719 vim_free(buf);
2720
2721 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2722
2723 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002724 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 if (p != NULL)
2726 set_internal_string_var((char_u *)"b:current_compiler", p);
2727
2728 /* Restore "current_compiler" for ":compiler {name}". */
2729 if (!eap->forceit)
2730 {
2731 if (old_cur_comp != NULL)
2732 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002733 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002734 old_cur_comp);
2735 vim_free(old_cur_comp);
2736 }
2737 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002738 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 }
2740 }
2741 }
2742}
2743#endif
2744
2745/*
2746 * ":runtime {name}"
2747 */
2748 void
2749ex_runtime(eap)
2750 exarg_T *eap;
2751{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002752 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753}
2754
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002755static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756
2757 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002758source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002760 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002762 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763}
2764
2765/*
2766 * Source the file "name" from all directories in 'runtimepath'.
2767 * "name" can contain wildcards.
2768 * When "all" is TRUE, source all files, otherwise only the first one.
2769 * return FAIL when no file could be sourced, OK otherwise.
2770 */
2771 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002772source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773 char_u *name;
2774 int all;
2775{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002776 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777}
2778
2779/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002780 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2781 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2783 * used.
2784 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002785 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002786 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2787 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002788 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002789 */
2790 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002791do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 char_u *name;
2793 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002794 void (*callback)__ARGS((char_u *fname, void *ck));
2795 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002796{
2797 char_u *rtp;
2798 char_u *np;
2799 char_u *buf;
2800 char_u *rtp_copy;
2801 char_u *tail;
2802 int num_files;
2803 char_u **files;
2804 int i;
2805 int did_one = FALSE;
2806#ifdef AMIGA
2807 struct Process *proc = (struct Process *)FindTask(0L);
2808 APTR save_winptr = proc->pr_WindowPtr;
2809
2810 /* Avoid a requester here for a volume that doesn't exist. */
2811 proc->pr_WindowPtr = (APTR)-1L;
2812#endif
2813
2814 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2815 * value. */
2816 rtp_copy = vim_strsave(p_rtp);
2817 buf = alloc(MAXPATHL);
2818 if (buf != NULL && rtp_copy != NULL)
2819 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002820 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002821 {
2822 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002823 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002825 verbose_leave();
2826 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002827
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 /* Loop over all entries in 'runtimepath'. */
2829 rtp = rtp_copy;
2830 while (*rtp != NUL && (all || !did_one))
2831 {
2832 /* Copy the path from 'runtimepath' to buf[]. */
2833 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002834 if (name == NULL)
2835 {
2836 (*callback)(buf, (void *) &cookie);
2837 if (!did_one)
2838 did_one = (cookie == NULL);
2839 }
2840 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 {
2842 add_pathsep(buf);
2843 tail = buf + STRLEN(buf);
2844
2845 /* Loop over all patterns in "name" */
2846 np = name;
2847 while (*np != NUL && (all || !did_one))
2848 {
2849 /* Append the pattern from "name" to buf[]. */
2850 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2851 "\t ");
2852
2853 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002854 {
2855 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002856 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002857 verbose_leave();
2858 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859
2860 /* Expand wildcards, invoke the callback for each match. */
2861 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2862 EW_FILE) == OK)
2863 {
2864 for (i = 0; i < num_files; ++i)
2865 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002866 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867 did_one = TRUE;
2868 if (!all)
2869 break;
2870 }
2871 FreeWild(num_files, files);
2872 }
2873 }
2874 }
2875 }
2876 }
2877 vim_free(buf);
2878 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002879 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002880 {
2881 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002882 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002883 verbose_leave();
2884 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002885
2886#ifdef AMIGA
2887 proc->pr_WindowPtr = save_winptr;
2888#endif
2889
2890 return did_one ? OK : FAIL;
2891}
2892
2893#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2894/*
2895 * ":options"
2896 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 void
2898ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002899 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900{
2901 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2902}
2903#endif
2904
2905/*
2906 * ":source {fname}"
2907 */
2908 void
2909ex_source(eap)
2910 exarg_T *eap;
2911{
2912#ifdef FEAT_BROWSE
2913 if (cmdmod.browse)
2914 {
2915 char_u *fname = NULL;
2916
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002917 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2919 if (fname != NULL)
2920 {
2921 cmd_source(fname, eap);
2922 vim_free(fname);
2923 }
2924 }
2925 else
2926#endif
2927 cmd_source(eap->arg, eap);
2928}
2929
2930 static void
2931cmd_source(fname, eap)
2932 char_u *fname;
2933 exarg_T *eap;
2934{
2935 if (*fname == NUL)
2936 EMSG(_(e_argreq));
2937
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002939 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002940 * Need to execute the commands directly. This is required at least
2941 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 * - ":g" command busy
2943 * - after ":argdo", ":windo" or ":bufdo"
2944 * - another command follows
2945 * - inside a loop
2946 */
2947 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2948#ifdef FEAT_EVAL
2949 || eap->cstack->cs_idx >= 0
2950#endif
2951 );
2952
2953 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002954 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955 EMSG2(_(e_notopen), fname);
2956}
2957
2958/*
2959 * ":source" and associated commands.
2960 */
2961/*
2962 * Structure used to store info for each sourced file.
2963 * It is shared between do_source() and getsourceline().
2964 * This is required, because it needs to be handed to do_cmdline() and
2965 * sourcing can be done recursively.
2966 */
2967struct source_cookie
2968{
2969 FILE *fp; /* opened file for sourcing */
2970 char_u *nextline; /* if not NULL: line that was read ahead */
2971 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002972#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2974 int error; /* TRUE if LF found after CR-LF */
2975#endif
2976#ifdef FEAT_EVAL
2977 linenr_T breakpoint; /* next line with breakpoint or zero */
2978 char_u *fname; /* name of sourced file */
2979 int dbg_tick; /* debug_tick when breakpoint was set */
2980 int level; /* top nesting level of sourced file */
2981#endif
2982#ifdef FEAT_MBYTE
2983 vimconv_T conv; /* type of conversion */
2984#endif
2985};
2986
2987#ifdef FEAT_EVAL
2988/*
2989 * Return the address holding the next breakpoint line for a source cookie.
2990 */
2991 linenr_T *
2992source_breakpoint(cookie)
2993 void *cookie;
2994{
2995 return &((struct source_cookie *)cookie)->breakpoint;
2996}
2997
2998/*
2999 * Return the address holding the debug tick for a source cookie.
3000 */
3001 int *
3002source_dbg_tick(cookie)
3003 void *cookie;
3004{
3005 return &((struct source_cookie *)cookie)->dbg_tick;
3006}
3007
3008/*
3009 * Return the nesting level for a source cookie.
3010 */
3011 int
3012source_level(cookie)
3013 void *cookie;
3014{
3015 return ((struct source_cookie *)cookie)->level;
3016}
3017#endif
3018
3019static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3020
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003021#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3022# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003023static FILE *fopen_noinh_readbin __ARGS((char *filename));
3024
3025/*
3026 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003027 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 */
3029 static FILE *
3030fopen_noinh_readbin(filename)
3031 char *filename;
3032{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003033# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003034 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3035# else
3036 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003037# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038
3039 if (fd_tmp == -1)
3040 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003041
3042# ifdef HAVE_FD_CLOEXEC
3043 {
3044 int fdflags = fcntl(fd_tmp, F_GETFD);
3045 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
3046 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
3047 }
3048# endif
3049
Bram Moolenaar071d4272004-06-13 20:20:40 +00003050 return fdopen(fd_tmp, READBIN);
3051}
3052#endif
3053
3054
3055/*
3056 * do_source: Read the file "fname" and execute its lines as EX commands.
3057 *
3058 * This function may be called recursively!
3059 *
3060 * return FAIL if file could not be opened, OK otherwise
3061 */
3062 int
3063do_source(fname, check_other, is_vimrc)
3064 char_u *fname;
3065 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003066 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067{
3068 struct source_cookie cookie;
3069 char_u *save_sourcing_name;
3070 linenr_T save_sourcing_lnum;
3071 char_u *p;
3072 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003073 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074 int retval = FAIL;
3075#ifdef FEAT_EVAL
3076 scid_T save_current_SID;
3077 static scid_T last_current_SID = 0;
3078 void *save_funccalp;
3079 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003080 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081# ifdef UNIX
3082 struct stat st;
3083 int stat_ok;
3084# endif
3085#endif
3086#ifdef STARTUPTIME
3087 struct timeval tv_rel;
3088 struct timeval tv_start;
3089#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003090#ifdef FEAT_PROFILE
3091 proftime_T wait_start;
3092#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095 if (p == NULL)
3096 return retval;
3097 fname_exp = fix_fname(p);
3098 vim_free(p);
3099 if (fname_exp == NULL)
3100 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 if (mch_isdir(fname_exp))
3102 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003103 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003104 goto theend;
3105 }
3106
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003107#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003108 /* Apply SourceCmd autocommands, they should get the file and source it. */
3109 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3110 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3111 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003112 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003113# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003114 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003115# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003116 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003117# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003118 goto theend;
3119 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003120
3121 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003122 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3123#endif
3124
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003125#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3127#else
3128 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3129#endif
3130 if (cookie.fp == NULL && check_other)
3131 {
3132 /*
3133 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3134 * and ".exrc" by "_exrc" or vice versa.
3135 */
3136 p = gettail(fname_exp);
3137 if ((*p == '.' || *p == '_')
3138 && (STRICMP(p + 1, "vimrc") == 0
3139 || STRICMP(p + 1, "gvimrc") == 0
3140 || STRICMP(p + 1, "exrc") == 0))
3141 {
3142 if (*p == '_')
3143 *p = '.';
3144 else
3145 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003146#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3148#else
3149 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3150#endif
3151 }
3152 }
3153
3154 if (cookie.fp == NULL)
3155 {
3156 if (p_verbose > 0)
3157 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003158 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003160 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161 else
3162 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003163 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003164 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165 }
3166 goto theend;
3167 }
3168
3169 /*
3170 * The file exists.
3171 * - In verbose mode, give a message.
3172 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3173 */
3174 if (p_verbose > 1)
3175 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003176 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003177 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003178 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 else
3180 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003181 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003182 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003184 if (is_vimrc == DOSO_VIMRC)
3185 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3186 else if (is_vimrc == DOSO_GVIMRC)
3187 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188
3189#ifdef USE_CRNL
3190 /* If no automatic file format: Set default to CR-NL. */
3191 if (*p_ffs == NUL)
3192 cookie.fileformat = EOL_DOS;
3193 else
3194 cookie.fileformat = EOL_UNKNOWN;
3195 cookie.error = FALSE;
3196#endif
3197
3198#ifdef USE_CR
3199 /* If no automatic file format: Set default to CR. */
3200 if (*p_ffs == NUL)
3201 cookie.fileformat = EOL_MAC;
3202 else
3203 cookie.fileformat = EOL_UNKNOWN;
3204 cookie.error = FALSE;
3205#endif
3206
3207 cookie.nextline = NULL;
3208 cookie.finished = FALSE;
3209
3210#ifdef FEAT_EVAL
3211 /*
3212 * Check if this script has a breakpoint.
3213 */
3214 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3215 cookie.fname = fname_exp;
3216 cookie.dbg_tick = debug_tick;
3217
3218 cookie.level = ex_nesting_level;
3219#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220
3221 /*
3222 * Keep the sourcing name/lnum, for recursive calls.
3223 */
3224 save_sourcing_name = sourcing_name;
3225 sourcing_name = fname_exp;
3226 save_sourcing_lnum = sourcing_lnum;
3227 sourcing_lnum = 0;
3228
Bram Moolenaar73881402009-02-04 16:50:47 +00003229#ifdef FEAT_MBYTE
3230 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3231
3232 /* Read the first line so we can check for a UTF-8 BOM. */
3233 firstline = getsourceline(0, (void *)&cookie, 0);
3234 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3235 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3236 {
3237 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3238 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3239 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003240 if (p == NULL)
3241 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003242 if (p != NULL)
3243 {
3244 vim_free(firstline);
3245 firstline = p;
3246 }
3247 }
3248#endif
3249
Bram Moolenaar071d4272004-06-13 20:20:40 +00003250#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003251 if (time_fd != NULL)
3252 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003253#endif
3254
3255#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003256# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003257 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003258 prof_child_enter(&wait_start); /* entering a child now */
3259# endif
3260
3261 /* Don't use local function variables, if called from a function.
3262 * Also starts profiling timer for nested script. */
3263 save_funccalp = save_funccal();
3264
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 /*
3266 * Check if this script was sourced before to finds its SID.
3267 * If it's new, generate a new SID.
3268 */
3269 save_current_SID = current_SID;
3270# ifdef UNIX
3271 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3272# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003273 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3274 {
3275 si = &SCRIPT_ITEM(current_SID);
3276 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003277 && (
3278# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003279 /* Compare dev/ino when possible, it catches symbolic
3280 * links. Also compare file names, the inode may change
3281 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003282 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003283 && (si->sn_dev == st.st_dev
3284 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003286 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003288 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 if (current_SID == 0)
3290 {
3291 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003292 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3293 == FAIL)
3294 goto almosttheend;
3295 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003297 ++script_items.ga_len;
3298 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3299# ifdef FEAT_PROFILE
3300 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003303 si = &SCRIPT_ITEM(current_SID);
3304 si->sn_name = fname_exp;
3305 fname_exp = NULL;
3306# ifdef UNIX
3307 if (stat_ok)
3308 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003309 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003310 si->sn_dev = st.st_dev;
3311 si->sn_ino = st.st_ino;
3312 }
3313 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003314 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003315# endif
3316
Bram Moolenaar071d4272004-06-13 20:20:40 +00003317 /* Allocate the local script variables to use for this script. */
3318 new_script_vars(current_SID);
3319 }
3320
Bram Moolenaar05159a02005-02-26 23:04:13 +00003321# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003322 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003323 {
3324 int forceit;
3325
3326 /* Check if we do profiling for this script. */
3327 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3328 {
3329 script_do_profile(si);
3330 si->sn_pr_force = forceit;
3331 }
3332 if (si->sn_prof_on)
3333 {
3334 ++si->sn_pr_count;
3335 profile_start(&si->sn_pr_start);
3336 profile_zero(&si->sn_pr_children);
3337 }
3338 }
3339# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340#endif
3341
3342 /*
3343 * Call do_cmdline, which will call getsourceline() to get the lines.
3344 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003345 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003347 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003348
3349#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003350 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003351 {
3352 /* Get "si" again, "script_items" may have been reallocated. */
3353 si = &SCRIPT_ITEM(current_SID);
3354 if (si->sn_prof_on)
3355 {
3356 profile_end(&si->sn_pr_start);
3357 profile_sub_wait(&wait_start, &si->sn_pr_start);
3358 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003359 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3360 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003361 }
3362 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363#endif
3364
3365 if (got_int)
3366 EMSG(_(e_interr));
3367 sourcing_name = save_sourcing_name;
3368 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369 if (p_verbose > 1)
3370 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003371 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003372 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003374 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003375 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 }
3377#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003378 if (time_fd != NULL)
3379 {
3380 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3381 time_msg((char *)IObuff, &tv_start);
3382 time_pop(&tv_rel);
3383 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384#endif
3385
3386#ifdef FEAT_EVAL
3387 /*
3388 * After a "finish" in debug mode, need to break at first command of next
3389 * sourced file.
3390 */
3391 if (save_debug_break_level > ex_nesting_level
3392 && debug_break_level == ex_nesting_level)
3393 ++debug_break_level;
3394#endif
3395
Bram Moolenaar05159a02005-02-26 23:04:13 +00003396#ifdef FEAT_EVAL
3397almosttheend:
3398 current_SID = save_current_SID;
3399 restore_funccal(save_funccalp);
3400# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003401 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003402 prof_child_exit(&wait_start); /* leaving a child now */
3403# endif
3404#endif
3405 fclose(cookie.fp);
3406 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003407 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003408#ifdef FEAT_MBYTE
3409 convert_setup(&cookie.conv, NULL, NULL);
3410#endif
3411
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412theend:
3413 vim_free(fname_exp);
3414 return retval;
3415}
3416
3417#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003418
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419/*
3420 * ":scriptnames"
3421 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422 void
3423ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003424 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425{
3426 int i;
3427
Bram Moolenaar05159a02005-02-26 23:04:13 +00003428 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3429 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003430 {
3431 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3432 NameBuff, MAXPATHL, TRUE);
3433 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003434 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435}
3436
3437# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3438/*
3439 * Fix slashes in the list of script names for 'shellslash'.
3440 */
3441 void
3442scriptnames_slash_adjust()
3443{
3444 int i;
3445
Bram Moolenaar05159a02005-02-26 23:04:13 +00003446 for (i = 1; i <= script_items.ga_len; ++i)
3447 if (SCRIPT_ITEM(i).sn_name != NULL)
3448 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003449}
3450# endif
3451
3452/*
3453 * Get a pointer to a script name. Used for ":verbose set".
3454 */
3455 char_u *
3456get_scriptname(id)
3457 scid_T id;
3458{
3459 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003460 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003462 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003463 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003464 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003466 return (char_u *)_("environment variable");
3467 if (id == SID_ERROR)
3468 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003469 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003471
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003472# if defined(EXITFREE) || defined(PROTO)
3473 void
3474free_scriptnames()
3475{
3476 int i;
3477
3478 for (i = script_items.ga_len; i > 0; --i)
3479 vim_free(SCRIPT_ITEM(i).sn_name);
3480 ga_clear(&script_items);
3481}
3482# endif
3483
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484#endif
3485
3486#if defined(USE_CR) || defined(PROTO)
3487
3488# if defined(__MSL__) && (__MSL__ >= 22)
3489/*
3490 * Newer version of the Metrowerks library handle DOS and UNIX files
3491 * without help.
3492 * Test with earlier versions, MSL 2.2 is the library supplied with
3493 * Codewarrior Pro 2.
3494 */
3495 char *
3496fgets_cr(s, n, stream)
3497 char *s;
3498 int n;
3499 FILE *stream;
3500{
3501 return fgets(s, n, stream);
3502}
3503# else
3504/*
3505 * Version of fgets() which also works for lines ending in a <CR> only
3506 * (Macintosh format).
3507 * For older versions of the Metrowerks library.
3508 * At least CodeWarrior 9 needed this code.
3509 */
3510 char *
3511fgets_cr(s, n, stream)
3512 char *s;
3513 int n;
3514 FILE *stream;
3515{
3516 int c = 0;
3517 int char_read = 0;
3518
3519 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3520 {
3521 c = fgetc(stream);
3522 s[char_read++] = c;
3523 /* If the file is in DOS format, we need to skip a NL after a CR. I
3524 * thought it was the other way around, but this appears to work... */
3525 if (c == '\n')
3526 {
3527 c = fgetc(stream);
3528 if (c != '\r')
3529 ungetc(c, stream);
3530 }
3531 }
3532
3533 s[char_read] = 0;
3534 if (char_read == 0)
3535 return NULL;
3536
3537 if (feof(stream) && char_read == 1)
3538 return NULL;
3539
3540 return s;
3541}
3542# endif
3543#endif
3544
3545/*
3546 * Get one full line from a sourced file.
3547 * Called by do_cmdline() when it's called from do_source().
3548 *
3549 * Return a pointer to the line in allocated memory.
3550 * Return NULL for end-of-file or some error.
3551 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 char_u *
3553getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003554 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003556 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557{
3558 struct source_cookie *sp = (struct source_cookie *)cookie;
3559 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003560 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003561
3562#ifdef FEAT_EVAL
3563 /* If breakpoints have been added/deleted need to check for it. */
3564 if (sp->dbg_tick < debug_tick)
3565 {
3566 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3567 sp->dbg_tick = debug_tick;
3568 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003569# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003570 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003571 script_line_end();
3572# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573#endif
3574 /*
3575 * Get current line. If there is a read-ahead line, use it, otherwise get
3576 * one now.
3577 */
3578 if (sp->finished)
3579 line = NULL;
3580 else if (sp->nextline == NULL)
3581 line = get_one_sourceline(sp);
3582 else
3583 {
3584 line = sp->nextline;
3585 sp->nextline = NULL;
3586 ++sourcing_lnum;
3587 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003588#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003589 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003590 script_line_start();
3591#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003592
3593 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3594 * contain the 'C' flag. */
3595 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3596 {
3597 /* compensate for the one line read-ahead */
3598 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003599
3600 /* Get the next line and concatenate it when it starts with a
3601 * backslash. We always need to read the next line, keep it in
3602 * sp->nextline. */
3603 sp->nextline = get_one_sourceline(sp);
3604 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003606 garray_T ga;
3607
Bram Moolenaarb549a732012-02-22 18:29:33 +01003608 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003609 ga_concat(&ga, line);
3610 ga_concat(&ga, p + 1);
3611 for (;;)
3612 {
3613 vim_free(sp->nextline);
3614 sp->nextline = get_one_sourceline(sp);
3615 if (sp->nextline == NULL)
3616 break;
3617 p = skipwhite(sp->nextline);
3618 if (*p != '\\')
3619 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003620 /* Adjust the growsize to the current length to speed up
3621 * concatenating many lines. */
3622 if (ga.ga_len > 400)
3623 {
3624 if (ga.ga_len > 8000)
3625 ga.ga_growsize = 8000;
3626 else
3627 ga.ga_growsize = ga.ga_len;
3628 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003629 ga_concat(&ga, p + 1);
3630 }
3631 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003633 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 }
3635 }
3636
3637#ifdef FEAT_MBYTE
3638 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3639 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003640 char_u *s;
3641
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642 /* Convert the encoding of the script line. */
3643 s = string_convert(&sp->conv, line, NULL);
3644 if (s != NULL)
3645 {
3646 vim_free(line);
3647 line = s;
3648 }
3649 }
3650#endif
3651
3652#ifdef FEAT_EVAL
3653 /* Did we encounter a breakpoint? */
3654 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3655 {
3656 dbg_breakpoint(sp->fname, sourcing_lnum);
3657 /* Find next breakpoint. */
3658 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3659 sp->dbg_tick = debug_tick;
3660 }
3661#endif
3662
3663 return line;
3664}
3665
3666 static char_u *
3667get_one_sourceline(sp)
3668 struct source_cookie *sp;
3669{
3670 garray_T ga;
3671 int len;
3672 int c;
3673 char_u *buf;
3674#ifdef USE_CRNL
3675 int has_cr; /* CR-LF found */
3676#endif
3677#ifdef USE_CR
3678 char_u *scan;
3679#endif
3680 int have_read = FALSE;
3681
3682 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003683 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684
3685 /*
3686 * Loop until there is a finished line (or end-of-file).
3687 */
3688 sourcing_lnum++;
3689 for (;;)
3690 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003691 /* make room to read at least 120 (more) characters */
3692 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 break;
3694 buf = (char_u *)ga.ga_data;
3695
3696#ifdef USE_CR
3697 if (sp->fileformat == EOL_MAC)
3698 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003699 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3700 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 break;
3702 }
3703 else
3704#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003705 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3706 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003708 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709#ifdef USE_CRNL
3710 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3711 * CTRL-Z by its own, or after a NL. */
3712 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3713 && sp->fileformat == EOL_DOS
3714 && buf[len - 1] == Ctrl_Z)
3715 {
3716 buf[len - 1] = NUL;
3717 break;
3718 }
3719#endif
3720
3721#ifdef USE_CR
3722 /* If the read doesn't stop on a new line, and there's
3723 * some CR then we assume a Mac format */
3724 if (sp->fileformat == EOL_UNKNOWN)
3725 {
3726 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3727 sp->fileformat = EOL_MAC;
3728 else
3729 sp->fileformat = EOL_UNIX;
3730 }
3731
3732 if (sp->fileformat == EOL_MAC)
3733 {
3734 scan = vim_strchr(buf, '\r');
3735
3736 if (scan != NULL)
3737 {
3738 *scan = '\n';
3739 if (*(scan + 1) != 0)
3740 {
3741 *(scan + 1) = 0;
3742 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3743 }
3744 }
3745 len = STRLEN(buf);
3746 }
3747#endif
3748
3749 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003750 ga.ga_len = len;
3751
3752 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003753 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 continue;
3755
3756 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3757 {
3758#ifdef USE_CRNL
3759 has_cr = (len >= 2 && buf[len - 2] == '\r');
3760 if (sp->fileformat == EOL_UNKNOWN)
3761 {
3762 if (has_cr)
3763 sp->fileformat = EOL_DOS;
3764 else
3765 sp->fileformat = EOL_UNIX;
3766 }
3767
3768 if (sp->fileformat == EOL_DOS)
3769 {
3770 if (has_cr) /* replace trailing CR */
3771 {
3772 buf[len - 2] = '\n';
3773 --len;
3774 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775 }
3776 else /* lines like ":map xx yy^M" will have failed */
3777 {
3778 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003779 {
3780 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003781 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003782 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783 sp->error = TRUE;
3784 sp->fileformat = EOL_UNIX;
3785 }
3786 }
3787#endif
3788 /* The '\n' is escaped if there is an odd number of ^V's just
3789 * before it, first set "c" just before the 'V's and then check
3790 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3791 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3792 ;
3793 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3794 {
3795 sourcing_lnum++;
3796 continue;
3797 }
3798
3799 buf[len - 1] = NUL; /* remove the NL */
3800 }
3801
3802 /*
3803 * Check for ^C here now and then, so recursive :so can be broken.
3804 */
3805 line_breakcheck();
3806 break;
3807 }
3808
3809 if (have_read)
3810 return (char_u *)ga.ga_data;
3811
3812 vim_free(ga.ga_data);
3813 return NULL;
3814}
3815
Bram Moolenaar05159a02005-02-26 23:04:13 +00003816#if defined(FEAT_PROFILE) || defined(PROTO)
3817/*
3818 * Called when starting to read a script line.
3819 * "sourcing_lnum" must be correct!
3820 * When skipping lines it may not actually be executed, but we won't find out
3821 * until later and we need to store the time now.
3822 */
3823 void
3824script_line_start()
3825{
3826 scriptitem_T *si;
3827 sn_prl_T *pp;
3828
3829 if (current_SID <= 0 || current_SID > script_items.ga_len)
3830 return;
3831 si = &SCRIPT_ITEM(current_SID);
3832 if (si->sn_prof_on && sourcing_lnum >= 1)
3833 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003834 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003835 * here isn't counted. */
3836 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3837 si->sn_prl_idx = sourcing_lnum - 1;
3838 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3839 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3840 {
3841 /* Zero counters for a line that was not used before. */
3842 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3843 pp->snp_count = 0;
3844 profile_zero(&pp->sn_prl_total);
3845 profile_zero(&pp->sn_prl_self);
3846 ++si->sn_prl_ga.ga_len;
3847 }
3848 si->sn_prl_execed = FALSE;
3849 profile_start(&si->sn_prl_start);
3850 profile_zero(&si->sn_prl_children);
3851 profile_get_wait(&si->sn_prl_wait);
3852 }
3853}
3854
3855/*
3856 * Called when actually executing a function line.
3857 */
3858 void
3859script_line_exec()
3860{
3861 scriptitem_T *si;
3862
3863 if (current_SID <= 0 || current_SID > script_items.ga_len)
3864 return;
3865 si = &SCRIPT_ITEM(current_SID);
3866 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3867 si->sn_prl_execed = TRUE;
3868}
3869
3870/*
3871 * Called when done with a function line.
3872 */
3873 void
3874script_line_end()
3875{
3876 scriptitem_T *si;
3877 sn_prl_T *pp;
3878
3879 if (current_SID <= 0 || current_SID > script_items.ga_len)
3880 return;
3881 si = &SCRIPT_ITEM(current_SID);
3882 if (si->sn_prof_on && si->sn_prl_idx >= 0
3883 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3884 {
3885 if (si->sn_prl_execed)
3886 {
3887 pp = &PRL_ITEM(si, si->sn_prl_idx);
3888 ++pp->snp_count;
3889 profile_end(&si->sn_prl_start);
3890 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003891 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003892 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3893 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003894 }
3895 si->sn_prl_idx = -1;
3896 }
3897}
3898#endif
3899
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900/*
3901 * ":scriptencoding": Set encoding conversion for a sourced script.
3902 * Without the multi-byte feature it's simply ignored.
3903 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 void
3905ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003906 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003907{
3908#ifdef FEAT_MBYTE
3909 struct source_cookie *sp;
3910 char_u *name;
3911
3912 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3913 {
3914 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3915 return;
3916 }
3917
3918 if (*eap->arg != NUL)
3919 {
3920 name = enc_canonize(eap->arg);
3921 if (name == NULL) /* out of memory */
3922 return;
3923 }
3924 else
3925 name = eap->arg;
3926
3927 /* Setup for conversion from the specified encoding to 'encoding'. */
3928 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3929 convert_setup(&sp->conv, name, p_enc);
3930
3931 if (name != eap->arg)
3932 vim_free(name);
3933#endif
3934}
3935
3936#if defined(FEAT_EVAL) || defined(PROTO)
3937/*
3938 * ":finish": Mark a sourced file as finished.
3939 */
3940 void
3941ex_finish(eap)
3942 exarg_T *eap;
3943{
3944 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3945 do_finish(eap, FALSE);
3946 else
3947 EMSG(_("E168: :finish used outside of a sourced file"));
3948}
3949
3950/*
3951 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3952 * Also called for a pending finish at the ":endtry" or after returning from
3953 * an extra do_cmdline(). "reanimate" is used in the latter case.
3954 */
3955 void
3956do_finish(eap, reanimate)
3957 exarg_T *eap;
3958 int reanimate;
3959{
3960 int idx;
3961
3962 if (reanimate)
3963 ((struct source_cookie *)getline_cookie(eap->getline,
3964 eap->cookie))->finished = FALSE;
3965
3966 /*
3967 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3968 * not in its finally clause (which then is to be executed next) is found.
3969 * In this case, make the ":finish" pending for execution at the ":endtry".
3970 * Otherwise, finish normally.
3971 */
3972 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3973 if (idx >= 0)
3974 {
3975 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3976 report_make_pending(CSTP_FINISH, NULL);
3977 }
3978 else
3979 ((struct source_cookie *)getline_cookie(eap->getline,
3980 eap->cookie))->finished = TRUE;
3981}
3982
3983
3984/*
3985 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3986 * message for missing ":endif".
3987 * Return FALSE when not sourcing a file.
3988 */
3989 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003990source_finished(fgetline, cookie)
3991 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992 void *cookie;
3993{
Bram Moolenaar89d40322006-08-29 15:30:07 +00003994 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00003996 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997}
3998#endif
3999
4000#if defined(FEAT_LISTCMDS) || defined(PROTO)
4001/*
4002 * ":checktime [buffer]"
4003 */
4004 void
4005ex_checktime(eap)
4006 exarg_T *eap;
4007{
4008 buf_T *buf;
4009 int save_no_check_timestamps = no_check_timestamps;
4010
4011 no_check_timestamps = 0;
4012 if (eap->addr_count == 0) /* default is all buffers */
4013 check_timestamps(FALSE);
4014 else
4015 {
4016 buf = buflist_findnr((int)eap->line2);
4017 if (buf != NULL) /* cannot happen? */
4018 (void)buf_check_timestamp(buf, FALSE);
4019 }
4020 no_check_timestamps = save_no_check_timestamps;
4021}
4022#endif
4023
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4025 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004026# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027static char *get_locale_val __ARGS((int what));
4028
4029 static char *
4030get_locale_val(what)
4031 int what;
4032{
4033 char *loc;
4034
4035 /* Obtain the locale value from the libraries. For DJGPP this is
4036 * redefined and it doesn't use the arguments. */
4037 loc = setlocale(what, NULL);
4038
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004039# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040 if (loc != NULL)
4041 {
4042 char_u *p;
4043
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004044 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4045 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 p = vim_strchr(loc, '=');
4047 if (p != NULL)
4048 {
4049 loc = ++p;
4050 while (*p != NUL) /* remove trailing newline */
4051 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004052 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053 {
4054 *p = NUL;
4055 break;
4056 }
4057 ++p;
4058 }
4059 }
4060 }
4061# endif
4062
4063 return loc;
4064}
4065#endif
4066
4067
4068#ifdef WIN32
4069/*
4070 * On MS-Windows locale names are strings like "German_Germany.1252", but
4071 * gettext expects "de". Try to translate one into another here for a few
4072 * supported languages.
4073 */
4074 static char_u *
4075gettext_lang(char_u *name)
4076{
4077 int i;
4078 static char *(mtable[]) = {
4079 "afrikaans", "af",
4080 "czech", "cs",
4081 "dutch", "nl",
4082 "german", "de",
4083 "english_united kingdom", "en_GB",
4084 "spanish", "es",
4085 "french", "fr",
4086 "italian", "it",
4087 "japanese", "ja",
4088 "korean", "ko",
4089 "norwegian", "no",
4090 "polish", "pl",
4091 "russian", "ru",
4092 "slovak", "sk",
4093 "swedish", "sv",
4094 "ukrainian", "uk",
4095 "chinese_china", "zh_CN",
4096 "chinese_taiwan", "zh_TW",
4097 NULL};
4098
4099 for (i = 0; mtable[i] != NULL; i += 2)
4100 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4101 return mtable[i + 1];
4102 return name;
4103}
4104#endif
4105
4106#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4107/*
4108 * Obtain the current messages language. Used to set the default for
4109 * 'helplang'. May return NULL or an empty string.
4110 */
4111 char_u *
4112get_mess_lang()
4113{
4114 char_u *p;
4115
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004116# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117# if defined(LC_MESSAGES)
4118 p = (char_u *)get_locale_val(LC_MESSAGES);
4119# else
4120 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004121 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4122 * and LC_MONETARY may be set differently for a Japanese working in the
4123 * US. */
4124 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125# endif
4126# else
4127 p = mch_getenv((char_u *)"LC_ALL");
4128 if (p == NULL || *p == NUL)
4129 {
4130 p = mch_getenv((char_u *)"LC_MESSAGES");
4131 if (p == NULL || *p == NUL)
4132 p = mch_getenv((char_u *)"LANG");
4133 }
4134# endif
4135# ifdef WIN32
4136 p = gettext_lang(p);
4137# endif
4138 return p;
4139}
4140#endif
4141
Bram Moolenaardef9e822004-12-31 20:58:58 +00004142/* Complicated #if; matches with where get_mess_env() is used below. */
4143#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4144 && defined(LC_MESSAGES))) \
4145 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4146 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4147 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148static char_u *get_mess_env __ARGS((void));
4149
4150/*
4151 * Get the language used for messages from the environment.
4152 */
4153 static char_u *
4154get_mess_env()
4155{
4156 char_u *p;
4157
4158 p = mch_getenv((char_u *)"LC_ALL");
4159 if (p == NULL || *p == NUL)
4160 {
4161 p = mch_getenv((char_u *)"LC_MESSAGES");
4162 if (p == NULL || *p == NUL)
4163 {
4164 p = mch_getenv((char_u *)"LANG");
4165 if (p != NULL && VIM_ISDIGIT(*p))
4166 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004167# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 if (p == NULL || *p == NUL)
4169 p = (char_u *)get_locale_val(LC_CTYPE);
4170# endif
4171 }
4172 }
4173 return p;
4174}
4175#endif
4176
4177#if defined(FEAT_EVAL) || defined(PROTO)
4178
4179/*
4180 * Set the "v:lang" variable according to the current locale setting.
4181 * Also do "v:lc_time"and "v:ctype".
4182 */
4183 void
4184set_lang_var()
4185{
4186 char_u *loc;
4187
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004188# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 loc = (char_u *)get_locale_val(LC_CTYPE);
4190# else
4191 /* setlocale() not supported: use the default value */
4192 loc = (char_u *)"C";
4193# endif
4194 set_vim_var_string(VV_CTYPE, loc, -1);
4195
4196 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4197 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004198# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199 loc = (char_u *)get_locale_val(LC_MESSAGES);
4200# else
4201 loc = get_mess_env();
4202# endif
4203 set_vim_var_string(VV_LANG, loc, -1);
4204
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004205# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206 loc = (char_u *)get_locale_val(LC_TIME);
4207# endif
4208 set_vim_var_string(VV_LC_TIME, loc, -1);
4209}
4210#endif
4211
4212#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4213 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4214/*
4215 * ":language": Set the language (locale).
4216 */
4217 void
4218ex_language(eap)
4219 exarg_T *eap;
4220{
4221 char *loc;
4222 char_u *p;
4223 char_u *name;
4224 int what = LC_ALL;
4225 char *whatstr = "";
4226#ifdef LC_MESSAGES
4227# define VIM_LC_MESSAGES LC_MESSAGES
4228#else
4229# define VIM_LC_MESSAGES 6789
4230#endif
4231
4232 name = eap->arg;
4233
4234 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4235 * Allow abbreviation, but require at least 3 characters to avoid
4236 * confusion with a two letter language name "me" or "ct". */
4237 p = skiptowhite(eap->arg);
4238 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4239 {
4240 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4241 {
4242 what = VIM_LC_MESSAGES;
4243 name = skipwhite(p);
4244 whatstr = "messages ";
4245 }
4246 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4247 {
4248 what = LC_CTYPE;
4249 name = skipwhite(p);
4250 whatstr = "ctype ";
4251 }
4252 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4253 {
4254 what = LC_TIME;
4255 name = skipwhite(p);
4256 whatstr = "time ";
4257 }
4258 }
4259
4260 if (*name == NUL)
4261 {
4262#ifndef LC_MESSAGES
4263 if (what == VIM_LC_MESSAGES)
4264 p = get_mess_env();
4265 else
4266#endif
4267 p = (char_u *)setlocale(what, NULL);
4268 if (p == NULL || *p == NUL)
4269 p = (char_u *)"Unknown";
4270 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4271 }
4272 else
4273 {
4274#ifndef LC_MESSAGES
4275 if (what == VIM_LC_MESSAGES)
4276 loc = "";
4277 else
4278#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004279 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004281#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4282 /* Make sure strtod() uses a decimal point, not a comma. */
4283 setlocale(LC_NUMERIC, "C");
4284#endif
4285 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 if (loc == NULL)
4287 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4288 else
4289 {
4290#ifdef HAVE_NL_MSG_CAT_CNTR
4291 /* Need to do this for GNU gettext, otherwise cached translations
4292 * will be used again. */
4293 extern int _nl_msg_cat_cntr;
4294
4295 ++_nl_msg_cat_cntr;
4296#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004297 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4299
4300 if (what != LC_TIME)
4301 {
4302 /* Tell gettext() what to translate to. It apparently doesn't
4303 * use the currently effective locale. Also do this when
4304 * FEAT_GETTEXT isn't defined, so that shell commands use this
4305 * value. */
4306 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004307 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004309
4310 /* Clear $LANGUAGE because GNU gettext uses it. */
4311 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004312# ifdef WIN32
4313 /* Apparently MS-Windows printf() may cause a crash when
4314 * we give it 8-bit text while it's expecting text in the
4315 * current locale. This call avoids that. */
4316 setlocale(LC_CTYPE, "C");
4317# endif
4318 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 if (what != LC_CTYPE)
4320 {
4321 char_u *mname;
4322#ifdef WIN32
4323 mname = gettext_lang(name);
4324#else
4325 mname = name;
4326#endif
4327 vim_setenv((char_u *)"LC_MESSAGES", mname);
4328#ifdef FEAT_MULTI_LANG
4329 set_helplang_default(mname);
4330#endif
4331 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332 }
4333
4334# ifdef FEAT_EVAL
4335 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4336 set_lang_var();
4337# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004338# ifdef FEAT_TITLE
4339 maketitle();
4340# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 }
4342 }
4343}
4344
4345# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004346
4347static char_u **locales = NULL; /* Array of all available locales */
4348static int did_init_locales = FALSE;
4349
4350static void init_locales __ARGS((void));
4351static char_u **find_locales __ARGS((void));
4352
4353/*
4354 * Lazy initialization of all available locales.
4355 */
4356 static void
4357init_locales()
4358{
4359 if (!did_init_locales)
4360 {
4361 did_init_locales = TRUE;
4362 locales = find_locales();
4363 }
4364}
4365
4366/* Return an array of strings for all available locales + NULL for the
4367 * last element. Return NULL in case of error. */
4368 static char_u **
4369find_locales()
4370{
4371 garray_T locales_ga;
4372 char_u *loc;
4373
4374 /* Find all available locales by running command "locale -a". If this
4375 * doesn't work we won't have completion. */
4376 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004377 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004378 if (locale_a == NULL)
4379 return NULL;
4380 ga_init2(&locales_ga, sizeof(char_u *), 20);
4381
4382 /* Transform locale_a string where each locale is separated by "\n"
4383 * into an array of locale strings. */
4384 loc = (char_u *)strtok((char *)locale_a, "\n");
4385
4386 while (loc != NULL)
4387 {
4388 if (ga_grow(&locales_ga, 1) == FAIL)
4389 break;
4390 loc = vim_strsave(loc);
4391 if (loc == NULL)
4392 break;
4393
4394 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4395 loc = (char_u *)strtok(NULL, "\n");
4396 }
4397 vim_free(locale_a);
4398 if (ga_grow(&locales_ga, 1) == FAIL)
4399 {
4400 ga_clear(&locales_ga);
4401 return NULL;
4402 }
4403 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4404 return (char_u **)locales_ga.ga_data;
4405}
4406
4407# if defined(EXITFREE) || defined(PROTO)
4408 void
4409free_locales()
4410{
4411 int i;
4412 if (locales != NULL)
4413 {
4414 for (i = 0; locales[i] != NULL; i++)
4415 vim_free(locales[i]);
4416 vim_free(locales);
4417 locales = NULL;
4418 }
4419}
4420# endif
4421
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422/*
4423 * Function given to ExpandGeneric() to obtain the possible arguments of the
4424 * ":language" command.
4425 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 char_u *
4427get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004428 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004429 int idx;
4430{
4431 if (idx == 0)
4432 return (char_u *)"messages";
4433 if (idx == 1)
4434 return (char_u *)"ctype";
4435 if (idx == 2)
4436 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004437
4438 init_locales();
4439 if (locales == NULL)
4440 return NULL;
4441 return locales[idx - 3];
4442}
4443
4444/*
4445 * Function given to ExpandGeneric() to obtain the available locales.
4446 */
4447 char_u *
4448get_locales(xp, idx)
4449 expand_T *xp UNUSED;
4450 int idx;
4451{
4452 init_locales();
4453 if (locales == NULL)
4454 return NULL;
4455 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004456}
4457# endif
4458
4459#endif