blob: 30f9e9d18b5755e33b63af5ed76c32720e33667f [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);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001111 profile_fname = expand_env_save_opt(e, TRUE);
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 Moolenaaraa23b372015-09-08 18:46:31 +02002432 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
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
Bram Moolenaare25bb902015-02-27 20:33:37 +01002443 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 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 Moolenaaraa23b372015-09-08 18:46:31 +02002449#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002450 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002451 int qf_idx;
2452#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002453
2454#ifndef FEAT_WINDOWS
2455 if (eap->cmdidx == CMD_windo)
2456 {
2457 ex_ni(eap);
2458 return;
2459 }
2460#endif
2461
2462#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002463 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002464 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2465 * great speed improvement. */
2466 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002468#ifdef FEAT_CLIPBOARD
2469 start_global_changes();
2470#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471
2472 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002473 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002475 || !check_changed(curbuf, CCGD_AW
2476 | (eap->forceit ? CCGD_FORCEIT : 0)
2477 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002480 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002482 wp = firstwin;
2483 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002485 switch (eap->cmdidx)
2486 {
2487#ifdef FEAT_WINDOWS
2488 case CMD_windo:
2489 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2490 i++;
2491 break;
2492 case CMD_tabdo:
2493 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2494 i++;
2495 break;
2496#endif
2497 case CMD_argdo:
2498 i = eap->line1 - 1;
2499 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002500 default:
2501 break;
2502 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 /* set pcmark now */
2504 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002505 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002506 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002507 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002508 || !buf->b_p_bl); buf = buf->b_next)
2509 if (buf->b_fnum > eap->line2)
2510 {
2511 buf = NULL;
2512 break;
2513 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002514 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002515 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002516 }
2517#ifdef FEAT_QUICKFIX
2518 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2519 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2520 {
2521 qf_size = qf_get_size(eap);
2522 if (qf_size <= 0 || eap->line1 > qf_size)
2523 buf = NULL;
2524 else
2525 {
2526 ex_cc(eap);
2527
2528 buf = curbuf;
2529 i = eap->line1 - 1;
2530 if (eap->addr_count <= 0)
2531 /* default is all the quickfix/location list entries */
2532 eap->line2 = qf_size;
2533 }
2534 }
2535#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 else
2537 setpcmark();
2538 listcmd_busy = TRUE; /* avoids setting pcmark below */
2539
Bram Moolenaare25bb902015-02-27 20:33:37 +01002540 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 {
2542 if (eap->cmdidx == CMD_argdo)
2543 {
2544 /* go to argument "i" */
2545 if (i == ARGCOUNT)
2546 break;
2547 /* Don't call do_argfile() when already there, it will try
2548 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002549 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002550 {
2551 /* Clear 'shm' to avoid that the file message overwrites
2552 * any output from the command. */
2553 p_shm_save = vim_strsave(p_shm);
2554 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002556 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2557 vim_free(p_shm_save);
2558 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 if (curwin->w_arg_idx != i)
2560 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002561 }
2562#ifdef FEAT_WINDOWS
2563 else if (eap->cmdidx == CMD_windo)
2564 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002565 /* go to window "wp" */
2566 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002568 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002569 if (curwin != wp)
2570 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002571 wp = curwin->w_next;
2572 }
2573 else if (eap->cmdidx == CMD_tabdo)
2574 {
2575 /* go to window "tp" */
2576 if (!valid_tabpage(tp))
2577 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002578 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002579 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 }
2581#endif
2582 else if (eap->cmdidx == CMD_bufdo)
2583 {
2584 /* Remember the number of the next listed buffer, in case
2585 * ":bwipe" is used or autocommands do something strange. */
2586 next_fnum = -1;
2587 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2588 if (buf->b_p_bl)
2589 {
2590 next_fnum = buf->b_fnum;
2591 break;
2592 }
2593 }
2594
Bram Moolenaara162bc52015-01-07 16:54:21 +01002595 ++i;
2596
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597 /* execute the command */
2598 do_cmdline(eap->arg, eap->getline, eap->cookie,
2599 DOCMD_VERBOSE + DOCMD_NOWAIT);
2600
2601 if (eap->cmdidx == CMD_bufdo)
2602 {
2603 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002604 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002605 break;
2606 /* Check if the buffer still exists. */
2607 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2608 if (buf->b_fnum == next_fnum)
2609 break;
2610 if (buf == NULL)
2611 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002612
2613 /* Go to the next buffer. Clear 'shm' to avoid that the file
2614 * message overwrites any output from the command. */
2615 p_shm_save = vim_strsave(p_shm);
2616 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002618 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2619 vim_free(p_shm_save);
2620
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002621 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002622 if (curbuf->b_fnum != next_fnum)
2623 break;
2624 }
2625
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002626#ifdef FEAT_QUICKFIX
2627 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2628 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2629 {
2630 if (i >= qf_size || i >= eap->line2)
2631 break;
2632
2633 qf_idx = qf_get_cur_idx(eap);
2634
2635 ex_cnext(eap);
2636
2637 /* If jumping to the next quickfix entry fails, quit here */
2638 if (qf_get_cur_idx(eap) == qf_idx)
2639 break;
2640 }
2641#endif
2642
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 if (eap->cmdidx == CMD_windo)
2644 {
2645 validate_cursor(); /* cursor may have moved */
2646#ifdef FEAT_SCROLLBIND
2647 /* required when 'scrollbind' has been set */
2648 if (curwin->w_p_scb)
2649 do_check_scrollbind(TRUE);
2650#endif
2651 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002652
2653#ifdef FEAT_WINDOWS
2654 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2655 if (i+1 > eap->line2)
2656 break;
2657#endif
2658 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2659 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660 }
2661 listcmd_busy = FALSE;
2662 }
2663
2664#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002665 if (save_ei != NULL)
2666 {
2667 au_event_restore(save_ei);
2668 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2669 curbuf->b_fname, TRUE, curbuf);
2670 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002672#ifdef FEAT_CLIPBOARD
2673 end_global_changes();
2674#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675}
2676
2677/*
2678 * Add files[count] to the arglist of the current window after arg "after".
2679 * The file names in files[count] must have been allocated and are taken over.
2680 * Files[] itself is not taken over.
2681 * Returns index of first added argument. Returns -1 when failed (out of mem).
2682 */
2683 static int
2684alist_add_list(count, files, after)
2685 int count;
2686 char_u **files;
2687 int after; /* where to add: 0 = before first one */
2688{
2689 int i;
2690
2691 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2692 {
2693 if (after < 0)
2694 after = 0;
2695 if (after > ARGCOUNT)
2696 after = ARGCOUNT;
2697 if (after < ARGCOUNT)
2698 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2699 (ARGCOUNT - after) * sizeof(aentry_T));
2700 for (i = 0; i < count; ++i)
2701 {
2702 ARGLIST[after + i].ae_fname = files[i];
2703 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2704 }
2705 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 if (curwin->w_arg_idx >= after)
2707 ++curwin->w_arg_idx;
2708 return after;
2709 }
2710
2711 for (i = 0; i < count; ++i)
2712 vim_free(files[i]);
2713 return -1;
2714}
2715
2716#endif /* FEAT_LISTCMDS */
2717
2718#ifdef FEAT_EVAL
2719/*
2720 * ":compiler[!] {name}"
2721 */
2722 void
2723ex_compiler(eap)
2724 exarg_T *eap;
2725{
2726 char_u *buf;
2727 char_u *old_cur_comp = NULL;
2728 char_u *p;
2729
2730 if (*eap->arg == NUL)
2731 {
2732 /* List all compiler scripts. */
2733 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2734 /* ) keep the indenter happy... */
2735 }
2736 else
2737 {
2738 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2739 if (buf != NULL)
2740 {
2741 if (eap->forceit)
2742 {
2743 /* ":compiler! {name}" sets global options */
2744 do_cmdline_cmd((char_u *)
2745 "command -nargs=* CompilerSet set <args>");
2746 }
2747 else
2748 {
2749 /* ":compiler! {name}" sets local options.
2750 * To remain backwards compatible "current_compiler" is always
2751 * used. A user's compiler plugin may set it, the distributed
2752 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002753 * "b:current_compiler" and restore "current_compiler".
2754 * Explicitly prepend "g:" to make it work in a function. */
2755 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 if (old_cur_comp != NULL)
2757 old_cur_comp = vim_strsave(old_cur_comp);
2758 do_cmdline_cmd((char_u *)
2759 "command -nargs=* CompilerSet setlocal <args>");
2760 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002761 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002762 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763
2764 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002765 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2767 vim_free(buf);
2768
2769 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2770
2771 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002772 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002773 if (p != NULL)
2774 set_internal_string_var((char_u *)"b:current_compiler", p);
2775
2776 /* Restore "current_compiler" for ":compiler {name}". */
2777 if (!eap->forceit)
2778 {
2779 if (old_cur_comp != NULL)
2780 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002781 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782 old_cur_comp);
2783 vim_free(old_cur_comp);
2784 }
2785 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002786 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787 }
2788 }
2789 }
2790}
2791#endif
2792
2793/*
2794 * ":runtime {name}"
2795 */
2796 void
2797ex_runtime(eap)
2798 exarg_T *eap;
2799{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002800 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801}
2802
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002803static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804
2805 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002806source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002807 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002808 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002809{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002810 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811}
2812
2813/*
2814 * Source the file "name" from all directories in 'runtimepath'.
2815 * "name" can contain wildcards.
2816 * When "all" is TRUE, source all files, otherwise only the first one.
2817 * return FAIL when no file could be sourced, OK otherwise.
2818 */
2819 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002820source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821 char_u *name;
2822 int all;
2823{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002824 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825}
2826
2827/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002828 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2829 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002830 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2831 * used.
2832 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002833 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002834 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2835 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002836 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 */
2838 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002839do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 char_u *name;
2841 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002842 void (*callback)__ARGS((char_u *fname, void *ck));
2843 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844{
2845 char_u *rtp;
2846 char_u *np;
2847 char_u *buf;
2848 char_u *rtp_copy;
2849 char_u *tail;
2850 int num_files;
2851 char_u **files;
2852 int i;
2853 int did_one = FALSE;
2854#ifdef AMIGA
2855 struct Process *proc = (struct Process *)FindTask(0L);
2856 APTR save_winptr = proc->pr_WindowPtr;
2857
2858 /* Avoid a requester here for a volume that doesn't exist. */
2859 proc->pr_WindowPtr = (APTR)-1L;
2860#endif
2861
2862 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2863 * value. */
2864 rtp_copy = vim_strsave(p_rtp);
2865 buf = alloc(MAXPATHL);
2866 if (buf != NULL && rtp_copy != NULL)
2867 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002868 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002869 {
2870 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002871 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002873 verbose_leave();
2874 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002875
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 /* Loop over all entries in 'runtimepath'. */
2877 rtp = rtp_copy;
2878 while (*rtp != NUL && (all || !did_one))
2879 {
2880 /* Copy the path from 'runtimepath' to buf[]. */
2881 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002882 if (name == NULL)
2883 {
2884 (*callback)(buf, (void *) &cookie);
2885 if (!did_one)
2886 did_one = (cookie == NULL);
2887 }
2888 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889 {
2890 add_pathsep(buf);
2891 tail = buf + STRLEN(buf);
2892
2893 /* Loop over all patterns in "name" */
2894 np = name;
2895 while (*np != NUL && (all || !did_one))
2896 {
2897 /* Append the pattern from "name" to buf[]. */
2898 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2899 "\t ");
2900
2901 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002902 {
2903 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002904 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002905 verbose_leave();
2906 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907
2908 /* Expand wildcards, invoke the callback for each match. */
2909 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2910 EW_FILE) == OK)
2911 {
2912 for (i = 0; i < num_files; ++i)
2913 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002914 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915 did_one = TRUE;
2916 if (!all)
2917 break;
2918 }
2919 FreeWild(num_files, files);
2920 }
2921 }
2922 }
2923 }
2924 }
2925 vim_free(buf);
2926 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002927 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002928 {
2929 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002930 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002931 verbose_leave();
2932 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933
2934#ifdef AMIGA
2935 proc->pr_WindowPtr = save_winptr;
2936#endif
2937
2938 return did_one ? OK : FAIL;
2939}
2940
2941#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2942/*
2943 * ":options"
2944 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002945 void
2946ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002947 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948{
2949 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2950}
2951#endif
2952
2953/*
2954 * ":source {fname}"
2955 */
2956 void
2957ex_source(eap)
2958 exarg_T *eap;
2959{
2960#ifdef FEAT_BROWSE
2961 if (cmdmod.browse)
2962 {
2963 char_u *fname = NULL;
2964
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002965 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002966 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2967 if (fname != NULL)
2968 {
2969 cmd_source(fname, eap);
2970 vim_free(fname);
2971 }
2972 }
2973 else
2974#endif
2975 cmd_source(eap->arg, eap);
2976}
2977
2978 static void
2979cmd_source(fname, eap)
2980 char_u *fname;
2981 exarg_T *eap;
2982{
2983 if (*fname == NUL)
2984 EMSG(_(e_argreq));
2985
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002987 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002988 * Need to execute the commands directly. This is required at least
2989 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 * - ":g" command busy
2991 * - after ":argdo", ":windo" or ":bufdo"
2992 * - another command follows
2993 * - inside a loop
2994 */
2995 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2996#ifdef FEAT_EVAL
2997 || eap->cstack->cs_idx >= 0
2998#endif
2999 );
3000
3001 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003002 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 EMSG2(_(e_notopen), fname);
3004}
3005
3006/*
3007 * ":source" and associated commands.
3008 */
3009/*
3010 * Structure used to store info for each sourced file.
3011 * It is shared between do_source() and getsourceline().
3012 * This is required, because it needs to be handed to do_cmdline() and
3013 * sourcing can be done recursively.
3014 */
3015struct source_cookie
3016{
3017 FILE *fp; /* opened file for sourcing */
3018 char_u *nextline; /* if not NULL: line that was read ahead */
3019 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003020#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3022 int error; /* TRUE if LF found after CR-LF */
3023#endif
3024#ifdef FEAT_EVAL
3025 linenr_T breakpoint; /* next line with breakpoint or zero */
3026 char_u *fname; /* name of sourced file */
3027 int dbg_tick; /* debug_tick when breakpoint was set */
3028 int level; /* top nesting level of sourced file */
3029#endif
3030#ifdef FEAT_MBYTE
3031 vimconv_T conv; /* type of conversion */
3032#endif
3033};
3034
3035#ifdef FEAT_EVAL
3036/*
3037 * Return the address holding the next breakpoint line for a source cookie.
3038 */
3039 linenr_T *
3040source_breakpoint(cookie)
3041 void *cookie;
3042{
3043 return &((struct source_cookie *)cookie)->breakpoint;
3044}
3045
3046/*
3047 * Return the address holding the debug tick for a source cookie.
3048 */
3049 int *
3050source_dbg_tick(cookie)
3051 void *cookie;
3052{
3053 return &((struct source_cookie *)cookie)->dbg_tick;
3054}
3055
3056/*
3057 * Return the nesting level for a source cookie.
3058 */
3059 int
3060source_level(cookie)
3061 void *cookie;
3062{
3063 return ((struct source_cookie *)cookie)->level;
3064}
3065#endif
3066
3067static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3068
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003069#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3070# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071static FILE *fopen_noinh_readbin __ARGS((char *filename));
3072
3073/*
3074 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003075 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 */
3077 static FILE *
3078fopen_noinh_readbin(filename)
3079 char *filename;
3080{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003081# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003082 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3083# else
3084 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003085# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086
3087 if (fd_tmp == -1)
3088 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003089
3090# ifdef HAVE_FD_CLOEXEC
3091 {
3092 int fdflags = fcntl(fd_tmp, F_GETFD);
3093 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003094 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003095 }
3096# endif
3097
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098 return fdopen(fd_tmp, READBIN);
3099}
3100#endif
3101
3102
3103/*
3104 * do_source: Read the file "fname" and execute its lines as EX commands.
3105 *
3106 * This function may be called recursively!
3107 *
3108 * return FAIL if file could not be opened, OK otherwise
3109 */
3110 int
3111do_source(fname, check_other, is_vimrc)
3112 char_u *fname;
3113 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003114 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115{
3116 struct source_cookie cookie;
3117 char_u *save_sourcing_name;
3118 linenr_T save_sourcing_lnum;
3119 char_u *p;
3120 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003121 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122 int retval = FAIL;
3123#ifdef FEAT_EVAL
3124 scid_T save_current_SID;
3125 static scid_T last_current_SID = 0;
3126 void *save_funccalp;
3127 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003128 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129# ifdef UNIX
3130 struct stat st;
3131 int stat_ok;
3132# endif
3133#endif
3134#ifdef STARTUPTIME
3135 struct timeval tv_rel;
3136 struct timeval tv_start;
3137#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003138#ifdef FEAT_PROFILE
3139 proftime_T wait_start;
3140#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003141
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 if (p == NULL)
3144 return retval;
3145 fname_exp = fix_fname(p);
3146 vim_free(p);
3147 if (fname_exp == NULL)
3148 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 if (mch_isdir(fname_exp))
3150 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003151 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 goto theend;
3153 }
3154
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003155#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003156 /* Apply SourceCmd autocommands, they should get the file and source it. */
3157 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3158 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3159 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003160 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003161# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003162 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003163# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003164 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003165# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003166 goto theend;
3167 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003168
3169 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003170 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3171#endif
3172
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003173#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3175#else
3176 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3177#endif
3178 if (cookie.fp == NULL && check_other)
3179 {
3180 /*
3181 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3182 * and ".exrc" by "_exrc" or vice versa.
3183 */
3184 p = gettail(fname_exp);
3185 if ((*p == '.' || *p == '_')
3186 && (STRICMP(p + 1, "vimrc") == 0
3187 || STRICMP(p + 1, "gvimrc") == 0
3188 || STRICMP(p + 1, "exrc") == 0))
3189 {
3190 if (*p == '_')
3191 *p = '.';
3192 else
3193 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003194#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3196#else
3197 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3198#endif
3199 }
3200 }
3201
3202 if (cookie.fp == NULL)
3203 {
3204 if (p_verbose > 0)
3205 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003206 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003208 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209 else
3210 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003211 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003212 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213 }
3214 goto theend;
3215 }
3216
3217 /*
3218 * The file exists.
3219 * - In verbose mode, give a message.
3220 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3221 */
3222 if (p_verbose > 1)
3223 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003224 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003226 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 else
3228 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003229 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003230 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003232 if (is_vimrc == DOSO_VIMRC)
3233 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3234 else if (is_vimrc == DOSO_GVIMRC)
3235 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236
3237#ifdef USE_CRNL
3238 /* If no automatic file format: Set default to CR-NL. */
3239 if (*p_ffs == NUL)
3240 cookie.fileformat = EOL_DOS;
3241 else
3242 cookie.fileformat = EOL_UNKNOWN;
3243 cookie.error = FALSE;
3244#endif
3245
3246#ifdef USE_CR
3247 /* If no automatic file format: Set default to CR. */
3248 if (*p_ffs == NUL)
3249 cookie.fileformat = EOL_MAC;
3250 else
3251 cookie.fileformat = EOL_UNKNOWN;
3252 cookie.error = FALSE;
3253#endif
3254
3255 cookie.nextline = NULL;
3256 cookie.finished = FALSE;
3257
3258#ifdef FEAT_EVAL
3259 /*
3260 * Check if this script has a breakpoint.
3261 */
3262 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3263 cookie.fname = fname_exp;
3264 cookie.dbg_tick = debug_tick;
3265
3266 cookie.level = ex_nesting_level;
3267#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003268
3269 /*
3270 * Keep the sourcing name/lnum, for recursive calls.
3271 */
3272 save_sourcing_name = sourcing_name;
3273 sourcing_name = fname_exp;
3274 save_sourcing_lnum = sourcing_lnum;
3275 sourcing_lnum = 0;
3276
Bram Moolenaar73881402009-02-04 16:50:47 +00003277#ifdef FEAT_MBYTE
3278 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3279
3280 /* Read the first line so we can check for a UTF-8 BOM. */
3281 firstline = getsourceline(0, (void *)&cookie, 0);
3282 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3283 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3284 {
3285 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3286 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3287 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003288 if (p == NULL)
3289 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003290 if (p != NULL)
3291 {
3292 vim_free(firstline);
3293 firstline = p;
3294 }
3295 }
3296#endif
3297
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003299 if (time_fd != NULL)
3300 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301#endif
3302
3303#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003304# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003305 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003306 prof_child_enter(&wait_start); /* entering a child now */
3307# endif
3308
3309 /* Don't use local function variables, if called from a function.
3310 * Also starts profiling timer for nested script. */
3311 save_funccalp = save_funccal();
3312
Bram Moolenaar071d4272004-06-13 20:20:40 +00003313 /*
3314 * Check if this script was sourced before to finds its SID.
3315 * If it's new, generate a new SID.
3316 */
3317 save_current_SID = current_SID;
3318# ifdef UNIX
3319 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3320# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003321 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3322 {
3323 si = &SCRIPT_ITEM(current_SID);
3324 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 && (
3326# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003327 /* Compare dev/ino when possible, it catches symbolic
3328 * links. Also compare file names, the inode may change
3329 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003330 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003331 && (si->sn_dev == st.st_dev
3332 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003333# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003334 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003336 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 if (current_SID == 0)
3338 {
3339 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003340 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3341 == FAIL)
3342 goto almosttheend;
3343 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003345 ++script_items.ga_len;
3346 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3347# ifdef FEAT_PROFILE
3348 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003349# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003350 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003351 si = &SCRIPT_ITEM(current_SID);
3352 si->sn_name = fname_exp;
3353 fname_exp = NULL;
3354# ifdef UNIX
3355 if (stat_ok)
3356 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003357 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003358 si->sn_dev = st.st_dev;
3359 si->sn_ino = st.st_ino;
3360 }
3361 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003362 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003363# endif
3364
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365 /* Allocate the local script variables to use for this script. */
3366 new_script_vars(current_SID);
3367 }
3368
Bram Moolenaar05159a02005-02-26 23:04:13 +00003369# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003370 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003371 {
3372 int forceit;
3373
3374 /* Check if we do profiling for this script. */
3375 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3376 {
3377 script_do_profile(si);
3378 si->sn_pr_force = forceit;
3379 }
3380 if (si->sn_prof_on)
3381 {
3382 ++si->sn_pr_count;
3383 profile_start(&si->sn_pr_start);
3384 profile_zero(&si->sn_pr_children);
3385 }
3386 }
3387# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388#endif
3389
3390 /*
3391 * Call do_cmdline, which will call getsourceline() to get the lines.
3392 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003393 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003394 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003396
3397#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003398 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003399 {
3400 /* Get "si" again, "script_items" may have been reallocated. */
3401 si = &SCRIPT_ITEM(current_SID);
3402 if (si->sn_prof_on)
3403 {
3404 profile_end(&si->sn_pr_start);
3405 profile_sub_wait(&wait_start, &si->sn_pr_start);
3406 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003407 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3408 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003409 }
3410 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003411#endif
3412
3413 if (got_int)
3414 EMSG(_(e_interr));
3415 sourcing_name = save_sourcing_name;
3416 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003417 if (p_verbose > 1)
3418 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003419 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003420 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003422 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003423 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003424 }
3425#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003426 if (time_fd != NULL)
3427 {
3428 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3429 time_msg((char *)IObuff, &tv_start);
3430 time_pop(&tv_rel);
3431 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432#endif
3433
3434#ifdef FEAT_EVAL
3435 /*
3436 * After a "finish" in debug mode, need to break at first command of next
3437 * sourced file.
3438 */
3439 if (save_debug_break_level > ex_nesting_level
3440 && debug_break_level == ex_nesting_level)
3441 ++debug_break_level;
3442#endif
3443
Bram Moolenaar05159a02005-02-26 23:04:13 +00003444#ifdef FEAT_EVAL
3445almosttheend:
3446 current_SID = save_current_SID;
3447 restore_funccal(save_funccalp);
3448# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003449 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003450 prof_child_exit(&wait_start); /* leaving a child now */
3451# endif
3452#endif
3453 fclose(cookie.fp);
3454 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003455 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003456#ifdef FEAT_MBYTE
3457 convert_setup(&cookie.conv, NULL, NULL);
3458#endif
3459
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460theend:
3461 vim_free(fname_exp);
3462 return retval;
3463}
3464
3465#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003466
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467/*
3468 * ":scriptnames"
3469 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 void
3471ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003472 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473{
3474 int i;
3475
Bram Moolenaar05159a02005-02-26 23:04:13 +00003476 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3477 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003478 {
3479 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3480 NameBuff, MAXPATHL, TRUE);
3481 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003482 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483}
3484
3485# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3486/*
3487 * Fix slashes in the list of script names for 'shellslash'.
3488 */
3489 void
3490scriptnames_slash_adjust()
3491{
3492 int i;
3493
Bram Moolenaar05159a02005-02-26 23:04:13 +00003494 for (i = 1; i <= script_items.ga_len; ++i)
3495 if (SCRIPT_ITEM(i).sn_name != NULL)
3496 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497}
3498# endif
3499
3500/*
3501 * Get a pointer to a script name. Used for ":verbose set".
3502 */
3503 char_u *
3504get_scriptname(id)
3505 scid_T id;
3506{
3507 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003508 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003510 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003512 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003514 return (char_u *)_("environment variable");
3515 if (id == SID_ERROR)
3516 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003517 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003518}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003519
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003520# if defined(EXITFREE) || defined(PROTO)
3521 void
3522free_scriptnames()
3523{
3524 int i;
3525
3526 for (i = script_items.ga_len; i > 0; --i)
3527 vim_free(SCRIPT_ITEM(i).sn_name);
3528 ga_clear(&script_items);
3529}
3530# endif
3531
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532#endif
3533
3534#if defined(USE_CR) || defined(PROTO)
3535
3536# if defined(__MSL__) && (__MSL__ >= 22)
3537/*
3538 * Newer version of the Metrowerks library handle DOS and UNIX files
3539 * without help.
3540 * Test with earlier versions, MSL 2.2 is the library supplied with
3541 * Codewarrior Pro 2.
3542 */
3543 char *
3544fgets_cr(s, n, stream)
3545 char *s;
3546 int n;
3547 FILE *stream;
3548{
3549 return fgets(s, n, stream);
3550}
3551# else
3552/*
3553 * Version of fgets() which also works for lines ending in a <CR> only
3554 * (Macintosh format).
3555 * For older versions of the Metrowerks library.
3556 * At least CodeWarrior 9 needed this code.
3557 */
3558 char *
3559fgets_cr(s, n, stream)
3560 char *s;
3561 int n;
3562 FILE *stream;
3563{
3564 int c = 0;
3565 int char_read = 0;
3566
3567 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3568 {
3569 c = fgetc(stream);
3570 s[char_read++] = c;
3571 /* If the file is in DOS format, we need to skip a NL after a CR. I
3572 * thought it was the other way around, but this appears to work... */
3573 if (c == '\n')
3574 {
3575 c = fgetc(stream);
3576 if (c != '\r')
3577 ungetc(c, stream);
3578 }
3579 }
3580
3581 s[char_read] = 0;
3582 if (char_read == 0)
3583 return NULL;
3584
3585 if (feof(stream) && char_read == 1)
3586 return NULL;
3587
3588 return s;
3589}
3590# endif
3591#endif
3592
3593/*
3594 * Get one full line from a sourced file.
3595 * Called by do_cmdline() when it's called from do_source().
3596 *
3597 * Return a pointer to the line in allocated memory.
3598 * Return NULL for end-of-file or some error.
3599 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600 char_u *
3601getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003602 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003604 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605{
3606 struct source_cookie *sp = (struct source_cookie *)cookie;
3607 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003608 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609
3610#ifdef FEAT_EVAL
3611 /* If breakpoints have been added/deleted need to check for it. */
3612 if (sp->dbg_tick < debug_tick)
3613 {
3614 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3615 sp->dbg_tick = debug_tick;
3616 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003617# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003618 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003619 script_line_end();
3620# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003621#endif
3622 /*
3623 * Get current line. If there is a read-ahead line, use it, otherwise get
3624 * one now.
3625 */
3626 if (sp->finished)
3627 line = NULL;
3628 else if (sp->nextline == NULL)
3629 line = get_one_sourceline(sp);
3630 else
3631 {
3632 line = sp->nextline;
3633 sp->nextline = NULL;
3634 ++sourcing_lnum;
3635 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003636#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003637 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003638 script_line_start();
3639#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640
3641 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3642 * contain the 'C' flag. */
3643 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3644 {
3645 /* compensate for the one line read-ahead */
3646 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003647
3648 /* Get the next line and concatenate it when it starts with a
3649 * backslash. We always need to read the next line, keep it in
3650 * sp->nextline. */
3651 sp->nextline = get_one_sourceline(sp);
3652 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003654 garray_T ga;
3655
Bram Moolenaarb549a732012-02-22 18:29:33 +01003656 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003657 ga_concat(&ga, line);
3658 ga_concat(&ga, p + 1);
3659 for (;;)
3660 {
3661 vim_free(sp->nextline);
3662 sp->nextline = get_one_sourceline(sp);
3663 if (sp->nextline == NULL)
3664 break;
3665 p = skipwhite(sp->nextline);
3666 if (*p != '\\')
3667 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003668 /* Adjust the growsize to the current length to speed up
3669 * concatenating many lines. */
3670 if (ga.ga_len > 400)
3671 {
3672 if (ga.ga_len > 8000)
3673 ga.ga_growsize = 8000;
3674 else
3675 ga.ga_growsize = ga.ga_len;
3676 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003677 ga_concat(&ga, p + 1);
3678 }
3679 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003681 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 }
3683 }
3684
3685#ifdef FEAT_MBYTE
3686 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3687 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003688 char_u *s;
3689
Bram Moolenaar071d4272004-06-13 20:20:40 +00003690 /* Convert the encoding of the script line. */
3691 s = string_convert(&sp->conv, line, NULL);
3692 if (s != NULL)
3693 {
3694 vim_free(line);
3695 line = s;
3696 }
3697 }
3698#endif
3699
3700#ifdef FEAT_EVAL
3701 /* Did we encounter a breakpoint? */
3702 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3703 {
3704 dbg_breakpoint(sp->fname, sourcing_lnum);
3705 /* Find next breakpoint. */
3706 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3707 sp->dbg_tick = debug_tick;
3708 }
3709#endif
3710
3711 return line;
3712}
3713
3714 static char_u *
3715get_one_sourceline(sp)
3716 struct source_cookie *sp;
3717{
3718 garray_T ga;
3719 int len;
3720 int c;
3721 char_u *buf;
3722#ifdef USE_CRNL
3723 int has_cr; /* CR-LF found */
3724#endif
3725#ifdef USE_CR
3726 char_u *scan;
3727#endif
3728 int have_read = FALSE;
3729
3730 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003731 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732
3733 /*
3734 * Loop until there is a finished line (or end-of-file).
3735 */
3736 sourcing_lnum++;
3737 for (;;)
3738 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003739 /* make room to read at least 120 (more) characters */
3740 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 break;
3742 buf = (char_u *)ga.ga_data;
3743
3744#ifdef USE_CR
3745 if (sp->fileformat == EOL_MAC)
3746 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003747 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3748 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 break;
3750 }
3751 else
3752#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003753 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3754 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003756 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757#ifdef USE_CRNL
3758 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3759 * CTRL-Z by its own, or after a NL. */
3760 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3761 && sp->fileformat == EOL_DOS
3762 && buf[len - 1] == Ctrl_Z)
3763 {
3764 buf[len - 1] = NUL;
3765 break;
3766 }
3767#endif
3768
3769#ifdef USE_CR
3770 /* If the read doesn't stop on a new line, and there's
3771 * some CR then we assume a Mac format */
3772 if (sp->fileformat == EOL_UNKNOWN)
3773 {
3774 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3775 sp->fileformat = EOL_MAC;
3776 else
3777 sp->fileformat = EOL_UNIX;
3778 }
3779
3780 if (sp->fileformat == EOL_MAC)
3781 {
3782 scan = vim_strchr(buf, '\r');
3783
3784 if (scan != NULL)
3785 {
3786 *scan = '\n';
3787 if (*(scan + 1) != 0)
3788 {
3789 *(scan + 1) = 0;
3790 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3791 }
3792 }
3793 len = STRLEN(buf);
3794 }
3795#endif
3796
3797 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 ga.ga_len = len;
3799
3800 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003801 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 continue;
3803
3804 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3805 {
3806#ifdef USE_CRNL
3807 has_cr = (len >= 2 && buf[len - 2] == '\r');
3808 if (sp->fileformat == EOL_UNKNOWN)
3809 {
3810 if (has_cr)
3811 sp->fileformat = EOL_DOS;
3812 else
3813 sp->fileformat = EOL_UNIX;
3814 }
3815
3816 if (sp->fileformat == EOL_DOS)
3817 {
3818 if (has_cr) /* replace trailing CR */
3819 {
3820 buf[len - 2] = '\n';
3821 --len;
3822 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 }
3824 else /* lines like ":map xx yy^M" will have failed */
3825 {
3826 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003827 {
3828 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003830 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 sp->error = TRUE;
3832 sp->fileformat = EOL_UNIX;
3833 }
3834 }
3835#endif
3836 /* The '\n' is escaped if there is an odd number of ^V's just
3837 * before it, first set "c" just before the 'V's and then check
3838 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3839 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3840 ;
3841 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3842 {
3843 sourcing_lnum++;
3844 continue;
3845 }
3846
3847 buf[len - 1] = NUL; /* remove the NL */
3848 }
3849
3850 /*
3851 * Check for ^C here now and then, so recursive :so can be broken.
3852 */
3853 line_breakcheck();
3854 break;
3855 }
3856
3857 if (have_read)
3858 return (char_u *)ga.ga_data;
3859
3860 vim_free(ga.ga_data);
3861 return NULL;
3862}
3863
Bram Moolenaar05159a02005-02-26 23:04:13 +00003864#if defined(FEAT_PROFILE) || defined(PROTO)
3865/*
3866 * Called when starting to read a script line.
3867 * "sourcing_lnum" must be correct!
3868 * When skipping lines it may not actually be executed, but we won't find out
3869 * until later and we need to store the time now.
3870 */
3871 void
3872script_line_start()
3873{
3874 scriptitem_T *si;
3875 sn_prl_T *pp;
3876
3877 if (current_SID <= 0 || current_SID > script_items.ga_len)
3878 return;
3879 si = &SCRIPT_ITEM(current_SID);
3880 if (si->sn_prof_on && sourcing_lnum >= 1)
3881 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003882 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003883 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02003884 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00003885 si->sn_prl_idx = sourcing_lnum - 1;
3886 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3887 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3888 {
3889 /* Zero counters for a line that was not used before. */
3890 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3891 pp->snp_count = 0;
3892 profile_zero(&pp->sn_prl_total);
3893 profile_zero(&pp->sn_prl_self);
3894 ++si->sn_prl_ga.ga_len;
3895 }
3896 si->sn_prl_execed = FALSE;
3897 profile_start(&si->sn_prl_start);
3898 profile_zero(&si->sn_prl_children);
3899 profile_get_wait(&si->sn_prl_wait);
3900 }
3901}
3902
3903/*
3904 * Called when actually executing a function line.
3905 */
3906 void
3907script_line_exec()
3908{
3909 scriptitem_T *si;
3910
3911 if (current_SID <= 0 || current_SID > script_items.ga_len)
3912 return;
3913 si = &SCRIPT_ITEM(current_SID);
3914 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3915 si->sn_prl_execed = TRUE;
3916}
3917
3918/*
3919 * Called when done with a function line.
3920 */
3921 void
3922script_line_end()
3923{
3924 scriptitem_T *si;
3925 sn_prl_T *pp;
3926
3927 if (current_SID <= 0 || current_SID > script_items.ga_len)
3928 return;
3929 si = &SCRIPT_ITEM(current_SID);
3930 if (si->sn_prof_on && si->sn_prl_idx >= 0
3931 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3932 {
3933 if (si->sn_prl_execed)
3934 {
3935 pp = &PRL_ITEM(si, si->sn_prl_idx);
3936 ++pp->snp_count;
3937 profile_end(&si->sn_prl_start);
3938 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003939 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003940 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3941 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003942 }
3943 si->sn_prl_idx = -1;
3944 }
3945}
3946#endif
3947
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948/*
3949 * ":scriptencoding": Set encoding conversion for a sourced script.
3950 * Without the multi-byte feature it's simply ignored.
3951 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 void
3953ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003954 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955{
3956#ifdef FEAT_MBYTE
3957 struct source_cookie *sp;
3958 char_u *name;
3959
3960 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3961 {
3962 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3963 return;
3964 }
3965
3966 if (*eap->arg != NUL)
3967 {
3968 name = enc_canonize(eap->arg);
3969 if (name == NULL) /* out of memory */
3970 return;
3971 }
3972 else
3973 name = eap->arg;
3974
3975 /* Setup for conversion from the specified encoding to 'encoding'. */
3976 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3977 convert_setup(&sp->conv, name, p_enc);
3978
3979 if (name != eap->arg)
3980 vim_free(name);
3981#endif
3982}
3983
3984#if defined(FEAT_EVAL) || defined(PROTO)
3985/*
3986 * ":finish": Mark a sourced file as finished.
3987 */
3988 void
3989ex_finish(eap)
3990 exarg_T *eap;
3991{
3992 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3993 do_finish(eap, FALSE);
3994 else
3995 EMSG(_("E168: :finish used outside of a sourced file"));
3996}
3997
3998/*
3999 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4000 * Also called for a pending finish at the ":endtry" or after returning from
4001 * an extra do_cmdline(). "reanimate" is used in the latter case.
4002 */
4003 void
4004do_finish(eap, reanimate)
4005 exarg_T *eap;
4006 int reanimate;
4007{
4008 int idx;
4009
4010 if (reanimate)
4011 ((struct source_cookie *)getline_cookie(eap->getline,
4012 eap->cookie))->finished = FALSE;
4013
4014 /*
4015 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4016 * not in its finally clause (which then is to be executed next) is found.
4017 * In this case, make the ":finish" pending for execution at the ":endtry".
4018 * Otherwise, finish normally.
4019 */
4020 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4021 if (idx >= 0)
4022 {
4023 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4024 report_make_pending(CSTP_FINISH, NULL);
4025 }
4026 else
4027 ((struct source_cookie *)getline_cookie(eap->getline,
4028 eap->cookie))->finished = TRUE;
4029}
4030
4031
4032/*
4033 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4034 * message for missing ":endif".
4035 * Return FALSE when not sourcing a file.
4036 */
4037 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00004038source_finished(fgetline, cookie)
4039 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040 void *cookie;
4041{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004042 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004044 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045}
4046#endif
4047
4048#if defined(FEAT_LISTCMDS) || defined(PROTO)
4049/*
4050 * ":checktime [buffer]"
4051 */
4052 void
4053ex_checktime(eap)
4054 exarg_T *eap;
4055{
4056 buf_T *buf;
4057 int save_no_check_timestamps = no_check_timestamps;
4058
4059 no_check_timestamps = 0;
4060 if (eap->addr_count == 0) /* default is all buffers */
4061 check_timestamps(FALSE);
4062 else
4063 {
4064 buf = buflist_findnr((int)eap->line2);
4065 if (buf != NULL) /* cannot happen? */
4066 (void)buf_check_timestamp(buf, FALSE);
4067 }
4068 no_check_timestamps = save_no_check_timestamps;
4069}
4070#endif
4071
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4073 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004074# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075static char *get_locale_val __ARGS((int what));
4076
4077 static char *
4078get_locale_val(what)
4079 int what;
4080{
4081 char *loc;
4082
4083 /* Obtain the locale value from the libraries. For DJGPP this is
4084 * redefined and it doesn't use the arguments. */
4085 loc = setlocale(what, NULL);
4086
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004087# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004088 if (loc != NULL)
4089 {
4090 char_u *p;
4091
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004092 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4093 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 p = vim_strchr(loc, '=');
4095 if (p != NULL)
4096 {
4097 loc = ++p;
4098 while (*p != NUL) /* remove trailing newline */
4099 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004100 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 {
4102 *p = NUL;
4103 break;
4104 }
4105 ++p;
4106 }
4107 }
4108 }
4109# endif
4110
4111 return loc;
4112}
4113#endif
4114
4115
4116#ifdef WIN32
4117/*
4118 * On MS-Windows locale names are strings like "German_Germany.1252", but
4119 * gettext expects "de". Try to translate one into another here for a few
4120 * supported languages.
4121 */
4122 static char_u *
4123gettext_lang(char_u *name)
4124{
4125 int i;
4126 static char *(mtable[]) = {
4127 "afrikaans", "af",
4128 "czech", "cs",
4129 "dutch", "nl",
4130 "german", "de",
4131 "english_united kingdom", "en_GB",
4132 "spanish", "es",
4133 "french", "fr",
4134 "italian", "it",
4135 "japanese", "ja",
4136 "korean", "ko",
4137 "norwegian", "no",
4138 "polish", "pl",
4139 "russian", "ru",
4140 "slovak", "sk",
4141 "swedish", "sv",
4142 "ukrainian", "uk",
4143 "chinese_china", "zh_CN",
4144 "chinese_taiwan", "zh_TW",
4145 NULL};
4146
4147 for (i = 0; mtable[i] != NULL; i += 2)
4148 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4149 return mtable[i + 1];
4150 return name;
4151}
4152#endif
4153
4154#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4155/*
4156 * Obtain the current messages language. Used to set the default for
4157 * 'helplang'. May return NULL or an empty string.
4158 */
4159 char_u *
4160get_mess_lang()
4161{
4162 char_u *p;
4163
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004164# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165# if defined(LC_MESSAGES)
4166 p = (char_u *)get_locale_val(LC_MESSAGES);
4167# else
4168 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004169 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4170 * and LC_MONETARY may be set differently for a Japanese working in the
4171 * US. */
4172 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004173# endif
4174# else
4175 p = mch_getenv((char_u *)"LC_ALL");
4176 if (p == NULL || *p == NUL)
4177 {
4178 p = mch_getenv((char_u *)"LC_MESSAGES");
4179 if (p == NULL || *p == NUL)
4180 p = mch_getenv((char_u *)"LANG");
4181 }
4182# endif
4183# ifdef WIN32
4184 p = gettext_lang(p);
4185# endif
4186 return p;
4187}
4188#endif
4189
Bram Moolenaardef9e822004-12-31 20:58:58 +00004190/* Complicated #if; matches with where get_mess_env() is used below. */
4191#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4192 && defined(LC_MESSAGES))) \
4193 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4194 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4195 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196static char_u *get_mess_env __ARGS((void));
4197
4198/*
4199 * Get the language used for messages from the environment.
4200 */
4201 static char_u *
4202get_mess_env()
4203{
4204 char_u *p;
4205
4206 p = mch_getenv((char_u *)"LC_ALL");
4207 if (p == NULL || *p == NUL)
4208 {
4209 p = mch_getenv((char_u *)"LC_MESSAGES");
4210 if (p == NULL || *p == NUL)
4211 {
4212 p = mch_getenv((char_u *)"LANG");
4213 if (p != NULL && VIM_ISDIGIT(*p))
4214 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004215# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004216 if (p == NULL || *p == NUL)
4217 p = (char_u *)get_locale_val(LC_CTYPE);
4218# endif
4219 }
4220 }
4221 return p;
4222}
4223#endif
4224
4225#if defined(FEAT_EVAL) || defined(PROTO)
4226
4227/*
4228 * Set the "v:lang" variable according to the current locale setting.
4229 * Also do "v:lc_time"and "v:ctype".
4230 */
4231 void
4232set_lang_var()
4233{
4234 char_u *loc;
4235
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004236# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 loc = (char_u *)get_locale_val(LC_CTYPE);
4238# else
4239 /* setlocale() not supported: use the default value */
4240 loc = (char_u *)"C";
4241# endif
4242 set_vim_var_string(VV_CTYPE, loc, -1);
4243
4244 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4245 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004246# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 loc = (char_u *)get_locale_val(LC_MESSAGES);
4248# else
4249 loc = get_mess_env();
4250# endif
4251 set_vim_var_string(VV_LANG, loc, -1);
4252
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004253# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 loc = (char_u *)get_locale_val(LC_TIME);
4255# endif
4256 set_vim_var_string(VV_LC_TIME, loc, -1);
4257}
4258#endif
4259
4260#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4261 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4262/*
4263 * ":language": Set the language (locale).
4264 */
4265 void
4266ex_language(eap)
4267 exarg_T *eap;
4268{
4269 char *loc;
4270 char_u *p;
4271 char_u *name;
4272 int what = LC_ALL;
4273 char *whatstr = "";
4274#ifdef LC_MESSAGES
4275# define VIM_LC_MESSAGES LC_MESSAGES
4276#else
4277# define VIM_LC_MESSAGES 6789
4278#endif
4279
4280 name = eap->arg;
4281
4282 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4283 * Allow abbreviation, but require at least 3 characters to avoid
4284 * confusion with a two letter language name "me" or "ct". */
4285 p = skiptowhite(eap->arg);
4286 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4287 {
4288 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4289 {
4290 what = VIM_LC_MESSAGES;
4291 name = skipwhite(p);
4292 whatstr = "messages ";
4293 }
4294 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4295 {
4296 what = LC_CTYPE;
4297 name = skipwhite(p);
4298 whatstr = "ctype ";
4299 }
4300 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4301 {
4302 what = LC_TIME;
4303 name = skipwhite(p);
4304 whatstr = "time ";
4305 }
4306 }
4307
4308 if (*name == NUL)
4309 {
4310#ifndef LC_MESSAGES
4311 if (what == VIM_LC_MESSAGES)
4312 p = get_mess_env();
4313 else
4314#endif
4315 p = (char_u *)setlocale(what, NULL);
4316 if (p == NULL || *p == NUL)
4317 p = (char_u *)"Unknown";
4318 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4319 }
4320 else
4321 {
4322#ifndef LC_MESSAGES
4323 if (what == VIM_LC_MESSAGES)
4324 loc = "";
4325 else
4326#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004327 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004329#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4330 /* Make sure strtod() uses a decimal point, not a comma. */
4331 setlocale(LC_NUMERIC, "C");
4332#endif
4333 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334 if (loc == NULL)
4335 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4336 else
4337 {
4338#ifdef HAVE_NL_MSG_CAT_CNTR
4339 /* Need to do this for GNU gettext, otherwise cached translations
4340 * will be used again. */
4341 extern int _nl_msg_cat_cntr;
4342
4343 ++_nl_msg_cat_cntr;
4344#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004345 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004346 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4347
4348 if (what != LC_TIME)
4349 {
4350 /* Tell gettext() what to translate to. It apparently doesn't
4351 * use the currently effective locale. Also do this when
4352 * FEAT_GETTEXT isn't defined, so that shell commands use this
4353 * value. */
4354 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004355 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004357
4358 /* Clear $LANGUAGE because GNU gettext uses it. */
4359 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004360# ifdef WIN32
4361 /* Apparently MS-Windows printf() may cause a crash when
4362 * we give it 8-bit text while it's expecting text in the
4363 * current locale. This call avoids that. */
4364 setlocale(LC_CTYPE, "C");
4365# endif
4366 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 if (what != LC_CTYPE)
4368 {
4369 char_u *mname;
4370#ifdef WIN32
4371 mname = gettext_lang(name);
4372#else
4373 mname = name;
4374#endif
4375 vim_setenv((char_u *)"LC_MESSAGES", mname);
4376#ifdef FEAT_MULTI_LANG
4377 set_helplang_default(mname);
4378#endif
4379 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380 }
4381
4382# ifdef FEAT_EVAL
4383 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4384 set_lang_var();
4385# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004386# ifdef FEAT_TITLE
4387 maketitle();
4388# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 }
4390 }
4391}
4392
4393# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004394
4395static char_u **locales = NULL; /* Array of all available locales */
4396static int did_init_locales = FALSE;
4397
4398static void init_locales __ARGS((void));
4399static char_u **find_locales __ARGS((void));
4400
4401/*
4402 * Lazy initialization of all available locales.
4403 */
4404 static void
4405init_locales()
4406{
4407 if (!did_init_locales)
4408 {
4409 did_init_locales = TRUE;
4410 locales = find_locales();
4411 }
4412}
4413
4414/* Return an array of strings for all available locales + NULL for the
4415 * last element. Return NULL in case of error. */
4416 static char_u **
4417find_locales()
4418{
4419 garray_T locales_ga;
4420 char_u *loc;
4421
4422 /* Find all available locales by running command "locale -a". If this
4423 * doesn't work we won't have completion. */
4424 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004425 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004426 if (locale_a == NULL)
4427 return NULL;
4428 ga_init2(&locales_ga, sizeof(char_u *), 20);
4429
4430 /* Transform locale_a string where each locale is separated by "\n"
4431 * into an array of locale strings. */
4432 loc = (char_u *)strtok((char *)locale_a, "\n");
4433
4434 while (loc != NULL)
4435 {
4436 if (ga_grow(&locales_ga, 1) == FAIL)
4437 break;
4438 loc = vim_strsave(loc);
4439 if (loc == NULL)
4440 break;
4441
4442 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4443 loc = (char_u *)strtok(NULL, "\n");
4444 }
4445 vim_free(locale_a);
4446 if (ga_grow(&locales_ga, 1) == FAIL)
4447 {
4448 ga_clear(&locales_ga);
4449 return NULL;
4450 }
4451 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4452 return (char_u **)locales_ga.ga_data;
4453}
4454
4455# if defined(EXITFREE) || defined(PROTO)
4456 void
4457free_locales()
4458{
4459 int i;
4460 if (locales != NULL)
4461 {
4462 for (i = 0; locales[i] != NULL; i++)
4463 vim_free(locales[i]);
4464 vim_free(locales);
4465 locales = NULL;
4466 }
4467}
4468# endif
4469
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470/*
4471 * Function given to ExpandGeneric() to obtain the possible arguments of the
4472 * ":language" command.
4473 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474 char_u *
4475get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004476 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 int idx;
4478{
4479 if (idx == 0)
4480 return (char_u *)"messages";
4481 if (idx == 1)
4482 return (char_u *)"ctype";
4483 if (idx == 2)
4484 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004485
4486 init_locales();
4487 if (locales == NULL)
4488 return NULL;
4489 return locales[idx - 3];
4490}
4491
4492/*
4493 * Function given to ExpandGeneric() to obtain the available locales.
4494 */
4495 char_u *
4496get_locales(xp, idx)
4497 expand_T *xp UNUSED;
4498 int idx;
4499{
4500 init_locales();
4501 if (locales == NULL)
4502 return NULL;
4503 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504}
4505# endif
4506
4507#endif