blob: 2763b69354b155b5c0bbee7a8db17dab6fe801d2 [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 Moolenaar32466aa2006-02-24 23:53:04 +00002432 * ":argdo", ":windo", ":bufdo", ":tabdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 */
2434 void
2435ex_listdo(eap)
2436 exarg_T *eap;
2437{
2438 int i;
2439#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002440 win_T *wp;
2441 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442#endif
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 Moolenaar071d4272004-06-13 20:20:40 +00002449
2450#ifndef FEAT_WINDOWS
2451 if (eap->cmdidx == CMD_windo)
2452 {
2453 ex_ni(eap);
2454 return;
2455 }
2456#endif
2457
2458#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002459 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002460 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2461 * great speed improvement. */
2462 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002464#ifdef FEAT_CLIPBOARD
2465 start_global_changes();
2466#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467
2468 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002469 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002471 || !check_changed(curbuf, CCGD_AW
2472 | (eap->forceit ? CCGD_FORCEIT : 0)
2473 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002476 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002478 wp = firstwin;
2479 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002481 switch (eap->cmdidx)
2482 {
2483#ifdef FEAT_WINDOWS
2484 case CMD_windo:
2485 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2486 i++;
2487 break;
2488 case CMD_tabdo:
2489 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2490 i++;
2491 break;
2492#endif
2493 case CMD_argdo:
2494 i = eap->line1 - 1;
2495 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002496 default:
2497 break;
2498 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 /* set pcmark now */
2500 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002501 {
2502 /* Advance to the first listed buffer after "eap->line1". */
2503 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
2504 || !buf->b_p_bl); buf = buf->b_next)
2505 if (buf->b_fnum > eap->line2)
2506 {
2507 buf = NULL;
2508 break;
2509 }
2510 if (buf != NULL)
2511 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
2512 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513 else
2514 setpcmark();
2515 listcmd_busy = TRUE; /* avoids setting pcmark below */
2516
Bram Moolenaare25bb902015-02-27 20:33:37 +01002517 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 {
2519 if (eap->cmdidx == CMD_argdo)
2520 {
2521 /* go to argument "i" */
2522 if (i == ARGCOUNT)
2523 break;
2524 /* Don't call do_argfile() when already there, it will try
2525 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002526 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002527 {
2528 /* Clear 'shm' to avoid that the file message overwrites
2529 * any output from the command. */
2530 p_shm_save = vim_strsave(p_shm);
2531 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002533 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2534 vim_free(p_shm_save);
2535 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 if (curwin->w_arg_idx != i)
2537 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538 }
2539#ifdef FEAT_WINDOWS
2540 else if (eap->cmdidx == CMD_windo)
2541 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002542 /* go to window "wp" */
2543 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002544 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002545 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002546 if (curwin != wp)
2547 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002548 wp = curwin->w_next;
2549 }
2550 else if (eap->cmdidx == CMD_tabdo)
2551 {
2552 /* go to window "tp" */
2553 if (!valid_tabpage(tp))
2554 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002555 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002556 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557 }
2558#endif
2559 else if (eap->cmdidx == CMD_bufdo)
2560 {
2561 /* Remember the number of the next listed buffer, in case
2562 * ":bwipe" is used or autocommands do something strange. */
2563 next_fnum = -1;
2564 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2565 if (buf->b_p_bl)
2566 {
2567 next_fnum = buf->b_fnum;
2568 break;
2569 }
2570 }
2571
Bram Moolenaara162bc52015-01-07 16:54:21 +01002572 ++i;
2573
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 /* execute the command */
2575 do_cmdline(eap->arg, eap->getline, eap->cookie,
2576 DOCMD_VERBOSE + DOCMD_NOWAIT);
2577
2578 if (eap->cmdidx == CMD_bufdo)
2579 {
2580 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002581 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 break;
2583 /* Check if the buffer still exists. */
2584 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2585 if (buf->b_fnum == next_fnum)
2586 break;
2587 if (buf == NULL)
2588 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002589
2590 /* Go to the next buffer. Clear 'shm' to avoid that the file
2591 * message overwrites any output from the command. */
2592 p_shm_save = vim_strsave(p_shm);
2593 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002595 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2596 vim_free(p_shm_save);
2597
Bram Moolenaar071d4272004-06-13 20:20:40 +00002598 /* If autocommands took us elsewhere, quit here */
2599 if (curbuf->b_fnum != next_fnum)
2600 break;
2601 }
2602
2603 if (eap->cmdidx == CMD_windo)
2604 {
2605 validate_cursor(); /* cursor may have moved */
2606#ifdef FEAT_SCROLLBIND
2607 /* required when 'scrollbind' has been set */
2608 if (curwin->w_p_scb)
2609 do_check_scrollbind(TRUE);
2610#endif
2611 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002612
2613#ifdef FEAT_WINDOWS
2614 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2615 if (i+1 > eap->line2)
2616 break;
2617#endif
2618 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2619 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 }
2621 listcmd_busy = FALSE;
2622 }
2623
2624#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002625 if (save_ei != NULL)
2626 {
2627 au_event_restore(save_ei);
2628 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2629 curbuf->b_fname, TRUE, curbuf);
2630 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002632#ifdef FEAT_CLIPBOARD
2633 end_global_changes();
2634#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002635}
2636
2637/*
2638 * Add files[count] to the arglist of the current window after arg "after".
2639 * The file names in files[count] must have been allocated and are taken over.
2640 * Files[] itself is not taken over.
2641 * Returns index of first added argument. Returns -1 when failed (out of mem).
2642 */
2643 static int
2644alist_add_list(count, files, after)
2645 int count;
2646 char_u **files;
2647 int after; /* where to add: 0 = before first one */
2648{
2649 int i;
2650
2651 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2652 {
2653 if (after < 0)
2654 after = 0;
2655 if (after > ARGCOUNT)
2656 after = ARGCOUNT;
2657 if (after < ARGCOUNT)
2658 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2659 (ARGCOUNT - after) * sizeof(aentry_T));
2660 for (i = 0; i < count; ++i)
2661 {
2662 ARGLIST[after + i].ae_fname = files[i];
2663 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2664 }
2665 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666 if (curwin->w_arg_idx >= after)
2667 ++curwin->w_arg_idx;
2668 return after;
2669 }
2670
2671 for (i = 0; i < count; ++i)
2672 vim_free(files[i]);
2673 return -1;
2674}
2675
2676#endif /* FEAT_LISTCMDS */
2677
2678#ifdef FEAT_EVAL
2679/*
2680 * ":compiler[!] {name}"
2681 */
2682 void
2683ex_compiler(eap)
2684 exarg_T *eap;
2685{
2686 char_u *buf;
2687 char_u *old_cur_comp = NULL;
2688 char_u *p;
2689
2690 if (*eap->arg == NUL)
2691 {
2692 /* List all compiler scripts. */
2693 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2694 /* ) keep the indenter happy... */
2695 }
2696 else
2697 {
2698 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2699 if (buf != NULL)
2700 {
2701 if (eap->forceit)
2702 {
2703 /* ":compiler! {name}" sets global options */
2704 do_cmdline_cmd((char_u *)
2705 "command -nargs=* CompilerSet set <args>");
2706 }
2707 else
2708 {
2709 /* ":compiler! {name}" sets local options.
2710 * To remain backwards compatible "current_compiler" is always
2711 * used. A user's compiler plugin may set it, the distributed
2712 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002713 * "b:current_compiler" and restore "current_compiler".
2714 * Explicitly prepend "g:" to make it work in a function. */
2715 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 if (old_cur_comp != NULL)
2717 old_cur_comp = vim_strsave(old_cur_comp);
2718 do_cmdline_cmd((char_u *)
2719 "command -nargs=* CompilerSet setlocal <args>");
2720 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002721 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002722 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723
2724 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002725 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002726 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2727 vim_free(buf);
2728
2729 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2730
2731 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002732 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733 if (p != NULL)
2734 set_internal_string_var((char_u *)"b:current_compiler", p);
2735
2736 /* Restore "current_compiler" for ":compiler {name}". */
2737 if (!eap->forceit)
2738 {
2739 if (old_cur_comp != NULL)
2740 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002741 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742 old_cur_comp);
2743 vim_free(old_cur_comp);
2744 }
2745 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002746 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002747 }
2748 }
2749 }
2750}
2751#endif
2752
2753/*
2754 * ":runtime {name}"
2755 */
2756 void
2757ex_runtime(eap)
2758 exarg_T *eap;
2759{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002760 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761}
2762
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002763static void source_callback __ARGS((char_u *fname, void *cookie));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764
2765 static void
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002766source_callback(fname, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 char_u *fname;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002768 void *cookie UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002770 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002771}
2772
2773/*
2774 * Source the file "name" from all directories in 'runtimepath'.
2775 * "name" can contain wildcards.
2776 * When "all" is TRUE, source all files, otherwise only the first one.
2777 * return FAIL when no file could be sourced, OK otherwise.
2778 */
2779 int
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002780source_runtime(name, all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002781 char_u *name;
2782 int all;
2783{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002784 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785}
2786
2787/*
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002788 * Find "name" in 'runtimepath'. When found, invoke the callback function for
2789 * it: callback(fname, "cookie")
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790 * When "all" is TRUE repeat for all matches, otherwise only the first one is
2791 * used.
2792 * Returns OK when at least one match found, FAIL otherwise.
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002793 *
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002794 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
2795 * passed by reference in this case, setting it to NULL indicates that callback
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002796 * has done its job.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797 */
2798 int
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002799do_in_runtimepath(name, all, callback, cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800 char_u *name;
2801 int all;
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002802 void (*callback)__ARGS((char_u *fname, void *ck));
2803 void *cookie;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804{
2805 char_u *rtp;
2806 char_u *np;
2807 char_u *buf;
2808 char_u *rtp_copy;
2809 char_u *tail;
2810 int num_files;
2811 char_u **files;
2812 int i;
2813 int did_one = FALSE;
2814#ifdef AMIGA
2815 struct Process *proc = (struct Process *)FindTask(0L);
2816 APTR save_winptr = proc->pr_WindowPtr;
2817
2818 /* Avoid a requester here for a volume that doesn't exist. */
2819 proc->pr_WindowPtr = (APTR)-1L;
2820#endif
2821
2822 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2823 * value. */
2824 rtp_copy = vim_strsave(p_rtp);
2825 buf = alloc(MAXPATHL);
2826 if (buf != NULL && rtp_copy != NULL)
2827 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002828 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002829 {
2830 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002831 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832 (char *)name, (char *)p_rtp);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002833 verbose_leave();
2834 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002835
Bram Moolenaar071d4272004-06-13 20:20:40 +00002836 /* Loop over all entries in 'runtimepath'. */
2837 rtp = rtp_copy;
2838 while (*rtp != NUL && (all || !did_one))
2839 {
2840 /* Copy the path from 'runtimepath' to buf[]. */
2841 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002842 if (name == NULL)
2843 {
2844 (*callback)(buf, (void *) &cookie);
2845 if (!did_one)
2846 did_one = (cookie == NULL);
2847 }
2848 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002849 {
2850 add_pathsep(buf);
2851 tail = buf + STRLEN(buf);
2852
2853 /* Loop over all patterns in "name" */
2854 np = name;
2855 while (*np != NUL && (all || !did_one))
2856 {
2857 /* Append the pattern from "name" to buf[]. */
2858 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2859 "\t ");
2860
2861 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002862 {
2863 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002864 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002865 verbose_leave();
2866 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867
2868 /* Expand wildcards, invoke the callback for each match. */
2869 if (gen_expand_wildcards(1, &buf, &num_files, &files,
2870 EW_FILE) == OK)
2871 {
2872 for (i = 0; i < num_files; ++i)
2873 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002874 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875 did_one = TRUE;
2876 if (!all)
2877 break;
2878 }
2879 FreeWild(num_files, files);
2880 }
2881 }
2882 }
2883 }
2884 }
2885 vim_free(buf);
2886 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002887 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002888 {
2889 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002890 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002891 verbose_leave();
2892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893
2894#ifdef AMIGA
2895 proc->pr_WindowPtr = save_winptr;
2896#endif
2897
2898 return did_one ? OK : FAIL;
2899}
2900
2901#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
2902/*
2903 * ":options"
2904 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905 void
2906ex_options(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00002907 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908{
2909 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
2910}
2911#endif
2912
2913/*
2914 * ":source {fname}"
2915 */
2916 void
2917ex_source(eap)
2918 exarg_T *eap;
2919{
2920#ifdef FEAT_BROWSE
2921 if (cmdmod.browse)
2922 {
2923 char_u *fname = NULL;
2924
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00002925 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
2927 if (fname != NULL)
2928 {
2929 cmd_source(fname, eap);
2930 vim_free(fname);
2931 }
2932 }
2933 else
2934#endif
2935 cmd_source(eap->arg, eap);
2936}
2937
2938 static void
2939cmd_source(fname, eap)
2940 char_u *fname;
2941 exarg_T *eap;
2942{
2943 if (*fname == NUL)
2944 EMSG(_(e_argreq));
2945
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02002947 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00002948 * Need to execute the commands directly. This is required at least
2949 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950 * - ":g" command busy
2951 * - after ":argdo", ":windo" or ":bufdo"
2952 * - another command follows
2953 * - inside a loop
2954 */
2955 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
2956#ifdef FEAT_EVAL
2957 || eap->cstack->cs_idx >= 0
2958#endif
2959 );
2960
2961 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002962 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963 EMSG2(_(e_notopen), fname);
2964}
2965
2966/*
2967 * ":source" and associated commands.
2968 */
2969/*
2970 * Structure used to store info for each sourced file.
2971 * It is shared between do_source() and getsourceline().
2972 * This is required, because it needs to be handed to do_cmdline() and
2973 * sourcing can be done recursively.
2974 */
2975struct source_cookie
2976{
2977 FILE *fp; /* opened file for sourcing */
2978 char_u *nextline; /* if not NULL: line that was read ahead */
2979 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02002980#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
2982 int error; /* TRUE if LF found after CR-LF */
2983#endif
2984#ifdef FEAT_EVAL
2985 linenr_T breakpoint; /* next line with breakpoint or zero */
2986 char_u *fname; /* name of sourced file */
2987 int dbg_tick; /* debug_tick when breakpoint was set */
2988 int level; /* top nesting level of sourced file */
2989#endif
2990#ifdef FEAT_MBYTE
2991 vimconv_T conv; /* type of conversion */
2992#endif
2993};
2994
2995#ifdef FEAT_EVAL
2996/*
2997 * Return the address holding the next breakpoint line for a source cookie.
2998 */
2999 linenr_T *
3000source_breakpoint(cookie)
3001 void *cookie;
3002{
3003 return &((struct source_cookie *)cookie)->breakpoint;
3004}
3005
3006/*
3007 * Return the address holding the debug tick for a source cookie.
3008 */
3009 int *
3010source_dbg_tick(cookie)
3011 void *cookie;
3012{
3013 return &((struct source_cookie *)cookie)->dbg_tick;
3014}
3015
3016/*
3017 * Return the nesting level for a source cookie.
3018 */
3019 int
3020source_level(cookie)
3021 void *cookie;
3022{
3023 return ((struct source_cookie *)cookie)->level;
3024}
3025#endif
3026
3027static char_u *get_one_sourceline __ARGS((struct source_cookie *sp));
3028
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003029#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3030# define USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031static FILE *fopen_noinh_readbin __ARGS((char *filename));
3032
3033/*
3034 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003035 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003036 */
3037 static FILE *
3038fopen_noinh_readbin(filename)
3039 char *filename;
3040{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003041# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003042 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3043# else
3044 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003045# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046
3047 if (fd_tmp == -1)
3048 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003049
3050# ifdef HAVE_FD_CLOEXEC
3051 {
3052 int fdflags = fcntl(fd_tmp, F_GETFD);
3053 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
3054 fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
3055 }
3056# endif
3057
Bram Moolenaar071d4272004-06-13 20:20:40 +00003058 return fdopen(fd_tmp, READBIN);
3059}
3060#endif
3061
3062
3063/*
3064 * do_source: Read the file "fname" and execute its lines as EX commands.
3065 *
3066 * This function may be called recursively!
3067 *
3068 * return FAIL if file could not be opened, OK otherwise
3069 */
3070 int
3071do_source(fname, check_other, is_vimrc)
3072 char_u *fname;
3073 int check_other; /* check for .vimrc and _vimrc */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003074 int is_vimrc; /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003075{
3076 struct source_cookie cookie;
3077 char_u *save_sourcing_name;
3078 linenr_T save_sourcing_lnum;
3079 char_u *p;
3080 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003081 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003082 int retval = FAIL;
3083#ifdef FEAT_EVAL
3084 scid_T save_current_SID;
3085 static scid_T last_current_SID = 0;
3086 void *save_funccalp;
3087 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003088 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089# ifdef UNIX
3090 struct stat st;
3091 int stat_ok;
3092# endif
3093#endif
3094#ifdef STARTUPTIME
3095 struct timeval tv_rel;
3096 struct timeval tv_start;
3097#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003098#ifdef FEAT_PROFILE
3099 proftime_T wait_start;
3100#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103 if (p == NULL)
3104 return retval;
3105 fname_exp = fix_fname(p);
3106 vim_free(p);
3107 if (fname_exp == NULL)
3108 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109 if (mch_isdir(fname_exp))
3110 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003111 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112 goto theend;
3113 }
3114
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003115#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003116 /* Apply SourceCmd autocommands, they should get the file and source it. */
3117 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3118 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3119 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003120 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003121# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003122 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003123# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003124 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003125# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003126 goto theend;
3127 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003128
3129 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003130 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3131#endif
3132
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003133#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3135#else
3136 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3137#endif
3138 if (cookie.fp == NULL && check_other)
3139 {
3140 /*
3141 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3142 * and ".exrc" by "_exrc" or vice versa.
3143 */
3144 p = gettail(fname_exp);
3145 if ((*p == '.' || *p == '_')
3146 && (STRICMP(p + 1, "vimrc") == 0
3147 || STRICMP(p + 1, "gvimrc") == 0
3148 || STRICMP(p + 1, "exrc") == 0))
3149 {
3150 if (*p == '_')
3151 *p = '.';
3152 else
3153 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003154#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3156#else
3157 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3158#endif
3159 }
3160 }
3161
3162 if (cookie.fp == NULL)
3163 {
3164 if (p_verbose > 0)
3165 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003166 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003167 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003168 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169 else
3170 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003171 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003172 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003173 }
3174 goto theend;
3175 }
3176
3177 /*
3178 * The file exists.
3179 * - In verbose mode, give a message.
3180 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3181 */
3182 if (p_verbose > 1)
3183 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003184 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003186 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003187 else
3188 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003189 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003190 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003191 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003192 if (is_vimrc == DOSO_VIMRC)
3193 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3194 else if (is_vimrc == DOSO_GVIMRC)
3195 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196
3197#ifdef USE_CRNL
3198 /* If no automatic file format: Set default to CR-NL. */
3199 if (*p_ffs == NUL)
3200 cookie.fileformat = EOL_DOS;
3201 else
3202 cookie.fileformat = EOL_UNKNOWN;
3203 cookie.error = FALSE;
3204#endif
3205
3206#ifdef USE_CR
3207 /* If no automatic file format: Set default to CR. */
3208 if (*p_ffs == NUL)
3209 cookie.fileformat = EOL_MAC;
3210 else
3211 cookie.fileformat = EOL_UNKNOWN;
3212 cookie.error = FALSE;
3213#endif
3214
3215 cookie.nextline = NULL;
3216 cookie.finished = FALSE;
3217
3218#ifdef FEAT_EVAL
3219 /*
3220 * Check if this script has a breakpoint.
3221 */
3222 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3223 cookie.fname = fname_exp;
3224 cookie.dbg_tick = debug_tick;
3225
3226 cookie.level = ex_nesting_level;
3227#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228
3229 /*
3230 * Keep the sourcing name/lnum, for recursive calls.
3231 */
3232 save_sourcing_name = sourcing_name;
3233 sourcing_name = fname_exp;
3234 save_sourcing_lnum = sourcing_lnum;
3235 sourcing_lnum = 0;
3236
Bram Moolenaar73881402009-02-04 16:50:47 +00003237#ifdef FEAT_MBYTE
3238 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3239
3240 /* Read the first line so we can check for a UTF-8 BOM. */
3241 firstline = getsourceline(0, (void *)&cookie, 0);
3242 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3243 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3244 {
3245 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3246 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3247 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003248 if (p == NULL)
3249 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003250 if (p != NULL)
3251 {
3252 vim_free(firstline);
3253 firstline = p;
3254 }
3255 }
3256#endif
3257
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003259 if (time_fd != NULL)
3260 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261#endif
3262
3263#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003264# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003265 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003266 prof_child_enter(&wait_start); /* entering a child now */
3267# endif
3268
3269 /* Don't use local function variables, if called from a function.
3270 * Also starts profiling timer for nested script. */
3271 save_funccalp = save_funccal();
3272
Bram Moolenaar071d4272004-06-13 20:20:40 +00003273 /*
3274 * Check if this script was sourced before to finds its SID.
3275 * If it's new, generate a new SID.
3276 */
3277 save_current_SID = current_SID;
3278# ifdef UNIX
3279 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3280# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003281 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3282 {
3283 si = &SCRIPT_ITEM(current_SID);
3284 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285 && (
3286# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003287 /* Compare dev/ino when possible, it catches symbolic
3288 * links. Also compare file names, the inode may change
3289 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003290 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003291 && (si->sn_dev == st.st_dev
3292 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003294 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003296 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297 if (current_SID == 0)
3298 {
3299 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003300 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3301 == FAIL)
3302 goto almosttheend;
3303 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003305 ++script_items.ga_len;
3306 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3307# ifdef FEAT_PROFILE
3308 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003309# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003311 si = &SCRIPT_ITEM(current_SID);
3312 si->sn_name = fname_exp;
3313 fname_exp = NULL;
3314# ifdef UNIX
3315 if (stat_ok)
3316 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003317 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003318 si->sn_dev = st.st_dev;
3319 si->sn_ino = st.st_ino;
3320 }
3321 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003322 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003323# endif
3324
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 /* Allocate the local script variables to use for this script. */
3326 new_script_vars(current_SID);
3327 }
3328
Bram Moolenaar05159a02005-02-26 23:04:13 +00003329# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003330 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003331 {
3332 int forceit;
3333
3334 /* Check if we do profiling for this script. */
3335 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3336 {
3337 script_do_profile(si);
3338 si->sn_pr_force = forceit;
3339 }
3340 if (si->sn_prof_on)
3341 {
3342 ++si->sn_pr_count;
3343 profile_start(&si->sn_pr_start);
3344 profile_zero(&si->sn_pr_children);
3345 }
3346 }
3347# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348#endif
3349
3350 /*
3351 * Call do_cmdline, which will call getsourceline() to get the lines.
3352 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003353 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003354 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003356
3357#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003358 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003359 {
3360 /* Get "si" again, "script_items" may have been reallocated. */
3361 si = &SCRIPT_ITEM(current_SID);
3362 if (si->sn_prof_on)
3363 {
3364 profile_end(&si->sn_pr_start);
3365 profile_sub_wait(&wait_start, &si->sn_pr_start);
3366 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003367 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3368 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003369 }
3370 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371#endif
3372
3373 if (got_int)
3374 EMSG(_(e_interr));
3375 sourcing_name = save_sourcing_name;
3376 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 if (p_verbose > 1)
3378 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003379 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003380 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003382 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003383 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384 }
3385#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003386 if (time_fd != NULL)
3387 {
3388 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3389 time_msg((char *)IObuff, &tv_start);
3390 time_pop(&tv_rel);
3391 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392#endif
3393
3394#ifdef FEAT_EVAL
3395 /*
3396 * After a "finish" in debug mode, need to break at first command of next
3397 * sourced file.
3398 */
3399 if (save_debug_break_level > ex_nesting_level
3400 && debug_break_level == ex_nesting_level)
3401 ++debug_break_level;
3402#endif
3403
Bram Moolenaar05159a02005-02-26 23:04:13 +00003404#ifdef FEAT_EVAL
3405almosttheend:
3406 current_SID = save_current_SID;
3407 restore_funccal(save_funccalp);
3408# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003409 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003410 prof_child_exit(&wait_start); /* leaving a child now */
3411# endif
3412#endif
3413 fclose(cookie.fp);
3414 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003415 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003416#ifdef FEAT_MBYTE
3417 convert_setup(&cookie.conv, NULL, NULL);
3418#endif
3419
Bram Moolenaar071d4272004-06-13 20:20:40 +00003420theend:
3421 vim_free(fname_exp);
3422 return retval;
3423}
3424
3425#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003426
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427/*
3428 * ":scriptnames"
3429 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003430 void
3431ex_scriptnames(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003432 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003433{
3434 int i;
3435
Bram Moolenaar05159a02005-02-26 23:04:13 +00003436 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3437 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003438 {
3439 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3440 NameBuff, MAXPATHL, TRUE);
3441 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003442 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003443}
3444
3445# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3446/*
3447 * Fix slashes in the list of script names for 'shellslash'.
3448 */
3449 void
3450scriptnames_slash_adjust()
3451{
3452 int i;
3453
Bram Moolenaar05159a02005-02-26 23:04:13 +00003454 for (i = 1; i <= script_items.ga_len; ++i)
3455 if (SCRIPT_ITEM(i).sn_name != NULL)
3456 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457}
3458# endif
3459
3460/*
3461 * Get a pointer to a script name. Used for ":verbose set".
3462 */
3463 char_u *
3464get_scriptname(id)
3465 scid_T id;
3466{
3467 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003468 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003470 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003472 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003474 return (char_u *)_("environment variable");
3475 if (id == SID_ERROR)
3476 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003477 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003479
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003480# if defined(EXITFREE) || defined(PROTO)
3481 void
3482free_scriptnames()
3483{
3484 int i;
3485
3486 for (i = script_items.ga_len; i > 0; --i)
3487 vim_free(SCRIPT_ITEM(i).sn_name);
3488 ga_clear(&script_items);
3489}
3490# endif
3491
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492#endif
3493
3494#if defined(USE_CR) || defined(PROTO)
3495
3496# if defined(__MSL__) && (__MSL__ >= 22)
3497/*
3498 * Newer version of the Metrowerks library handle DOS and UNIX files
3499 * without help.
3500 * Test with earlier versions, MSL 2.2 is the library supplied with
3501 * Codewarrior Pro 2.
3502 */
3503 char *
3504fgets_cr(s, n, stream)
3505 char *s;
3506 int n;
3507 FILE *stream;
3508{
3509 return fgets(s, n, stream);
3510}
3511# else
3512/*
3513 * Version of fgets() which also works for lines ending in a <CR> only
3514 * (Macintosh format).
3515 * For older versions of the Metrowerks library.
3516 * At least CodeWarrior 9 needed this code.
3517 */
3518 char *
3519fgets_cr(s, n, stream)
3520 char *s;
3521 int n;
3522 FILE *stream;
3523{
3524 int c = 0;
3525 int char_read = 0;
3526
3527 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3528 {
3529 c = fgetc(stream);
3530 s[char_read++] = c;
3531 /* If the file is in DOS format, we need to skip a NL after a CR. I
3532 * thought it was the other way around, but this appears to work... */
3533 if (c == '\n')
3534 {
3535 c = fgetc(stream);
3536 if (c != '\r')
3537 ungetc(c, stream);
3538 }
3539 }
3540
3541 s[char_read] = 0;
3542 if (char_read == 0)
3543 return NULL;
3544
3545 if (feof(stream) && char_read == 1)
3546 return NULL;
3547
3548 return s;
3549}
3550# endif
3551#endif
3552
3553/*
3554 * Get one full line from a sourced file.
3555 * Called by do_cmdline() when it's called from do_source().
3556 *
3557 * Return a pointer to the line in allocated memory.
3558 * Return NULL for end-of-file or some error.
3559 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 char_u *
3561getsourceline(c, cookie, indent)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003562 int c UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003563 void *cookie;
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003564 int indent UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565{
3566 struct source_cookie *sp = (struct source_cookie *)cookie;
3567 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003568 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569
3570#ifdef FEAT_EVAL
3571 /* If breakpoints have been added/deleted need to check for it. */
3572 if (sp->dbg_tick < debug_tick)
3573 {
3574 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3575 sp->dbg_tick = debug_tick;
3576 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003577# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003578 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003579 script_line_end();
3580# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003581#endif
3582 /*
3583 * Get current line. If there is a read-ahead line, use it, otherwise get
3584 * one now.
3585 */
3586 if (sp->finished)
3587 line = NULL;
3588 else if (sp->nextline == NULL)
3589 line = get_one_sourceline(sp);
3590 else
3591 {
3592 line = sp->nextline;
3593 sp->nextline = NULL;
3594 ++sourcing_lnum;
3595 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003596#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003597 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003598 script_line_start();
3599#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600
3601 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3602 * contain the 'C' flag. */
3603 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3604 {
3605 /* compensate for the one line read-ahead */
3606 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003607
3608 /* Get the next line and concatenate it when it starts with a
3609 * backslash. We always need to read the next line, keep it in
3610 * sp->nextline. */
3611 sp->nextline = get_one_sourceline(sp);
3612 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003614 garray_T ga;
3615
Bram Moolenaarb549a732012-02-22 18:29:33 +01003616 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003617 ga_concat(&ga, line);
3618 ga_concat(&ga, p + 1);
3619 for (;;)
3620 {
3621 vim_free(sp->nextline);
3622 sp->nextline = get_one_sourceline(sp);
3623 if (sp->nextline == NULL)
3624 break;
3625 p = skipwhite(sp->nextline);
3626 if (*p != '\\')
3627 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003628 /* Adjust the growsize to the current length to speed up
3629 * concatenating many lines. */
3630 if (ga.ga_len > 400)
3631 {
3632 if (ga.ga_len > 8000)
3633 ga.ga_growsize = 8000;
3634 else
3635 ga.ga_growsize = ga.ga_len;
3636 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003637 ga_concat(&ga, p + 1);
3638 }
3639 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003640 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003641 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642 }
3643 }
3644
3645#ifdef FEAT_MBYTE
3646 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3647 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003648 char_u *s;
3649
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650 /* Convert the encoding of the script line. */
3651 s = string_convert(&sp->conv, line, NULL);
3652 if (s != NULL)
3653 {
3654 vim_free(line);
3655 line = s;
3656 }
3657 }
3658#endif
3659
3660#ifdef FEAT_EVAL
3661 /* Did we encounter a breakpoint? */
3662 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3663 {
3664 dbg_breakpoint(sp->fname, sourcing_lnum);
3665 /* Find next breakpoint. */
3666 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3667 sp->dbg_tick = debug_tick;
3668 }
3669#endif
3670
3671 return line;
3672}
3673
3674 static char_u *
3675get_one_sourceline(sp)
3676 struct source_cookie *sp;
3677{
3678 garray_T ga;
3679 int len;
3680 int c;
3681 char_u *buf;
3682#ifdef USE_CRNL
3683 int has_cr; /* CR-LF found */
3684#endif
3685#ifdef USE_CR
3686 char_u *scan;
3687#endif
3688 int have_read = FALSE;
3689
3690 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003691 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003692
3693 /*
3694 * Loop until there is a finished line (or end-of-file).
3695 */
3696 sourcing_lnum++;
3697 for (;;)
3698 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003699 /* make room to read at least 120 (more) characters */
3700 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 break;
3702 buf = (char_u *)ga.ga_data;
3703
3704#ifdef USE_CR
3705 if (sp->fileformat == EOL_MAC)
3706 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003707 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3708 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003709 break;
3710 }
3711 else
3712#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003713 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3714 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003715 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003716 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003717#ifdef USE_CRNL
3718 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3719 * CTRL-Z by its own, or after a NL. */
3720 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3721 && sp->fileformat == EOL_DOS
3722 && buf[len - 1] == Ctrl_Z)
3723 {
3724 buf[len - 1] = NUL;
3725 break;
3726 }
3727#endif
3728
3729#ifdef USE_CR
3730 /* If the read doesn't stop on a new line, and there's
3731 * some CR then we assume a Mac format */
3732 if (sp->fileformat == EOL_UNKNOWN)
3733 {
3734 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3735 sp->fileformat = EOL_MAC;
3736 else
3737 sp->fileformat = EOL_UNIX;
3738 }
3739
3740 if (sp->fileformat == EOL_MAC)
3741 {
3742 scan = vim_strchr(buf, '\r');
3743
3744 if (scan != NULL)
3745 {
3746 *scan = '\n';
3747 if (*(scan + 1) != 0)
3748 {
3749 *(scan + 1) = 0;
3750 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3751 }
3752 }
3753 len = STRLEN(buf);
3754 }
3755#endif
3756
3757 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758 ga.ga_len = len;
3759
3760 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003761 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762 continue;
3763
3764 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3765 {
3766#ifdef USE_CRNL
3767 has_cr = (len >= 2 && buf[len - 2] == '\r');
3768 if (sp->fileformat == EOL_UNKNOWN)
3769 {
3770 if (has_cr)
3771 sp->fileformat = EOL_DOS;
3772 else
3773 sp->fileformat = EOL_UNIX;
3774 }
3775
3776 if (sp->fileformat == EOL_DOS)
3777 {
3778 if (has_cr) /* replace trailing CR */
3779 {
3780 buf[len - 2] = '\n';
3781 --len;
3782 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783 }
3784 else /* lines like ":map xx yy^M" will have failed */
3785 {
3786 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003787 {
3788 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00003790 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791 sp->error = TRUE;
3792 sp->fileformat = EOL_UNIX;
3793 }
3794 }
3795#endif
3796 /* The '\n' is escaped if there is an odd number of ^V's just
3797 * before it, first set "c" just before the 'V's and then check
3798 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
3799 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
3800 ;
3801 if ((len & 1) != (c & 1)) /* escaped NL, read more */
3802 {
3803 sourcing_lnum++;
3804 continue;
3805 }
3806
3807 buf[len - 1] = NUL; /* remove the NL */
3808 }
3809
3810 /*
3811 * Check for ^C here now and then, so recursive :so can be broken.
3812 */
3813 line_breakcheck();
3814 break;
3815 }
3816
3817 if (have_read)
3818 return (char_u *)ga.ga_data;
3819
3820 vim_free(ga.ga_data);
3821 return NULL;
3822}
3823
Bram Moolenaar05159a02005-02-26 23:04:13 +00003824#if defined(FEAT_PROFILE) || defined(PROTO)
3825/*
3826 * Called when starting to read a script line.
3827 * "sourcing_lnum" must be correct!
3828 * When skipping lines it may not actually be executed, but we won't find out
3829 * until later and we need to store the time now.
3830 */
3831 void
3832script_line_start()
3833{
3834 scriptitem_T *si;
3835 sn_prl_T *pp;
3836
3837 if (current_SID <= 0 || current_SID > script_items.ga_len)
3838 return;
3839 si = &SCRIPT_ITEM(current_SID);
3840 if (si->sn_prof_on && sourcing_lnum >= 1)
3841 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00003842 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00003843 * here isn't counted. */
3844 ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
3845 si->sn_prl_idx = sourcing_lnum - 1;
3846 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
3847 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
3848 {
3849 /* Zero counters for a line that was not used before. */
3850 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
3851 pp->snp_count = 0;
3852 profile_zero(&pp->sn_prl_total);
3853 profile_zero(&pp->sn_prl_self);
3854 ++si->sn_prl_ga.ga_len;
3855 }
3856 si->sn_prl_execed = FALSE;
3857 profile_start(&si->sn_prl_start);
3858 profile_zero(&si->sn_prl_children);
3859 profile_get_wait(&si->sn_prl_wait);
3860 }
3861}
3862
3863/*
3864 * Called when actually executing a function line.
3865 */
3866 void
3867script_line_exec()
3868{
3869 scriptitem_T *si;
3870
3871 if (current_SID <= 0 || current_SID > script_items.ga_len)
3872 return;
3873 si = &SCRIPT_ITEM(current_SID);
3874 if (si->sn_prof_on && si->sn_prl_idx >= 0)
3875 si->sn_prl_execed = TRUE;
3876}
3877
3878/*
3879 * Called when done with a function line.
3880 */
3881 void
3882script_line_end()
3883{
3884 scriptitem_T *si;
3885 sn_prl_T *pp;
3886
3887 if (current_SID <= 0 || current_SID > script_items.ga_len)
3888 return;
3889 si = &SCRIPT_ITEM(current_SID);
3890 if (si->sn_prof_on && si->sn_prl_idx >= 0
3891 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
3892 {
3893 if (si->sn_prl_execed)
3894 {
3895 pp = &PRL_ITEM(si, si->sn_prl_idx);
3896 ++pp->snp_count;
3897 profile_end(&si->sn_prl_start);
3898 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003899 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003900 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
3901 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003902 }
3903 si->sn_prl_idx = -1;
3904 }
3905}
3906#endif
3907
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908/*
3909 * ":scriptencoding": Set encoding conversion for a sourced script.
3910 * Without the multi-byte feature it's simply ignored.
3911 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912 void
3913ex_scriptencoding(eap)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00003914 exarg_T *eap UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915{
3916#ifdef FEAT_MBYTE
3917 struct source_cookie *sp;
3918 char_u *name;
3919
3920 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
3921 {
3922 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
3923 return;
3924 }
3925
3926 if (*eap->arg != NUL)
3927 {
3928 name = enc_canonize(eap->arg);
3929 if (name == NULL) /* out of memory */
3930 return;
3931 }
3932 else
3933 name = eap->arg;
3934
3935 /* Setup for conversion from the specified encoding to 'encoding'. */
3936 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
3937 convert_setup(&sp->conv, name, p_enc);
3938
3939 if (name != eap->arg)
3940 vim_free(name);
3941#endif
3942}
3943
3944#if defined(FEAT_EVAL) || defined(PROTO)
3945/*
3946 * ":finish": Mark a sourced file as finished.
3947 */
3948 void
3949ex_finish(eap)
3950 exarg_T *eap;
3951{
3952 if (getline_equal(eap->getline, eap->cookie, getsourceline))
3953 do_finish(eap, FALSE);
3954 else
3955 EMSG(_("E168: :finish used outside of a sourced file"));
3956}
3957
3958/*
3959 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
3960 * Also called for a pending finish at the ":endtry" or after returning from
3961 * an extra do_cmdline(). "reanimate" is used in the latter case.
3962 */
3963 void
3964do_finish(eap, reanimate)
3965 exarg_T *eap;
3966 int reanimate;
3967{
3968 int idx;
3969
3970 if (reanimate)
3971 ((struct source_cookie *)getline_cookie(eap->getline,
3972 eap->cookie))->finished = FALSE;
3973
3974 /*
3975 * Cleanup (and inactivate) conditionals, but stop when a try conditional
3976 * not in its finally clause (which then is to be executed next) is found.
3977 * In this case, make the ":finish" pending for execution at the ":endtry".
3978 * Otherwise, finish normally.
3979 */
3980 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
3981 if (idx >= 0)
3982 {
3983 eap->cstack->cs_pending[idx] = CSTP_FINISH;
3984 report_make_pending(CSTP_FINISH, NULL);
3985 }
3986 else
3987 ((struct source_cookie *)getline_cookie(eap->getline,
3988 eap->cookie))->finished = TRUE;
3989}
3990
3991
3992/*
3993 * Return TRUE when a sourced file had the ":finish" command: Don't give error
3994 * message for missing ":endif".
3995 * Return FALSE when not sourcing a file.
3996 */
3997 int
Bram Moolenaar89d40322006-08-29 15:30:07 +00003998source_finished(fgetline, cookie)
3999 char_u *(*fgetline) __ARGS((int, void *, int));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 void *cookie;
4001{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004002 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004004 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004005}
4006#endif
4007
4008#if defined(FEAT_LISTCMDS) || defined(PROTO)
4009/*
4010 * ":checktime [buffer]"
4011 */
4012 void
4013ex_checktime(eap)
4014 exarg_T *eap;
4015{
4016 buf_T *buf;
4017 int save_no_check_timestamps = no_check_timestamps;
4018
4019 no_check_timestamps = 0;
4020 if (eap->addr_count == 0) /* default is all buffers */
4021 check_timestamps(FALSE);
4022 else
4023 {
4024 buf = buflist_findnr((int)eap->line2);
4025 if (buf != NULL) /* cannot happen? */
4026 (void)buf_check_timestamp(buf, FALSE);
4027 }
4028 no_check_timestamps = save_no_check_timestamps;
4029}
4030#endif
4031
Bram Moolenaar071d4272004-06-13 20:20:40 +00004032#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4033 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004034# define HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004035static char *get_locale_val __ARGS((int what));
4036
4037 static char *
4038get_locale_val(what)
4039 int what;
4040{
4041 char *loc;
4042
4043 /* Obtain the locale value from the libraries. For DJGPP this is
4044 * redefined and it doesn't use the arguments. */
4045 loc = setlocale(what, NULL);
4046
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004047# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048 if (loc != NULL)
4049 {
4050 char_u *p;
4051
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004052 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4053 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 p = vim_strchr(loc, '=');
4055 if (p != NULL)
4056 {
4057 loc = ++p;
4058 while (*p != NUL) /* remove trailing newline */
4059 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004060 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004061 {
4062 *p = NUL;
4063 break;
4064 }
4065 ++p;
4066 }
4067 }
4068 }
4069# endif
4070
4071 return loc;
4072}
4073#endif
4074
4075
4076#ifdef WIN32
4077/*
4078 * On MS-Windows locale names are strings like "German_Germany.1252", but
4079 * gettext expects "de". Try to translate one into another here for a few
4080 * supported languages.
4081 */
4082 static char_u *
4083gettext_lang(char_u *name)
4084{
4085 int i;
4086 static char *(mtable[]) = {
4087 "afrikaans", "af",
4088 "czech", "cs",
4089 "dutch", "nl",
4090 "german", "de",
4091 "english_united kingdom", "en_GB",
4092 "spanish", "es",
4093 "french", "fr",
4094 "italian", "it",
4095 "japanese", "ja",
4096 "korean", "ko",
4097 "norwegian", "no",
4098 "polish", "pl",
4099 "russian", "ru",
4100 "slovak", "sk",
4101 "swedish", "sv",
4102 "ukrainian", "uk",
4103 "chinese_china", "zh_CN",
4104 "chinese_taiwan", "zh_TW",
4105 NULL};
4106
4107 for (i = 0; mtable[i] != NULL; i += 2)
4108 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
4109 return mtable[i + 1];
4110 return name;
4111}
4112#endif
4113
4114#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4115/*
4116 * Obtain the current messages language. Used to set the default for
4117 * 'helplang'. May return NULL or an empty string.
4118 */
4119 char_u *
4120get_mess_lang()
4121{
4122 char_u *p;
4123
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004124# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125# if defined(LC_MESSAGES)
4126 p = (char_u *)get_locale_val(LC_MESSAGES);
4127# else
4128 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004129 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4130 * and LC_MONETARY may be set differently for a Japanese working in the
4131 * US. */
4132 p = (char_u *)get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133# endif
4134# else
4135 p = mch_getenv((char_u *)"LC_ALL");
4136 if (p == NULL || *p == NUL)
4137 {
4138 p = mch_getenv((char_u *)"LC_MESSAGES");
4139 if (p == NULL || *p == NUL)
4140 p = mch_getenv((char_u *)"LANG");
4141 }
4142# endif
4143# ifdef WIN32
4144 p = gettext_lang(p);
4145# endif
4146 return p;
4147}
4148#endif
4149
Bram Moolenaardef9e822004-12-31 20:58:58 +00004150/* Complicated #if; matches with where get_mess_env() is used below. */
4151#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4152 && defined(LC_MESSAGES))) \
4153 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4154 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4155 && !defined(LC_MESSAGES))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156static char_u *get_mess_env __ARGS((void));
4157
4158/*
4159 * Get the language used for messages from the environment.
4160 */
4161 static char_u *
4162get_mess_env()
4163{
4164 char_u *p;
4165
4166 p = mch_getenv((char_u *)"LC_ALL");
4167 if (p == NULL || *p == NUL)
4168 {
4169 p = mch_getenv((char_u *)"LC_MESSAGES");
4170 if (p == NULL || *p == NUL)
4171 {
4172 p = mch_getenv((char_u *)"LANG");
4173 if (p != NULL && VIM_ISDIGIT(*p))
4174 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004175# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 if (p == NULL || *p == NUL)
4177 p = (char_u *)get_locale_val(LC_CTYPE);
4178# endif
4179 }
4180 }
4181 return p;
4182}
4183#endif
4184
4185#if defined(FEAT_EVAL) || defined(PROTO)
4186
4187/*
4188 * Set the "v:lang" variable according to the current locale setting.
4189 * Also do "v:lc_time"and "v:ctype".
4190 */
4191 void
4192set_lang_var()
4193{
4194 char_u *loc;
4195
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004196# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004197 loc = (char_u *)get_locale_val(LC_CTYPE);
4198# else
4199 /* setlocale() not supported: use the default value */
4200 loc = (char_u *)"C";
4201# endif
4202 set_vim_var_string(VV_CTYPE, loc, -1);
4203
4204 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4205 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004206# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207 loc = (char_u *)get_locale_val(LC_MESSAGES);
4208# else
4209 loc = get_mess_env();
4210# endif
4211 set_vim_var_string(VV_LANG, loc, -1);
4212
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004213# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 loc = (char_u *)get_locale_val(LC_TIME);
4215# endif
4216 set_vim_var_string(VV_LC_TIME, loc, -1);
4217}
4218#endif
4219
4220#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4221 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4222/*
4223 * ":language": Set the language (locale).
4224 */
4225 void
4226ex_language(eap)
4227 exarg_T *eap;
4228{
4229 char *loc;
4230 char_u *p;
4231 char_u *name;
4232 int what = LC_ALL;
4233 char *whatstr = "";
4234#ifdef LC_MESSAGES
4235# define VIM_LC_MESSAGES LC_MESSAGES
4236#else
4237# define VIM_LC_MESSAGES 6789
4238#endif
4239
4240 name = eap->arg;
4241
4242 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4243 * Allow abbreviation, but require at least 3 characters to avoid
4244 * confusion with a two letter language name "me" or "ct". */
4245 p = skiptowhite(eap->arg);
4246 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4247 {
4248 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4249 {
4250 what = VIM_LC_MESSAGES;
4251 name = skipwhite(p);
4252 whatstr = "messages ";
4253 }
4254 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4255 {
4256 what = LC_CTYPE;
4257 name = skipwhite(p);
4258 whatstr = "ctype ";
4259 }
4260 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4261 {
4262 what = LC_TIME;
4263 name = skipwhite(p);
4264 whatstr = "time ";
4265 }
4266 }
4267
4268 if (*name == NUL)
4269 {
4270#ifndef LC_MESSAGES
4271 if (what == VIM_LC_MESSAGES)
4272 p = get_mess_env();
4273 else
4274#endif
4275 p = (char_u *)setlocale(what, NULL);
4276 if (p == NULL || *p == NUL)
4277 p = (char_u *)"Unknown";
4278 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4279 }
4280 else
4281 {
4282#ifndef LC_MESSAGES
4283 if (what == VIM_LC_MESSAGES)
4284 loc = "";
4285 else
4286#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004287 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004289#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4290 /* Make sure strtod() uses a decimal point, not a comma. */
4291 setlocale(LC_NUMERIC, "C");
4292#endif
4293 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294 if (loc == NULL)
4295 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4296 else
4297 {
4298#ifdef HAVE_NL_MSG_CAT_CNTR
4299 /* Need to do this for GNU gettext, otherwise cached translations
4300 * will be used again. */
4301 extern int _nl_msg_cat_cntr;
4302
4303 ++_nl_msg_cat_cntr;
4304#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004305 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4307
4308 if (what != LC_TIME)
4309 {
4310 /* Tell gettext() what to translate to. It apparently doesn't
4311 * use the currently effective locale. Also do this when
4312 * FEAT_GETTEXT isn't defined, so that shell commands use this
4313 * value. */
4314 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004315 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004317
4318 /* Clear $LANGUAGE because GNU gettext uses it. */
4319 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004320# ifdef WIN32
4321 /* Apparently MS-Windows printf() may cause a crash when
4322 * we give it 8-bit text while it's expecting text in the
4323 * current locale. This call avoids that. */
4324 setlocale(LC_CTYPE, "C");
4325# endif
4326 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327 if (what != LC_CTYPE)
4328 {
4329 char_u *mname;
4330#ifdef WIN32
4331 mname = gettext_lang(name);
4332#else
4333 mname = name;
4334#endif
4335 vim_setenv((char_u *)"LC_MESSAGES", mname);
4336#ifdef FEAT_MULTI_LANG
4337 set_helplang_default(mname);
4338#endif
4339 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340 }
4341
4342# ifdef FEAT_EVAL
4343 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4344 set_lang_var();
4345# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004346# ifdef FEAT_TITLE
4347 maketitle();
4348# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 }
4350 }
4351}
4352
4353# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004354
4355static char_u **locales = NULL; /* Array of all available locales */
4356static int did_init_locales = FALSE;
4357
4358static void init_locales __ARGS((void));
4359static char_u **find_locales __ARGS((void));
4360
4361/*
4362 * Lazy initialization of all available locales.
4363 */
4364 static void
4365init_locales()
4366{
4367 if (!did_init_locales)
4368 {
4369 did_init_locales = TRUE;
4370 locales = find_locales();
4371 }
4372}
4373
4374/* Return an array of strings for all available locales + NULL for the
4375 * last element. Return NULL in case of error. */
4376 static char_u **
4377find_locales()
4378{
4379 garray_T locales_ga;
4380 char_u *loc;
4381
4382 /* Find all available locales by running command "locale -a". If this
4383 * doesn't work we won't have completion. */
4384 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004385 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004386 if (locale_a == NULL)
4387 return NULL;
4388 ga_init2(&locales_ga, sizeof(char_u *), 20);
4389
4390 /* Transform locale_a string where each locale is separated by "\n"
4391 * into an array of locale strings. */
4392 loc = (char_u *)strtok((char *)locale_a, "\n");
4393
4394 while (loc != NULL)
4395 {
4396 if (ga_grow(&locales_ga, 1) == FAIL)
4397 break;
4398 loc = vim_strsave(loc);
4399 if (loc == NULL)
4400 break;
4401
4402 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4403 loc = (char_u *)strtok(NULL, "\n");
4404 }
4405 vim_free(locale_a);
4406 if (ga_grow(&locales_ga, 1) == FAIL)
4407 {
4408 ga_clear(&locales_ga);
4409 return NULL;
4410 }
4411 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4412 return (char_u **)locales_ga.ga_data;
4413}
4414
4415# if defined(EXITFREE) || defined(PROTO)
4416 void
4417free_locales()
4418{
4419 int i;
4420 if (locales != NULL)
4421 {
4422 for (i = 0; locales[i] != NULL; i++)
4423 vim_free(locales[i]);
4424 vim_free(locales);
4425 locales = NULL;
4426 }
4427}
4428# endif
4429
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430/*
4431 * Function given to ExpandGeneric() to obtain the possible arguments of the
4432 * ":language" command.
4433 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004434 char_u *
4435get_lang_arg(xp, idx)
Bram Moolenaar0c094b92009-05-14 20:20:33 +00004436 expand_T *xp UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437 int idx;
4438{
4439 if (idx == 0)
4440 return (char_u *)"messages";
4441 if (idx == 1)
4442 return (char_u *)"ctype";
4443 if (idx == 2)
4444 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004445
4446 init_locales();
4447 if (locales == NULL)
4448 return NULL;
4449 return locales[idx - 3];
4450}
4451
4452/*
4453 * Function given to ExpandGeneric() to obtain the available locales.
4454 */
4455 char_u *
4456get_locales(xp, idx)
4457 expand_T *xp UNUSED;
4458 int idx;
4459{
4460 init_locales();
4461 if (locales == NULL)
4462 return NULL;
4463 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004464}
4465# endif
4466
4467#endif