blob: 3f8c50816c84253d3a92f14bb3b44514448f73d6 [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
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
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. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
134#ifdef FEAT_SNIFF
135 want_sniff_request = 0; /* No K_SNIFF wanted */
136#endif
137
138 if (!debug_did_msg)
139 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
140 if (sourcing_name != NULL)
141 msg(sourcing_name);
142 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000143 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000145 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146
147 /*
148 * Repeat getting a command and executing it.
149 */
150 for (;;)
151 {
152 msg_scroll = TRUE;
153 need_wait_return = FALSE;
154#ifdef FEAT_SNIFF
155 ProcessSniffRequests();
156#endif
157 /* Save the current typeahead buffer and replace it with an empty one.
158 * This makes sure we get input from the user here and don't interfere
159 * with the commands being executed. Reset "ex_normal_busy" to avoid
160 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000161 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162 save_ex_normal_busy = ex_normal_busy;
163 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000165 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000167 typeahead_saved = TRUE;
168 save_ignore_script = ignore_script;
169 ignore_script = TRUE;
170 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000172 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000174 if (typeahead_saved)
175 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000177 ignore_script = save_ignore_script;
178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180
181 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100182 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183 if (cmdline != NULL)
184 {
185 /* If this is a debug command, set "last_cmd".
186 * If not, reset "last_cmd".
187 * For a blank line use previous command. */
188 p = skipwhite(cmdline);
189 if (*p != NUL)
190 {
191 switch (*p)
192 {
193 case 'c': last_cmd = CMD_CONT;
194 tail = "ont";
195 break;
196 case 'n': last_cmd = CMD_NEXT;
197 tail = "ext";
198 break;
199 case 's': last_cmd = CMD_STEP;
200 tail = "tep";
201 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100202 case 'f':
203 last_cmd = 0;
204 if (p[1] == 'r')
205 {
206 last_cmd = CMD_FRAME;
207 tail = "rame";
208 }
209 else
210 {
211 last_cmd = CMD_FINISH;
212 tail = "inish";
213 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214 break;
215 case 'q': last_cmd = CMD_QUIT;
216 tail = "uit";
217 break;
218 case 'i': last_cmd = CMD_INTERRUPT;
219 tail = "nterrupt";
220 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100221 case 'b': last_cmd = CMD_BACKTRACE;
222 if (p[1] == 't')
223 tail = "t";
224 else
225 tail = "acktrace";
226 break;
227 case 'w': last_cmd = CMD_BACKTRACE;
228 tail = "here";
229 break;
230 case 'u': last_cmd = CMD_UP;
231 tail = "p";
232 break;
233 case 'd': last_cmd = CMD_DOWN;
234 tail = "own";
235 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 default: last_cmd = 0;
237 }
238 if (last_cmd != 0)
239 {
240 /* Check that the tail matches. */
241 ++p;
242 while (*p != NUL && *p == *tail)
243 {
244 ++p;
245 ++tail;
246 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100247 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000248 last_cmd = 0;
249 }
250 }
251
252 if (last_cmd != 0)
253 {
254 /* Execute debug command: decided where to break next and
255 * return. */
256 switch (last_cmd)
257 {
258 case CMD_CONT:
259 debug_break_level = -1;
260 break;
261 case CMD_NEXT:
262 debug_break_level = ex_nesting_level;
263 break;
264 case CMD_STEP:
265 debug_break_level = 9999;
266 break;
267 case CMD_FINISH:
268 debug_break_level = ex_nesting_level - 1;
269 break;
270 case CMD_QUIT:
271 got_int = TRUE;
272 debug_break_level = -1;
273 break;
274 case CMD_INTERRUPT:
275 got_int = TRUE;
276 debug_break_level = 9999;
277 /* Do not repeat ">interrupt" cmd, continue stepping. */
278 last_cmd = CMD_STEP;
279 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100280 case CMD_BACKTRACE:
281 do_showbacktrace(cmd);
282 continue;
283 case CMD_FRAME:
284 if (*p == NUL)
285 {
286 do_showbacktrace(cmd);
287 }
288 else
289 {
290 p = skipwhite(p);
291 do_setdebugtracelevel(p);
292 }
293 continue;
294 case CMD_UP:
295 debug_backtrace_level++;
296 do_checkbacktracelevel();
297 continue;
298 case CMD_DOWN:
299 debug_backtrace_level--;
300 do_checkbacktracelevel();
301 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100303 /* Going out reset backtrace_level */
304 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 break;
306 }
307
308 /* don't debug this command */
309 n = debug_break_level;
310 debug_break_level = -1;
311 (void)do_cmdline(cmdline, getexline, NULL,
312 DOCMD_VERBOSE|DOCMD_EXCRESET);
313 debug_break_level = n;
314
315 vim_free(cmdline);
316 }
317 lines_left = Rows - 1;
318 }
319 vim_free(cmdline);
320
321 --RedrawingDisabled;
322 --no_wait_return;
323 redraw_all_later(NOT_VALID);
324 need_wait_return = FALSE;
325 msg_scroll = save_msg_scroll;
326 lines_left = Rows - 1;
327 State = save_State;
328 did_emsg = save_did_emsg;
329 cmd_silent = save_cmd_silent;
330 msg_silent = save_msg_silent;
331 emsg_silent = save_emsg_silent;
332 redir_off = save_redir_off;
333
334 /* Only print the message again when typing a command before coming back
335 * here. */
336 debug_did_msg = TRUE;
337}
338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 static int
340get_maxbacktrace_level(void)
341{
342 char *p, *q;
343 int maxbacktrace = 1;
344
345 maxbacktrace = 0;
346 if (sourcing_name != NULL)
347 {
348 p = (char *)sourcing_name;
349 while ((q = strstr(p, "..")) != NULL)
350 {
351 p = q + 2;
352 maxbacktrace++;
353 }
354 }
355 return maxbacktrace;
356}
357
358 static void
359do_setdebugtracelevel(char_u *arg)
360{
361 int level;
362
363 level = atoi((char *)arg);
364 if (*arg == '+' || level < 0)
365 debug_backtrace_level += level;
366 else
367 debug_backtrace_level = level;
368
369 do_checkbacktracelevel();
370}
371
372 static void
373do_checkbacktracelevel(void)
374{
375 if (debug_backtrace_level < 0)
376 {
377 debug_backtrace_level = 0;
378 MSG(_("frame is zero"));
379 }
380 else
381 {
382 int max = get_maxbacktrace_level();
383
384 if (debug_backtrace_level > max)
385 {
386 debug_backtrace_level = max;
387 smsg((char_u *)_("frame at highest level: %d"), max);
388 }
389 }
390}
391
392 static void
393do_showbacktrace(char_u *cmd)
394{
395 char *cur;
396 char *next;
397 int i = 0;
398 int max = get_maxbacktrace_level();
399
400 if (sourcing_name != NULL)
401 {
402 cur = (char *)sourcing_name;
403 while (!got_int)
404 {
405 next = strstr(cur, "..");
406 if (next != NULL)
407 *next = NUL;
408 if (i == max - debug_backtrace_level)
409 smsg((char_u *)"->%d %s", max - i, cur);
410 else
411 smsg((char_u *)" %d %s", max - i, cur);
412 ++i;
413 if (next == NULL)
414 break;
415 *next = '.';
416 cur = next + 2;
417 }
418 }
419 if (sourcing_lnum != 0)
420 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
421 else
422 smsg((char_u *)_("cmd: %s"), cmd);
423}
424
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425/*
426 * ":debug".
427 */
428 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100429ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430{
431 int debug_break_level_save = debug_break_level;
432
433 debug_break_level = 9999;
434 do_cmdline_cmd(eap->arg);
435 debug_break_level = debug_break_level_save;
436}
437
438static char_u *debug_breakpoint_name = NULL;
439static linenr_T debug_breakpoint_lnum;
440
441/*
442 * When debugging or a breakpoint is set on a skipped command, no debug prompt
443 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
444 * debug_skipped_name is then set to the source name in the breakpoint case. If
445 * a skipped command decides itself that a debug prompt should be displayed, it
446 * can do so by calling dbg_check_skipped().
447 */
448static int debug_skipped;
449static char_u *debug_skipped_name;
450
451/*
452 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
453 * at or below the break level. But only when the line is actually
454 * executed. Return TRUE and set breakpoint_name for skipped commands that
455 * decide to execute something themselves.
456 * Called from do_one_cmd() before executing a command.
457 */
458 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100459dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460{
461 char_u *p;
462
463 debug_skipped = FALSE;
464 if (debug_breakpoint_name != NULL)
465 {
466 if (!eap->skip)
467 {
468 /* replace K_SNR with "<SNR>" */
469 if (debug_breakpoint_name[0] == K_SPECIAL
470 && debug_breakpoint_name[1] == KS_EXTRA
471 && debug_breakpoint_name[2] == (int)KE_SNR)
472 p = (char_u *)"<SNR>";
473 else
474 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000475 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
476 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000477 debug_breakpoint_name + (*p == NUL ? 0 : 3),
478 (long)debug_breakpoint_lnum);
479 debug_breakpoint_name = NULL;
480 do_debug(eap->cmd);
481 }
482 else
483 {
484 debug_skipped = TRUE;
485 debug_skipped_name = debug_breakpoint_name;
486 debug_breakpoint_name = NULL;
487 }
488 }
489 else if (ex_nesting_level <= debug_break_level)
490 {
491 if (!eap->skip)
492 do_debug(eap->cmd);
493 else
494 {
495 debug_skipped = TRUE;
496 debug_skipped_name = NULL;
497 }
498 }
499}
500
501/*
502 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
503 * set. Return TRUE when the debug mode is entered this time.
504 */
505 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100506dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507{
508 int prev_got_int;
509
510 if (debug_skipped)
511 {
512 /*
513 * Save the value of got_int and reset it. We don't want a previous
514 * interruption cause flushing the input buffer.
515 */
516 prev_got_int = got_int;
517 got_int = FALSE;
518 debug_breakpoint_name = debug_skipped_name;
519 /* eap->skip is TRUE */
520 eap->skip = FALSE;
521 (void)dbg_check_breakpoint(eap);
522 eap->skip = TRUE;
523 got_int |= prev_got_int;
524 return TRUE;
525 }
526 return FALSE;
527}
528
529/*
530 * The list of breakpoints: dbg_breakp.
531 * This is a grow-array of structs.
532 */
533struct debuggy
534{
535 int dbg_nr; /* breakpoint number */
536 int dbg_type; /* DBG_FUNC or DBG_FILE */
537 char_u *dbg_name; /* function or file name */
538 regprog_T *dbg_prog; /* regexp program */
539 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000540 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541};
542
543static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000544#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
545#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546static int last_breakp = 0; /* nr of last defined breakpoint */
547
Bram Moolenaar05159a02005-02-26 23:04:13 +0000548#ifdef FEAT_PROFILE
549/* Profiling uses file and func names similar to breakpoints. */
550static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
551#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552#define DBG_FUNC 1
553#define DBG_FILE 2
554
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100555static int dbg_parsearg(char_u *arg, garray_T *gap);
556static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557
558/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000559 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
560 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
561 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562 * Returns FAIL for failure.
563 */
564 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100565dbg_parsearg(
566 char_u *arg,
567 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568{
569 char_u *p = arg;
570 char_u *q;
571 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000572 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573
Bram Moolenaar05159a02005-02-26 23:04:13 +0000574 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577
578 /* Find "func" or "file". */
579 if (STRNCMP(p, "func", 4) == 0)
580 bp->dbg_type = DBG_FUNC;
581 else if (STRNCMP(p, "file", 4) == 0)
582 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000583 else if (
584#ifdef FEAT_PROFILE
585 gap != &prof_ga &&
586#endif
587 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000588 {
589 if (curbuf->b_ffname == NULL)
590 {
591 EMSG(_(e_noname));
592 return FAIL;
593 }
594 bp->dbg_type = DBG_FILE;
595 here = TRUE;
596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 else
598 {
599 EMSG2(_(e_invarg2), p);
600 return FAIL;
601 }
602 p = skipwhite(p + 4);
603
604 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000605 if (here)
606 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000607 else if (
608#ifdef FEAT_PROFILE
609 gap != &prof_ga &&
610#endif
611 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 {
613 bp->dbg_lnum = getdigits(&p);
614 p = skipwhite(p);
615 }
616 else
617 bp->dbg_lnum = 0;
618
619 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000620 if ((!here && *p == NUL)
621 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
623 {
624 EMSG2(_(e_invarg2), arg);
625 return FAIL;
626 }
627
628 if (bp->dbg_type == DBG_FUNC)
629 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000630 else if (here)
631 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 else
633 {
634 /* Expand the file name in the same way as do_source(). This means
635 * doing it twice, so that $DIR/file gets expanded when $DIR is
636 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 if (q == NULL)
639 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 vim_free(q);
642 if (p == NULL)
643 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000644 if (*p != '*')
645 {
646 bp->dbg_name = fix_fname(p);
647 vim_free(p);
648 }
649 else
650 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 }
652
653 if (bp->dbg_name == NULL)
654 return FAIL;
655 return OK;
656}
657
658/*
659 * ":breakadd".
660 */
661 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100662ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663{
664 struct debuggy *bp;
665 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000666 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667
Bram Moolenaar05159a02005-02-26 23:04:13 +0000668 gap = &dbg_breakp;
669#ifdef FEAT_PROFILE
670 if (eap->cmdidx == CMD_profile)
671 gap = &prof_ga;
672#endif
673
674 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000675 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000676 bp = &DEBUGGY(gap, gap->ga_len);
677 bp->dbg_forceit = eap->forceit;
678
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
680 if (pat != NULL)
681 {
682 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
683 vim_free(pat);
684 }
685 if (pat == NULL || bp->dbg_prog == NULL)
686 vim_free(bp->dbg_name);
687 else
688 {
689 if (bp->dbg_lnum == 0) /* default line number is 1 */
690 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000691#ifdef FEAT_PROFILE
692 if (eap->cmdidx != CMD_profile)
693#endif
694 {
695 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
696 ++debug_tick;
697 }
698 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 }
700 }
701}
702
703/*
704 * ":debuggreedy".
705 */
706 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100707ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000708{
709 if (eap->addr_count == 0 || eap->line2 != 0)
710 debug_greedy = TRUE;
711 else
712 debug_greedy = FALSE;
713}
714
715/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000716 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000717 */
718 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100719ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720{
721 struct debuggy *bp, *bpi;
722 int nr;
723 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000724 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 int i;
726 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000727 garray_T *gap;
728
729 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 {
732#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000733 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200734#else
735 ex_ni(eap);
736 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200738 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739
740 if (vim_isdigit(*eap->arg))
741 {
742 /* ":breakdel {nr}" */
743 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000744 for (i = 0; i < gap->ga_len; ++i)
745 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 {
747 todel = i;
748 break;
749 }
750 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000751 else if (*eap->arg == '*')
752 {
753 todel = 0;
754 del_all = TRUE;
755 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 else
757 {
758 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000759 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000761 bp = &DEBUGGY(gap, gap->ga_len);
762 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000764 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 if (bp->dbg_type == bpi->dbg_type
766 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
767 && (bp->dbg_lnum == bpi->dbg_lnum
768 || (bp->dbg_lnum == 0
769 && (best_lnum == 0
770 || bpi->dbg_lnum < best_lnum))))
771 {
772 todel = i;
773 best_lnum = bpi->dbg_lnum;
774 }
775 }
776 vim_free(bp->dbg_name);
777 }
778
779 if (todel < 0)
780 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
781 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000782 {
783 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000784 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000785 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200786 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000787 --gap->ga_len;
788 if (todel < gap->ga_len)
789 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
790 (gap->ga_len - todel) * sizeof(struct debuggy));
791#ifdef FEAT_PROFILE
792 if (eap->cmdidx == CMD_breakdel)
793#endif
794 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000795 if (!del_all)
796 break;
797 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000798
799 /* If all breakpoints were removed clear the array. */
800 if (gap->ga_len == 0)
801 ga_clear(gap);
802 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803}
804
805/*
806 * ":breaklist".
807 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100809ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810{
811 struct debuggy *bp;
812 int i;
813
814 if (dbg_breakp.ga_len == 0)
815 MSG(_("No breakpoints defined"));
816 else
817 for (i = 0; i < dbg_breakp.ga_len; ++i)
818 {
819 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200820 if (bp->dbg_type == DBG_FILE)
821 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 smsg((char_u *)_("%3d %s %s line %ld"),
823 bp->dbg_nr,
824 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200825 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 (long)bp->dbg_lnum);
827 }
828}
829
830/*
831 * Find a breakpoint for a function or sourced file.
832 * Returns line number at which to break; zero when no matching breakpoint.
833 */
834 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100835dbg_find_breakpoint(
836 int file, /* TRUE for a file, FALSE for a function */
837 char_u *fname, /* file or function name */
838 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000840 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
841}
842
843#if defined(FEAT_PROFILE) || defined(PROTO)
844/*
845 * Return TRUE if profiling is on for a function or sourced file.
846 */
847 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100848has_profiling(
849 int file, /* TRUE for a file, FALSE for a function */
850 char_u *fname, /* file or function name */
851 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000852{
853 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
854 != (linenr_T)0);
855}
856#endif
857
858/*
859 * Common code for dbg_find_breakpoint() and has_profiling().
860 */
861 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100862debuggy_find(
863 int file, /* TRUE for a file, FALSE for a function */
864 char_u *fname, /* file or function name */
865 linenr_T after, /* after this line number */
866 garray_T *gap, /* either &dbg_breakp or &prof_ga */
867 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 struct debuggy *bp;
870 int i;
871 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 char_u *name = fname;
873 int prev_got_int;
874
Bram Moolenaar05159a02005-02-26 23:04:13 +0000875 /* Return quickly when there are no breakpoints. */
876 if (gap->ga_len == 0)
877 return (linenr_T)0;
878
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 /* Replace K_SNR in function name with "<SNR>". */
880 if (!file && fname[0] == K_SPECIAL)
881 {
882 name = alloc((unsigned)STRLEN(fname) + 3);
883 if (name == NULL)
884 name = fname;
885 else
886 {
887 STRCPY(name, "<SNR>");
888 STRCPY(name + 5, fname + 3);
889 }
890 }
891
Bram Moolenaar05159a02005-02-26 23:04:13 +0000892 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000894 /* Skip entries that are not useful or are for a line that is beyond
895 * an already found breakpoint. */
896 bp = &DEBUGGY(gap, i);
897 if (((bp->dbg_type == DBG_FILE) == file && (
898#ifdef FEAT_PROFILE
899 gap == &prof_ga ||
900#endif
901 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 * Save the value of got_int and reset it. We don't want a
905 * previous interruption cancel matching, only hitting CTRL-C
906 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 */
908 prev_got_int = got_int;
909 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100910 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000911 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000913 if (fp != NULL)
914 *fp = bp->dbg_forceit;
915 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000916 got_int |= prev_got_int;
917 }
918 }
919 if (name != fname)
920 vim_free(name);
921
922 return lnum;
923}
924
925/*
926 * Called when a breakpoint was encountered.
927 */
928 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100929dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930{
931 /* We need to check if this line is actually executed in do_one_cmd() */
932 debug_breakpoint_name = name;
933 debug_breakpoint_lnum = lnum;
934}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000935
936
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000937# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000938/*
939 * Store the current time in "tm".
940 */
941 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100942profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000943{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000944# ifdef WIN3264
945 QueryPerformanceCounter(tm);
946# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000947 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000948# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949}
950
951/*
952 * Compute the elapsed time from "tm" till now and store in "tm".
953 */
954 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100955profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956{
957 proftime_T now;
958
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000959# ifdef WIN3264
960 QueryPerformanceCounter(&now);
961 tm->QuadPart = now.QuadPart - tm->QuadPart;
962# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000963 gettimeofday(&now, NULL);
964 tm->tv_usec = now.tv_usec - tm->tv_usec;
965 tm->tv_sec = now.tv_sec - tm->tv_sec;
966 if (tm->tv_usec < 0)
967 {
968 tm->tv_usec += 1000000;
969 --tm->tv_sec;
970 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000971# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972}
973
974/*
975 * Subtract the time "tm2" from "tm".
976 */
977 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100978profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000979{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000980# ifdef WIN3264
981 tm->QuadPart -= tm2->QuadPart;
982# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000983 tm->tv_usec -= tm2->tv_usec;
984 tm->tv_sec -= tm2->tv_sec;
985 if (tm->tv_usec < 0)
986 {
987 tm->tv_usec += 1000000;
988 --tm->tv_sec;
989 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000990# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000991}
992
993/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000994 * Return a string that represents the time in "tm".
995 * Uses a static buffer!
996 */
997 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100998profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000999{
1000 static char buf[50];
1001
1002# ifdef WIN3264
1003 LARGE_INTEGER fr;
1004
1005 QueryPerformanceFrequency(&fr);
1006 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1007# else
1008 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001009# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001010 return buf;
1011}
1012
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001013# if defined(FEAT_FLOAT) || defined(PROTO)
1014/*
1015 * Return a float that represents the time in "tm".
1016 */
1017 float_T
1018profile_float(proftime_T *tm)
1019{
1020# ifdef WIN3264
1021 LARGE_INTEGER fr;
1022
1023 QueryPerformanceFrequency(&fr);
1024 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1025# else
1026 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1027# endif
1028}
1029# endif
1030
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001031/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001032 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001033 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001034 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001035profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001036{
1037 if (msec <= 0) /* no limit */
1038 profile_zero(tm);
1039 else
1040 {
1041# ifdef WIN3264
1042 LARGE_INTEGER fr;
1043
1044 QueryPerformanceCounter(tm);
1045 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001046 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001047# else
1048 long usec;
1049
1050 gettimeofday(tm, NULL);
1051 usec = (long)tm->tv_usec + (long)msec * 1000;
1052 tm->tv_usec = usec % 1000000L;
1053 tm->tv_sec += usec / 1000000L;
1054# endif
1055 }
1056}
1057
1058/*
1059 * Return TRUE if the current time is past "tm".
1060 */
1061 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001062profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001063{
1064 proftime_T now;
1065
1066# ifdef WIN3264
1067 if (tm->QuadPart == 0) /* timer was not set */
1068 return FALSE;
1069 QueryPerformanceCounter(&now);
1070 return (now.QuadPart > tm->QuadPart);
1071# else
1072 if (tm->tv_sec == 0) /* timer was not set */
1073 return FALSE;
1074 gettimeofday(&now, NULL);
1075 return (now.tv_sec > tm->tv_sec
1076 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1077# endif
1078}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001079
1080/*
1081 * Set the time in "tm" to zero.
1082 */
1083 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001084profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001085{
1086# ifdef WIN3264
1087 tm->QuadPart = 0;
1088# else
1089 tm->tv_usec = 0;
1090 tm->tv_sec = 0;
1091# endif
1092}
1093
Bram Moolenaar76929292008-01-06 19:07:36 +00001094# endif /* FEAT_PROFILE || FEAT_RELTIME */
1095
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001096#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1097# if defined(HAVE_MATH_H)
1098# include <math.h>
1099# endif
1100
1101/*
1102 * Divide the time "tm" by "count" and store in "tm2".
1103 */
1104 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001105profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001106{
1107 if (count == 0)
1108 profile_zero(tm2);
1109 else
1110 {
1111# ifdef WIN3264
1112 tm2->QuadPart = tm->QuadPart / count;
1113# else
1114 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1115
1116 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001117 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001118# endif
1119 }
1120}
1121#endif
1122
Bram Moolenaar76929292008-01-06 19:07:36 +00001123# if defined(FEAT_PROFILE) || defined(PROTO)
1124/*
1125 * Functions for profiling.
1126 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001127static void script_do_profile(scriptitem_T *si);
1128static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001129static proftime_T prof_wait_time;
1130
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001131/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001132 * Add the time "tm2" to "tm".
1133 */
1134 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001135profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001136{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001137# ifdef WIN3264
1138 tm->QuadPart += tm2->QuadPart;
1139# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001140 tm->tv_usec += tm2->tv_usec;
1141 tm->tv_sec += tm2->tv_sec;
1142 if (tm->tv_usec >= 1000000)
1143 {
1144 tm->tv_usec -= 1000000;
1145 ++tm->tv_sec;
1146 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001147# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001148}
1149
1150/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001151 * Add the "self" time from the total time and the children's time.
1152 */
1153 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001154profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001155{
1156 /* Check that the result won't be negative. Can happen with recursive
1157 * calls. */
1158#ifdef WIN3264
1159 if (total->QuadPart <= children->QuadPart)
1160 return;
1161#else
1162 if (total->tv_sec < children->tv_sec
1163 || (total->tv_sec == children->tv_sec
1164 && total->tv_usec <= children->tv_usec))
1165 return;
1166#endif
1167 profile_add(self, total);
1168 profile_sub(self, children);
1169}
1170
1171/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001172 * Get the current waittime.
1173 */
1174 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001175profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001176{
1177 *tm = prof_wait_time;
1178}
1179
1180/*
1181 * Subtract the passed waittime since "tm" from "tma".
1182 */
1183 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001184profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001185{
1186 proftime_T tm3 = prof_wait_time;
1187
1188 profile_sub(&tm3, tm);
1189 profile_sub(tma, &tm3);
1190}
1191
1192/*
1193 * Return TRUE if "tm1" and "tm2" are equal.
1194 */
1195 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001196profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001197{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001198# ifdef WIN3264
1199 return (tm1->QuadPart == tm2->QuadPart);
1200# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001201 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001202# endif
1203}
1204
1205/*
1206 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1207 */
1208 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001209profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001210{
1211# ifdef WIN3264
1212 return (int)(tm2->QuadPart - tm1->QuadPart);
1213# else
1214 if (tm1->tv_sec == tm2->tv_sec)
1215 return tm2->tv_usec - tm1->tv_usec;
1216 return tm2->tv_sec - tm1->tv_sec;
1217# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001218}
1219
Bram Moolenaar05159a02005-02-26 23:04:13 +00001220static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001221static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001222
1223/*
1224 * ":profile cmd args"
1225 */
1226 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001227ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001228{
1229 char_u *e;
1230 int len;
1231
1232 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001233 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001234 e = skipwhite(e);
1235
1236 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1237 {
1238 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001239 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001240 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001241 profile_zero(&prof_wait_time);
1242 set_vim_var_nr(VV_PROFILING, 1L);
1243 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001244 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001245 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001246 else if (STRCMP(eap->arg, "pause") == 0)
1247 {
1248 if (do_profiling == PROF_YES)
1249 profile_start(&pause_time);
1250 do_profiling = PROF_PAUSED;
1251 }
1252 else if (STRCMP(eap->arg, "continue") == 0)
1253 {
1254 if (do_profiling == PROF_PAUSED)
1255 {
1256 profile_end(&pause_time);
1257 profile_add(&prof_wait_time, &pause_time);
1258 }
1259 do_profiling = PROF_YES;
1260 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001261 else
1262 {
1263 /* The rest is similar to ":breakadd". */
1264 ex_breakadd(eap);
1265 }
1266}
1267
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001268/* Command line expansion for :profile. */
1269static enum
1270{
1271 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001272 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001273} pexpand_what;
1274
1275static char *pexpand_cmds[] = {
1276 "start",
1277#define PROFCMD_START 0
1278 "pause",
1279#define PROFCMD_PAUSE 1
1280 "continue",
1281#define PROFCMD_CONTINUE 2
1282 "func",
1283#define PROFCMD_FUNC 3
1284 "file",
1285#define PROFCMD_FILE 4
1286 NULL
1287#define PROFCMD_LAST 5
1288};
1289
1290/*
1291 * Function given to ExpandGeneric() to obtain the profile command
1292 * specific expansion.
1293 */
1294 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001295get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001296{
1297 switch (pexpand_what)
1298 {
1299 case PEXP_SUBCMD:
1300 return (char_u *)pexpand_cmds[idx];
1301 /* case PEXP_FUNC: TODO */
1302 default:
1303 return NULL;
1304 }
1305}
1306
1307/*
1308 * Handle command line completion for :profile command.
1309 */
1310 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001311set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001312{
1313 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001314
1315 /* Default: expand subcommands. */
1316 xp->xp_context = EXPAND_PROFILE;
1317 pexpand_what = PEXP_SUBCMD;
1318 xp->xp_pattern = arg;
1319
1320 end_subcmd = skiptowhite(arg);
1321 if (*end_subcmd == NUL)
1322 return;
1323
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001324 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001325 {
1326 xp->xp_context = EXPAND_FILES;
1327 xp->xp_pattern = skipwhite(end_subcmd);
1328 return;
1329 }
1330
1331 /* TODO: expand function names after "func" */
1332 xp->xp_context = EXPAND_NOTHING;
1333}
1334
Bram Moolenaar05159a02005-02-26 23:04:13 +00001335/*
1336 * Dump the profiling info.
1337 */
1338 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001339profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001340{
1341 FILE *fd;
1342
1343 if (profile_fname != NULL)
1344 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001345 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001346 if (fd == NULL)
1347 EMSG2(_(e_notopen), profile_fname);
1348 else
1349 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001350 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001351 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001352 fclose(fd);
1353 }
1354 }
1355}
1356
1357/*
1358 * Start profiling script "fp".
1359 */
1360 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001361script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001362{
1363 si->sn_pr_count = 0;
1364 profile_zero(&si->sn_pr_total);
1365 profile_zero(&si->sn_pr_self);
1366
1367 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1368 si->sn_prl_idx = -1;
1369 si->sn_prof_on = TRUE;
1370 si->sn_pr_nest = 0;
1371}
1372
1373/*
1374 * save time when starting to invoke another script or function.
1375 */
1376 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001377script_prof_save(
1378 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001379{
1380 scriptitem_T *si;
1381
1382 if (current_SID > 0 && current_SID <= script_items.ga_len)
1383 {
1384 si = &SCRIPT_ITEM(current_SID);
1385 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1386 profile_start(&si->sn_pr_child);
1387 }
1388 profile_get_wait(tm);
1389}
1390
1391/*
1392 * Count time spent in children after invoking another script or function.
1393 */
1394 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001395script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001396{
1397 scriptitem_T *si;
1398
1399 if (current_SID > 0 && current_SID <= script_items.ga_len)
1400 {
1401 si = &SCRIPT_ITEM(current_SID);
1402 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1403 {
1404 profile_end(&si->sn_pr_child);
1405 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1406 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1407 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1408 }
1409 }
1410}
1411
1412static proftime_T inchar_time;
1413
1414/*
1415 * Called when starting to wait for the user to type a character.
1416 */
1417 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001418prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001419{
1420 profile_start(&inchar_time);
1421}
1422
1423/*
1424 * Called when finished waiting for the user to type a character.
1425 */
1426 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001427prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001428{
1429 profile_end(&inchar_time);
1430 profile_add(&prof_wait_time, &inchar_time);
1431}
1432
1433/*
1434 * Dump the profiling results for all scripts in file "fd".
1435 */
1436 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001437script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001438{
1439 int id;
1440 scriptitem_T *si;
1441 int i;
1442 FILE *sfd;
1443 sn_prl_T *pp;
1444
1445 for (id = 1; id <= script_items.ga_len; ++id)
1446 {
1447 si = &SCRIPT_ITEM(id);
1448 if (si->sn_prof_on)
1449 {
1450 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1451 if (si->sn_pr_count == 1)
1452 fprintf(fd, "Sourced 1 time\n");
1453 else
1454 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1455 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1456 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1457 fprintf(fd, "\n");
1458 fprintf(fd, "count total (s) self (s)\n");
1459
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001460 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001461 if (sfd == NULL)
1462 fprintf(fd, "Cannot open file!\n");
1463 else
1464 {
1465 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1466 {
1467 if (vim_fgets(IObuff, IOSIZE, sfd))
1468 break;
1469 pp = &PRL_ITEM(si, i);
1470 if (pp->snp_count > 0)
1471 {
1472 fprintf(fd, "%5d ", pp->snp_count);
1473 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1474 fprintf(fd, " ");
1475 else
1476 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1477 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1478 }
1479 else
1480 fprintf(fd, " ");
1481 fprintf(fd, "%s", IObuff);
1482 }
1483 fclose(sfd);
1484 }
1485 fprintf(fd, "\n");
1486 }
1487 }
1488}
1489
1490/*
1491 * Return TRUE when a function defined in the current script should be
1492 * profiled.
1493 */
1494 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001495prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001496{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001497 if (current_SID > 0)
1498 return SCRIPT_ITEM(current_SID).sn_pr_force;
1499 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001500}
1501
1502# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503#endif
1504
1505/*
1506 * If 'autowrite' option set, try to write the file.
1507 * Careful: autocommands may make "buf" invalid!
1508 *
1509 * return FAIL for failure, OK otherwise
1510 */
1511 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001512autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001513{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001514 int r;
1515
Bram Moolenaar071d4272004-06-13 20:20:40 +00001516 if (!(p_aw || p_awa) || !p_write
1517#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001518 /* never autowrite a "nofile" or "nowrite" buffer */
1519 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001521 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522 return FAIL;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001523 r = buf_write_all(buf, forceit);
1524
1525 /* Writing may succeed but the buffer still changed, e.g., when there is a
1526 * conversion error. We do want to return FAIL then. */
1527 if (buf_valid(buf) && bufIsChanged(buf))
1528 r = FAIL;
1529 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530}
1531
1532/*
1533 * flush all buffers, except the ones that are readonly
1534 */
1535 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001536autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001537{
1538 buf_T *buf;
1539
1540 if (!(p_aw || p_awa) || !p_write)
1541 return;
1542 for (buf = firstbuf; buf; buf = buf->b_next)
1543 if (bufIsChanged(buf) && !buf->b_p_ro)
1544 {
1545 (void)buf_write_all(buf, FALSE);
1546#ifdef FEAT_AUTOCMD
1547 /* an autocommand may have deleted the buffer */
1548 if (!buf_valid(buf))
1549 buf = firstbuf;
1550#endif
1551 }
1552}
1553
1554/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001555 * Return TRUE if buffer was changed and cannot be abandoned.
1556 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001557 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001559check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560{
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001561 int forceit = (flags & CCGD_FORCEIT);
1562
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563 if ( !forceit
1564 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001565 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1566 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567 {
1568#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1569 if ((p_confirm || cmdmod.confirm) && p_write)
1570 {
1571 buf_T *buf2;
1572 int count = 0;
1573
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001574 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001575 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1576 if (bufIsChanged(buf2)
1577 && (buf2->b_ffname != NULL
1578# ifdef FEAT_BROWSE
1579 || cmdmod.browse
1580# endif
1581 ))
1582 ++count;
1583# ifdef FEAT_AUTOCMD
1584 if (!buf_valid(buf))
1585 /* Autocommand deleted buffer, oops! It's not changed now. */
1586 return FALSE;
1587# endif
1588 dialog_changed(buf, count > 1);
1589# ifdef FEAT_AUTOCMD
1590 if (!buf_valid(buf))
1591 /* Autocommand deleted buffer, oops! It's not changed now. */
1592 return FALSE;
1593# endif
1594 return bufIsChanged(buf);
1595 }
1596#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001597 if (flags & CCGD_EXCMD)
1598 EMSG(_(e_nowrtmsg));
1599 else
1600 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 return TRUE;
1602 }
1603 return FALSE;
1604}
1605
1606#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1607
1608#if defined(FEAT_BROWSE) || defined(PROTO)
1609/*
1610 * When wanting to write a file without a file name, ask the user for a name.
1611 */
1612 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001613browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614{
1615 if (buf->b_fname == NULL)
1616 {
1617 char_u *fname;
1618
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001619 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1620 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001621 if (fname != NULL)
1622 {
1623 if (setfname(buf, fname, NULL, TRUE) == OK)
1624 buf->b_flags |= BF_NOTEDITED;
1625 vim_free(fname);
1626 }
1627 }
1628}
1629#endif
1630
1631/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001632 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 * Must check 'write' option first!
1634 */
1635 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001636dialog_changed(
1637 buf_T *buf,
1638 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001640 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641 int ret;
1642 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001643 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001644
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001645 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646 (buf->b_fname != NULL) ?
1647 buf->b_fname : (char_u *)_("Untitled"));
1648 if (checkall)
1649 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1650 else
1651 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1652
Bram Moolenaar8218f602012-04-25 17:32:18 +02001653 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1654 * function. */
1655 ea.append = ea.forceit = FALSE;
1656
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657 if (ret == VIM_YES)
1658 {
1659#ifdef FEAT_BROWSE
1660 /* May get file name, when there is none */
1661 browse_save_fname(buf);
1662#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001663 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1664 buf->b_fname, buf->b_ffname, FALSE) == OK)
1665 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001666 (void)buf_write_all(buf, FALSE);
1667 }
1668 else if (ret == VIM_NO)
1669 {
1670 unchanged(buf, TRUE);
1671 }
1672 else if (ret == VIM_ALL)
1673 {
1674 /*
1675 * Write all modified files that can be written.
1676 * Skip readonly buffers, these need to be confirmed
1677 * individually.
1678 */
1679 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1680 {
1681 if (bufIsChanged(buf2)
1682 && (buf2->b_ffname != NULL
1683#ifdef FEAT_BROWSE
1684 || cmdmod.browse
1685#endif
1686 )
1687 && !buf2->b_p_ro)
1688 {
1689#ifdef FEAT_BROWSE
1690 /* May get file name, when there is none */
1691 browse_save_fname(buf2);
1692#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001693 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1694 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1695 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001696 (void)buf_write_all(buf2, FALSE);
1697#ifdef FEAT_AUTOCMD
1698 /* an autocommand may have deleted the buffer */
1699 if (!buf_valid(buf2))
1700 buf2 = firstbuf;
1701#endif
1702 }
1703 }
1704 }
1705 else if (ret == VIM_DISCARDALL)
1706 {
1707 /*
1708 * mark all buffers as unchanged
1709 */
1710 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1711 unchanged(buf2, TRUE);
1712 }
1713}
1714#endif
1715
1716/*
1717 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1718 * hidden, autowriting it or unloading it.
1719 */
1720 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001721can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722{
1723 return ( P_HID(buf)
1724 || !bufIsChanged(buf)
1725 || buf->b_nwindows > 1
1726 || autowrite(buf, forceit) == OK
1727 || forceit);
1728}
1729
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001730static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001731
1732/*
1733 * Add a buffer number to "bufnrs", unless it's already there.
1734 */
1735 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001736add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001737{
1738 int i;
1739
1740 for (i = 0; i < *bufnump; ++i)
1741 if (bufnrs[i] == nr)
1742 return;
1743 bufnrs[*bufnump] = nr;
1744 *bufnump = *bufnump + 1;
1745}
1746
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747/*
1748 * Return TRUE if any buffer was changed and cannot be abandoned.
1749 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001750 * When "unload" is true the current buffer is unloaded instead of making it
1751 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001752 */
1753 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001754check_changed_any(
1755 int hidden, /* Only check hidden buffers */
1756 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001758 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 buf_T *buf;
1760 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001761 int i;
1762 int bufnum = 0;
1763 int bufcount = 0;
1764 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001766 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 win_T *wp;
1768#endif
1769
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001770 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1771 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001773 if (bufcount == 0)
1774 return FALSE;
1775
1776 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1777 if (bufnrs == NULL)
1778 return FALSE;
1779
1780 /* curbuf */
1781 bufnrs[bufnum++] = curbuf->b_fnum;
1782#ifdef FEAT_WINDOWS
1783 /* buf in curtab */
1784 FOR_ALL_WINDOWS(wp)
1785 if (wp->w_buffer != curbuf)
1786 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1787
1788 /* buf in other tab */
1789 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1790 if (tp != curtab)
1791 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1792 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1793#endif
1794 /* any other buf */
1795 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1796 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1797
1798 for (i = 0; i < bufnum; ++i)
1799 {
1800 buf = buflist_findnr(bufnrs[i]);
1801 if (buf == NULL)
1802 continue;
1803 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
1804 {
1805 /* Try auto-writing the buffer. If this fails but the buffer no
1806 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001807 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
1808 | CCGD_MULTWIN
1809 | CCGD_ALLBUF) && buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001810 break; /* didn't save - still changes */
1811 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001812 }
1813
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001814 if (i >= bufnum)
1815 goto theend;
1816
1817 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818 exiting = FALSE;
1819#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1820 /*
1821 * When ":confirm" used, don't give an error message.
1822 */
1823 if (!(p_confirm || cmdmod.confirm))
1824#endif
1825 {
1826 /* There must be a wait_return for this message, do_buffer()
1827 * may cause a redraw. But wait_return() is a no-op when vgetc()
1828 * is busy (Quit used from window menu), then make sure we don't
1829 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00001830 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831 {
1832 msg_row = cmdline_row;
1833 msg_col = 0;
1834 msg_didout = FALSE;
1835 }
1836 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02001837 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 {
1839 save = no_wait_return;
1840 no_wait_return = FALSE;
1841 wait_return(FALSE);
1842 no_wait_return = save;
1843 }
1844 }
1845
1846#ifdef FEAT_WINDOWS
1847 /* Try to find a window that contains the buffer. */
1848 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001849 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 if (wp->w_buffer == buf)
1851 {
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001852 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001853# ifdef FEAT_AUTOCMD
1854 /* Paranoia: did autocms wipe out the buffer with changes? */
1855 if (!buf_valid(buf))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001856 {
1857 goto theend;
1858 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001860 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001861 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001862buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863#endif
1864
1865 /* Open the changed buffer in the current window. */
1866 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01001867 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001868
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001869theend:
1870 vim_free(bufnrs);
1871 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872}
1873
1874/*
1875 * return FAIL if there is no file name, OK if there is one
1876 * give error message for FAIL
1877 */
1878 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001879check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880{
1881 if (curbuf->b_ffname == NULL)
1882 {
1883 EMSG(_(e_noname));
1884 return FAIL;
1885 }
1886 return OK;
1887}
1888
1889/*
1890 * flush the contents of a buffer, unless it has no file name
1891 *
1892 * return FAIL for failure, OK otherwise
1893 */
1894 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001895buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896{
1897 int retval;
1898#ifdef FEAT_AUTOCMD
1899 buf_T *old_curbuf = curbuf;
1900#endif
1901
1902 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
1903 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
1904 FALSE, forceit, TRUE, FALSE));
1905#ifdef FEAT_AUTOCMD
1906 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001907 {
1908 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00001910 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911#endif
1912 return retval;
1913}
1914
1915/*
1916 * Code to handle the argument list.
1917 */
1918
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001919static char_u *do_one_arg(char_u *str);
1920static int do_arglist(char_u *str, int what, int after);
1921static void alist_check_arg_idx(void);
1922static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001923#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001924static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001925#endif
1926#define AL_SET 1
1927#define AL_ADD 2
1928#define AL_DEL 3
1929
Bram Moolenaar071d4272004-06-13 20:20:40 +00001930/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001931 * Isolate one argument, taking backticks.
1932 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933 * Return a pointer to the start of the next argument.
1934 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001935 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001936do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937{
1938 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 int inbacktick;
1940
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941 inbacktick = FALSE;
1942 for (p = str; *str; ++str)
1943 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001944 /* When the backslash is used for escaping the special meaning of a
1945 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001946 if (rem_backslash(str))
1947 {
1948 *p++ = *str++;
1949 *p++ = *str;
1950 }
1951 else
1952 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001953 /* An item ends at a space not in backticks */
1954 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001956 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00001958 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001959 }
1960 }
1961 str = skipwhite(str);
1962 *p = NUL;
1963
1964 return str;
1965}
1966
Bram Moolenaar86b68352004-12-27 21:59:20 +00001967/*
1968 * Separate the arguments in "str" and return a list of pointers in the
1969 * growarray "gap".
1970 */
1971 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001972get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00001973{
1974 ga_init2(gap, (int)sizeof(char_u *), 20);
1975 while (*str != NUL)
1976 {
1977 if (ga_grow(gap, 1) == FAIL)
1978 {
1979 ga_clear(gap);
1980 return FAIL;
1981 }
1982 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
1983
1984 /* Isolate one argument, change it in-place, put a NUL after it. */
1985 str = do_one_arg(str);
1986 }
1987 return OK;
1988}
1989
Bram Moolenaar7df351e2006-01-23 22:30:28 +00001990#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001991/*
1992 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02001993 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00001994 * Return FAIL or OK.
1995 */
1996 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001997get_arglist_exp(
1998 char_u *str,
1999 int *fcountp,
2000 char_u ***fnamesp,
2001 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002002{
2003 garray_T ga;
2004 int i;
2005
2006 if (get_arglist(&ga, str) == FAIL)
2007 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002008 if (wig == TRUE)
2009 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2010 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2011 else
2012 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2013 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2014
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002015 ga_clear(&ga);
2016 return i;
2017}
2018#endif
2019
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2021/*
2022 * Redefine the argument list.
2023 */
2024 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002025set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026{
2027 do_arglist(str, AL_SET, 0);
2028}
2029#endif
2030
2031/*
2032 * "what" == AL_SET: Redefine the argument list to 'str'.
2033 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2034 * "what" == AL_DEL: remove files in 'str' from the argument list.
2035 *
2036 * Return FAIL for failure, OK otherwise.
2037 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002039do_arglist(
2040 char_u *str,
2041 int what UNUSED,
2042 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043{
2044 garray_T new_ga;
2045 int exp_count;
2046 char_u **exp_files;
2047 int i;
2048#ifdef FEAT_LISTCMDS
2049 char_u *p;
2050 int match;
2051#endif
2052
2053 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002054 * Set default argument for ":argadd" command.
2055 */
2056 if (what == AL_ADD && *str == NUL)
2057 {
2058 if (curbuf->b_ffname == NULL)
2059 return FAIL;
2060 str = curbuf->b_fname;
2061 }
2062
2063 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064 * Collect all file name arguments in "new_ga".
2065 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002066 if (get_arglist(&new_ga, str) == FAIL)
2067 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068
2069#ifdef FEAT_LISTCMDS
2070 if (what == AL_DEL)
2071 {
2072 regmatch_T regmatch;
2073 int didone;
2074
2075 /*
2076 * Delete the items: use each item as a regexp and find a match in the
2077 * argument list.
2078 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002079 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2081 {
2082 p = ((char_u **)new_ga.ga_data)[i];
2083 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2084 if (p == NULL)
2085 break;
2086 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2087 if (regmatch.regprog == NULL)
2088 {
2089 vim_free(p);
2090 break;
2091 }
2092
2093 didone = FALSE;
2094 for (match = 0; match < ARGCOUNT; ++match)
2095 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2096 (colnr_T)0))
2097 {
2098 didone = TRUE;
2099 vim_free(ARGLIST[match].ae_fname);
2100 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2101 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2102 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 if (curwin->w_arg_idx > match)
2104 --curwin->w_arg_idx;
2105 --match;
2106 }
2107
Bram Moolenaar473de612013-06-08 18:19:48 +02002108 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002109 vim_free(p);
2110 if (!didone)
2111 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2112 }
2113 ga_clear(&new_ga);
2114 }
2115 else
2116#endif
2117 {
2118 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2119 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2120 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002121 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 {
2123 EMSG(_(e_nomatch));
2124 return FAIL;
2125 }
2126
2127#ifdef FEAT_LISTCMDS
2128 if (what == AL_ADD)
2129 {
2130 (void)alist_add_list(exp_count, exp_files, after);
2131 vim_free(exp_files);
2132 }
2133 else /* what == AL_SET */
2134#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002135 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136 }
2137
2138 alist_check_arg_idx();
2139
2140 return OK;
2141}
2142
2143/*
2144 * Check the validity of the arg_idx for each other window.
2145 */
2146 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002147alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148{
2149#ifdef FEAT_WINDOWS
2150 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002151 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152
Bram Moolenaarf740b292006-02-16 22:11:02 +00002153 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154 if (win->w_alist == curwin->w_alist)
2155 check_arg_idx(win);
2156#else
2157 check_arg_idx(curwin);
2158#endif
2159}
2160
2161/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002162 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002163 * index.
2164 */
2165 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002166editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002167{
2168 return !(win->w_arg_idx >= WARGCOUNT(win)
2169 || (win->w_buffer->b_fnum
2170 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2171 && (win->w_buffer->b_ffname == NULL
2172 || !(fullpathcmp(
2173 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2174 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2175}
2176
2177/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 * Check if window "win" is editing the w_arg_idx file in its argument list.
2179 */
2180 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002181check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002183 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184 {
2185 /* We are not editing the current entry in the argument list.
2186 * Set "arg_had_last" if we are editing the last one. */
2187 win->w_arg_idx_invalid = TRUE;
2188 if (win->w_arg_idx != WARGCOUNT(win) - 1
2189 && arg_had_last == FALSE
2190#ifdef FEAT_WINDOWS
2191 && ALIST(win) == &global_alist
2192#endif
2193 && GARGCOUNT > 0
2194 && win->w_arg_idx < GARGCOUNT
2195 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2196 || (win->w_buffer->b_ffname != NULL
2197 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2198 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2199 arg_had_last = TRUE;
2200 }
2201 else
2202 {
2203 /* We are editing the current entry in the argument list.
2204 * Set "arg_had_last" if it's also the last one */
2205 win->w_arg_idx_invalid = FALSE;
2206 if (win->w_arg_idx == WARGCOUNT(win) - 1
2207#ifdef FEAT_WINDOWS
2208 && win->w_alist == &global_alist
2209#endif
2210 )
2211 arg_had_last = TRUE;
2212 }
2213}
2214
2215/*
2216 * ":args", ":argslocal" and ":argsglobal".
2217 */
2218 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002219ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220{
2221 int i;
2222
2223 if (eap->cmdidx != CMD_args)
2224 {
2225#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2226 alist_unlink(ALIST(curwin));
2227 if (eap->cmdidx == CMD_argglobal)
2228 ALIST(curwin) = &global_alist;
2229 else /* eap->cmdidx == CMD_arglocal */
2230 alist_new();
2231#else
2232 ex_ni(eap);
2233 return;
2234#endif
2235 }
2236
2237 if (!ends_excmd(*eap->arg))
2238 {
2239 /*
2240 * ":args file ..": define new argument list, handle like ":next"
2241 * Also for ":argslocal file .." and ":argsglobal file ..".
2242 */
2243 ex_next(eap);
2244 }
2245 else
2246#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2247 if (eap->cmdidx == CMD_args)
2248#endif
2249 {
2250 /*
2251 * ":args": list arguments.
2252 */
2253 if (ARGCOUNT > 0)
2254 {
2255 /* Overwrite the command, for a short list there is no scrolling
2256 * required and no wait_return(). */
2257 gotocmdline(TRUE);
2258 for (i = 0; i < ARGCOUNT; ++i)
2259 {
2260 if (i == curwin->w_arg_idx)
2261 msg_putchar('[');
2262 msg_outtrans(alist_name(&ARGLIST[i]));
2263 if (i == curwin->w_arg_idx)
2264 msg_putchar(']');
2265 msg_putchar(' ');
2266 }
2267 }
2268 }
2269#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2270 else if (eap->cmdidx == CMD_arglocal)
2271 {
2272 garray_T *gap = &curwin->w_alist->al_ga;
2273
2274 /*
2275 * ":argslocal": make a local copy of the global argument list.
2276 */
2277 if (ga_grow(gap, GARGCOUNT) == OK)
2278 for (i = 0; i < GARGCOUNT; ++i)
2279 if (GARGLIST[i].ae_fname != NULL)
2280 {
2281 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2282 vim_strsave(GARGLIST[i].ae_fname);
2283 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2284 GARGLIST[i].ae_fnum;
2285 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 }
2287 }
2288#endif
2289}
2290
2291/*
2292 * ":previous", ":sprevious", ":Next" and ":sNext".
2293 */
2294 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002295ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296{
2297 /* If past the last one already, go to the last one. */
2298 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2299 do_argfile(eap, ARGCOUNT - 1);
2300 else
2301 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2302}
2303
2304/*
2305 * ":rewind", ":first", ":sfirst" and ":srewind".
2306 */
2307 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002308ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309{
2310 do_argfile(eap, 0);
2311}
2312
2313/*
2314 * ":last" and ":slast".
2315 */
2316 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002317ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318{
2319 do_argfile(eap, ARGCOUNT - 1);
2320}
2321
2322/*
2323 * ":argument" and ":sargument".
2324 */
2325 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002326ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327{
2328 int i;
2329
2330 if (eap->addr_count > 0)
2331 i = eap->line2 - 1;
2332 else
2333 i = curwin->w_arg_idx;
2334 do_argfile(eap, i);
2335}
2336
2337/*
2338 * Edit file "argn" of the argument lists.
2339 */
2340 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002341do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342{
2343 int other;
2344 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002345 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346
2347 if (argn < 0 || argn >= ARGCOUNT)
2348 {
2349 if (ARGCOUNT <= 1)
2350 EMSG(_("E163: There is only one file to edit"));
2351 else if (argn < 0)
2352 EMSG(_("E164: Cannot go before first file"));
2353 else
2354 EMSG(_("E165: Cannot go beyond last file"));
2355 }
2356 else
2357 {
2358 setpcmark();
2359#ifdef FEAT_GUI
2360 need_mouse_correct = TRUE;
2361#endif
2362
2363#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002364 /* split window or create new tab page first */
2365 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 {
2367 if (win_split(0, 0) == FAIL)
2368 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002369 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 }
2371 else
2372#endif
2373 {
2374 /*
2375 * if 'hidden' set, only check for changed file when re-editing
2376 * the same buffer
2377 */
2378 other = TRUE;
2379 if (P_HID(curbuf))
2380 {
2381 p = fix_fname(alist_name(&ARGLIST[argn]));
2382 other = otherfile(p);
2383 vim_free(p);
2384 }
2385 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002386 && check_changed(curbuf, CCGD_AW
2387 | (other ? 0 : CCGD_MULTWIN)
2388 | (eap->forceit ? CCGD_FORCEIT : 0)
2389 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 return;
2391 }
2392
2393 curwin->w_arg_idx = argn;
2394 if (argn == ARGCOUNT - 1
2395#ifdef FEAT_WINDOWS
2396 && curwin->w_alist == &global_alist
2397#endif
2398 )
2399 arg_had_last = TRUE;
2400
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002401 /* Edit the file; always use the last known line number.
2402 * When it fails (e.g. Abort for already edited file) restore the
2403 * argument index. */
2404 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002406 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2407 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002408 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002410 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411 setmark('\'');
2412 }
2413}
2414
2415/*
2416 * ":next", and commands that behave like it.
2417 */
2418 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002419ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420{
2421 int i;
2422
2423 /*
2424 * check for changed buffer now, if this fails the argument list is not
2425 * redefined.
2426 */
2427 if ( P_HID(curbuf)
2428 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002429 || !check_changed(curbuf, CCGD_AW
2430 | (eap->forceit ? CCGD_FORCEIT : 0)
2431 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 {
2433 if (*eap->arg != NUL) /* redefine file list */
2434 {
2435 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2436 return;
2437 i = 0;
2438 }
2439 else
2440 i = curwin->w_arg_idx + (int)eap->line2;
2441 do_argfile(eap, i);
2442 }
2443}
2444
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002445#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446/*
2447 * ":argedit"
2448 */
2449 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002450ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002451{
2452 int fnum;
2453 int i;
2454 char_u *s;
2455
2456 /* Add the argument to the buffer list and get the buffer number. */
2457 fnum = buflist_add(eap->arg, BLN_LISTED);
2458
2459 /* Check if this argument is already in the argument list. */
2460 for (i = 0; i < ARGCOUNT; ++i)
2461 if (ARGLIST[i].ae_fnum == fnum)
2462 break;
2463 if (i == ARGCOUNT)
2464 {
2465 /* Can't find it, add it to the argument list. */
2466 s = vim_strsave(eap->arg);
2467 if (s == NULL)
2468 return;
2469 i = alist_add_list(1, &s,
2470 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2471 if (i < 0)
2472 return;
2473 curwin->w_arg_idx = i;
2474 }
2475
2476 alist_check_arg_idx();
2477
2478 /* Edit the argument. */
2479 do_argfile(eap, i);
2480}
2481
2482/*
2483 * ":argadd"
2484 */
2485 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002486ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002487{
2488 do_arglist(eap->arg, AL_ADD,
2489 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2490#ifdef FEAT_TITLE
2491 maketitle();
2492#endif
2493}
2494
2495/*
2496 * ":argdelete"
2497 */
2498 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002499ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500{
2501 int i;
2502 int n;
2503
2504 if (eap->addr_count > 0)
2505 {
2506 /* ":1,4argdel": Delete all arguments in the range. */
2507 if (eap->line2 > ARGCOUNT)
2508 eap->line2 = ARGCOUNT;
2509 n = eap->line2 - eap->line1 + 1;
2510 if (*eap->arg != NUL || n <= 0)
2511 EMSG(_(e_invarg));
2512 else
2513 {
2514 for (i = eap->line1; i <= eap->line2; ++i)
2515 vim_free(ARGLIST[i - 1].ae_fname);
2516 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2517 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2518 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 if (curwin->w_arg_idx >= eap->line2)
2520 curwin->w_arg_idx -= n;
2521 else if (curwin->w_arg_idx > eap->line1)
2522 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002523 if (ARGCOUNT == 0)
2524 curwin->w_arg_idx = 0;
2525 else if (curwin->w_arg_idx >= ARGCOUNT)
2526 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 }
2528 }
2529 else if (*eap->arg == NUL)
2530 EMSG(_(e_argreq));
2531 else
2532 do_arglist(eap->arg, AL_DEL, 0);
2533#ifdef FEAT_TITLE
2534 maketitle();
2535#endif
2536}
2537
2538/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002539 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002540 */
2541 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002542ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543{
2544 int i;
2545#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002546 win_T *wp;
2547 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002549 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 int next_fnum = 0;
2551#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2552 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002554 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002555#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002556 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002557 int qf_idx;
2558#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559
2560#ifndef FEAT_WINDOWS
2561 if (eap->cmdidx == CMD_windo)
2562 {
2563 ex_ni(eap);
2564 return;
2565 }
2566#endif
2567
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002568#ifndef FEAT_QUICKFIX
2569 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2570 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2571 {
2572 ex_ni(eap);
2573 return;
2574 }
2575#endif
2576
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002578 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002579 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2580 * great speed improvement. */
2581 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002583#ifdef FEAT_CLIPBOARD
2584 start_global_changes();
2585#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586
2587 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002588 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002590 || !check_changed(curbuf, CCGD_AW
2591 | (eap->forceit ? CCGD_FORCEIT : 0)
2592 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002595 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002597 wp = firstwin;
2598 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002599#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002600 switch (eap->cmdidx)
2601 {
2602#ifdef FEAT_WINDOWS
2603 case CMD_windo:
2604 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2605 i++;
2606 break;
2607 case CMD_tabdo:
2608 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2609 i++;
2610 break;
2611#endif
2612 case CMD_argdo:
2613 i = eap->line1 - 1;
2614 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002615 default:
2616 break;
2617 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 /* set pcmark now */
2619 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002620 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002621 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002622 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002623 || !buf->b_p_bl); buf = buf->b_next)
2624 if (buf->b_fnum > eap->line2)
2625 {
2626 buf = NULL;
2627 break;
2628 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002629 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002630 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002631 }
2632#ifdef FEAT_QUICKFIX
2633 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2634 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2635 {
2636 qf_size = qf_get_size(eap);
2637 if (qf_size <= 0 || eap->line1 > qf_size)
2638 buf = NULL;
2639 else
2640 {
2641 ex_cc(eap);
2642
2643 buf = curbuf;
2644 i = eap->line1 - 1;
2645 if (eap->addr_count <= 0)
2646 /* default is all the quickfix/location list entries */
2647 eap->line2 = qf_size;
2648 }
2649 }
2650#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651 else
2652 setpcmark();
2653 listcmd_busy = TRUE; /* avoids setting pcmark below */
2654
Bram Moolenaare25bb902015-02-27 20:33:37 +01002655 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 {
2657 if (eap->cmdidx == CMD_argdo)
2658 {
2659 /* go to argument "i" */
2660 if (i == ARGCOUNT)
2661 break;
2662 /* Don't call do_argfile() when already there, it will try
2663 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002664 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002665 {
2666 /* Clear 'shm' to avoid that the file message overwrites
2667 * any output from the command. */
2668 p_shm_save = vim_strsave(p_shm);
2669 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002670 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002671 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2672 vim_free(p_shm_save);
2673 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674 if (curwin->w_arg_idx != i)
2675 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676 }
2677#ifdef FEAT_WINDOWS
2678 else if (eap->cmdidx == CMD_windo)
2679 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002680 /* go to window "wp" */
2681 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002683 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002684 if (curwin != wp)
2685 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002686 wp = curwin->w_next;
2687 }
2688 else if (eap->cmdidx == CMD_tabdo)
2689 {
2690 /* go to window "tp" */
2691 if (!valid_tabpage(tp))
2692 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002693 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002694 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 }
2696#endif
2697 else if (eap->cmdidx == CMD_bufdo)
2698 {
2699 /* Remember the number of the next listed buffer, in case
2700 * ":bwipe" is used or autocommands do something strange. */
2701 next_fnum = -1;
2702 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2703 if (buf->b_p_bl)
2704 {
2705 next_fnum = buf->b_fnum;
2706 break;
2707 }
2708 }
2709
Bram Moolenaara162bc52015-01-07 16:54:21 +01002710 ++i;
2711
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712 /* execute the command */
2713 do_cmdline(eap->arg, eap->getline, eap->cookie,
2714 DOCMD_VERBOSE + DOCMD_NOWAIT);
2715
2716 if (eap->cmdidx == CMD_bufdo)
2717 {
2718 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002719 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 break;
2721 /* Check if the buffer still exists. */
2722 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2723 if (buf->b_fnum == next_fnum)
2724 break;
2725 if (buf == NULL)
2726 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002727
2728 /* Go to the next buffer. Clear 'shm' to avoid that the file
2729 * message overwrites any output from the command. */
2730 p_shm_save = vim_strsave(p_shm);
2731 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002733 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2734 vim_free(p_shm_save);
2735
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002736 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 if (curbuf->b_fnum != next_fnum)
2738 break;
2739 }
2740
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002741#ifdef FEAT_QUICKFIX
2742 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2743 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2744 {
2745 if (i >= qf_size || i >= eap->line2)
2746 break;
2747
2748 qf_idx = qf_get_cur_idx(eap);
2749
2750 ex_cnext(eap);
2751
2752 /* If jumping to the next quickfix entry fails, quit here */
2753 if (qf_get_cur_idx(eap) == qf_idx)
2754 break;
2755 }
2756#endif
2757
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758 if (eap->cmdidx == CMD_windo)
2759 {
2760 validate_cursor(); /* cursor may have moved */
2761#ifdef FEAT_SCROLLBIND
2762 /* required when 'scrollbind' has been set */
2763 if (curwin->w_p_scb)
2764 do_check_scrollbind(TRUE);
2765#endif
2766 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002767
2768#ifdef FEAT_WINDOWS
2769 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2770 if (i+1 > eap->line2)
2771 break;
2772#endif
2773 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2774 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 }
2776 listcmd_busy = FALSE;
2777 }
2778
2779#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002780 if (save_ei != NULL)
2781 {
2782 au_event_restore(save_ei);
2783 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2784 curbuf->b_fname, TRUE, curbuf);
2785 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002786#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002787#ifdef FEAT_CLIPBOARD
2788 end_global_changes();
2789#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790}
2791
2792/*
2793 * Add files[count] to the arglist of the current window after arg "after".
2794 * The file names in files[count] must have been allocated and are taken over.
2795 * Files[] itself is not taken over.
2796 * Returns index of first added argument. Returns -1 when failed (out of mem).
2797 */
2798 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002799alist_add_list(
2800 int count,
2801 char_u **files,
2802 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002803{
2804 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002805 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806
2807 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
2808 {
2809 if (after < 0)
2810 after = 0;
2811 if (after > ARGCOUNT)
2812 after = ARGCOUNT;
2813 if (after < ARGCOUNT)
2814 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
2815 (ARGCOUNT - after) * sizeof(aentry_T));
2816 for (i = 0; i < count; ++i)
2817 {
2818 ARGLIST[after + i].ae_fname = files[i];
2819 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
2820 }
2821 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01002822 if (old_argcount > 0 && curwin->w_arg_idx >= after)
2823 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 return after;
2825 }
2826
2827 for (i = 0; i < count; ++i)
2828 vim_free(files[i]);
2829 return -1;
2830}
2831
2832#endif /* FEAT_LISTCMDS */
2833
2834#ifdef FEAT_EVAL
2835/*
2836 * ":compiler[!] {name}"
2837 */
2838 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002839ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840{
2841 char_u *buf;
2842 char_u *old_cur_comp = NULL;
2843 char_u *p;
2844
2845 if (*eap->arg == NUL)
2846 {
2847 /* List all compiler scripts. */
2848 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
2849 /* ) keep the indenter happy... */
2850 }
2851 else
2852 {
2853 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
2854 if (buf != NULL)
2855 {
2856 if (eap->forceit)
2857 {
2858 /* ":compiler! {name}" sets global options */
2859 do_cmdline_cmd((char_u *)
2860 "command -nargs=* CompilerSet set <args>");
2861 }
2862 else
2863 {
2864 /* ":compiler! {name}" sets local options.
2865 * To remain backwards compatible "current_compiler" is always
2866 * used. A user's compiler plugin may set it, the distributed
2867 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002868 * "b:current_compiler" and restore "current_compiler".
2869 * Explicitly prepend "g:" to make it work in a function. */
2870 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 if (old_cur_comp != NULL)
2872 old_cur_comp = vim_strsave(old_cur_comp);
2873 do_cmdline_cmd((char_u *)
2874 "command -nargs=* CompilerSet setlocal <args>");
2875 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002876 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00002877 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002878
2879 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002880 if (source_runtime(buf, TRUE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
2882 vim_free(buf);
2883
2884 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
2885
2886 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002887 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 if (p != NULL)
2889 set_internal_string_var((char_u *)"b:current_compiler", p);
2890
2891 /* Restore "current_compiler" for ":compiler {name}". */
2892 if (!eap->forceit)
2893 {
2894 if (old_cur_comp != NULL)
2895 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002896 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897 old_cur_comp);
2898 vim_free(old_cur_comp);
2899 }
2900 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01002901 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902 }
2903 }
2904 }
2905}
2906#endif
2907
2908/*
2909 * ":runtime {name}"
2910 */
2911 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002912ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913{
Bram Moolenaar90cfdbe2005-08-12 19:59:19 +00002914 source_runtime(eap->arg, eap->forceit);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915}
2916
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002918source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002920 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921}
2922
2923/*
2924 * Source the file "name" from all directories in 'runtimepath'.
2925 * "name" can contain wildcards.
2926 * When "all" is TRUE, source all files, otherwise only the first one.
2927 * return FAIL when no file could be sourced, OK otherwise.
2928 */
2929 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002930source_runtime(char_u *name, int all)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931{
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002932 return do_in_runtimepath(name, all, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933}
2934
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002935 static int
2936do_in_path(
2937 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002938 char_u *name,
2939 int all,
2940 void (*callback)(char_u *fname, void *ck),
2941 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942{
2943 char_u *rtp;
2944 char_u *np;
2945 char_u *buf;
2946 char_u *rtp_copy;
2947 char_u *tail;
2948 int num_files;
2949 char_u **files;
2950 int i;
2951 int did_one = FALSE;
2952#ifdef AMIGA
2953 struct Process *proc = (struct Process *)FindTask(0L);
2954 APTR save_winptr = proc->pr_WindowPtr;
2955
2956 /* Avoid a requester here for a volume that doesn't exist. */
2957 proc->pr_WindowPtr = (APTR)-1L;
2958#endif
2959
2960 /* Make a copy of 'runtimepath'. Invoking the callback may change the
2961 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002962 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963 buf = alloc(MAXPATHL);
2964 if (buf != NULL && rtp_copy != NULL)
2965 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002966 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002967 {
2968 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00002969 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01002970 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00002971 verbose_leave();
2972 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002973
Bram Moolenaar071d4272004-06-13 20:20:40 +00002974 /* Loop over all entries in 'runtimepath'. */
2975 rtp = rtp_copy;
2976 while (*rtp != NUL && (all || !did_one))
2977 {
2978 /* Copy the path from 'runtimepath' to buf[]. */
2979 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02002980 if (name == NULL)
2981 {
2982 (*callback)(buf, (void *) &cookie);
2983 if (!did_one)
2984 did_one = (cookie == NULL);
2985 }
2986 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987 {
2988 add_pathsep(buf);
2989 tail = buf + STRLEN(buf);
2990
2991 /* Loop over all patterns in "name" */
2992 np = name;
2993 while (*np != NUL && (all || !did_one))
2994 {
2995 /* Append the pattern from "name" to buf[]. */
2996 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
2997 "\t ");
2998
2999 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003000 {
3001 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003002 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003003 verbose_leave();
3004 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003005
3006 /* Expand wildcards, invoke the callback for each match. */
3007 if (gen_expand_wildcards(1, &buf, &num_files, &files,
3008 EW_FILE) == OK)
3009 {
3010 for (i = 0; i < num_files; ++i)
3011 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003012 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013 did_one = TRUE;
3014 if (!all)
3015 break;
3016 }
3017 FreeWild(num_files, files);
3018 }
3019 }
3020 }
3021 }
3022 }
3023 vim_free(buf);
3024 vim_free(rtp_copy);
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003025 if (p_verbose > 0 && !did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003026 {
3027 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003028 smsg((char_u *)_("not found in 'runtimepath': \"%s\""), name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003029 verbose_leave();
3030 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031
3032#ifdef AMIGA
3033 proc->pr_WindowPtr = save_winptr;
3034#endif
3035
3036 return did_one ? OK : FAIL;
3037}
3038
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003039/*
3040 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3041 * it: callback(fname, "cookie")
3042 * When "all" is TRUE repeat for all matches, otherwise only the first one is
3043 * used.
3044 * Returns OK when at least one match found, FAIL otherwise.
3045 *
3046 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3047 * passed by reference in this case, setting it to NULL indicates that callback
3048 * has done its job.
3049 */
3050 int
3051do_in_runtimepath(
3052 char_u *name,
3053 int all,
3054 void (*callback)(char_u *fname, void *ck),
3055 void *cookie)
3056{
3057 return do_in_path(p_rtp, name, all, callback, cookie);
3058}
3059
3060 static void
3061source_pack_plugin(char_u *fname, void *cookie UNUSED)
3062{
3063 char_u *p6, *p5, *p4, *p3, *p2, *p1, *p;
3064 int c;
3065 char_u *new_rtp;
3066 int keep;
3067 int oldlen;
3068 int addlen;
3069
Bram Moolenaarbdcd7522016-02-22 20:19:03 +01003070 p6 = p5 = p4 = p3 = p2 = p1 = get_past_head(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003071 for (p = p1; *p; mb_ptr_adv(p))
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003072 if (vim_ispathsep_nocolon(*p))
3073 {
3074 p6 = p5; p5 = p4; p4 = p3; p3 = p2; p2 = p1; p1 = p;
3075 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003076
3077 /* now we have:
3078 * rtp/pack/name/ever/name/plugin/name.vim
3079 * p6 p5 p4 p3 p2 p1
3080 */
3081
3082 /* find the part up to "pack" in 'runtimepath' */
3083 c = *p6;
3084 *p6 = NUL;
3085 p = (char_u *)strstr((char *)p_rtp, (char *)fname);
3086 if (p == NULL)
3087 /* not found, append at the end */
3088 p = p_rtp + STRLEN(p_rtp);
3089 else
3090 /* append after the matching directory. */
3091 p += STRLEN(fname);
3092 *p6 = c;
3093
3094 c = *p2;
3095 *p2 = NUL;
3096 if (strstr((char *)p_rtp, (char *)fname) == NULL)
3097 {
3098 /* directory not in 'runtimepath', add it */
Bram Moolenaar1daae442016-02-22 23:25:25 +01003099 oldlen = (int)STRLEN(p_rtp);
3100 addlen = (int)STRLEN(fname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003101 new_rtp = alloc(oldlen + addlen + 2);
3102 if (new_rtp == NULL)
3103 {
3104 *p2 = c;
3105 return;
3106 }
3107 keep = (int)(p - p_rtp);
3108 mch_memmove(new_rtp, p_rtp, keep);
3109 new_rtp[keep] = ',';
3110 mch_memmove(new_rtp + keep + 1, fname, addlen + 1);
3111 if (p_rtp[keep] != NUL)
3112 mch_memmove(new_rtp + keep + 1 + addlen, p_rtp + keep,
3113 oldlen - keep + 1);
3114 free_string_option(p_rtp);
3115 p_rtp = new_rtp;
3116 }
3117 *p2 = c;
3118
3119 (void)do_source(fname, FALSE, DOSO_NONE);
3120}
3121
3122/*
3123 * Source the plugins in the package directories.
3124 */
3125 void
3126source_packages()
3127{
3128 do_in_path(p_pp, (char_u *)"pack/*/ever/*/plugin/*.vim",
3129 TRUE, source_pack_plugin, NULL);
3130}
3131
3132/*
3133 * ":loadplugin {name}"
3134 */
3135 void
3136ex_loadplugin(exarg_T *eap)
3137{
3138 static char *pattern = "pack/*/opt/%s/plugin/*.vim";
3139 int len;
3140 char *pat;
3141
Bram Moolenaar1daae442016-02-22 23:25:25 +01003142 len = (int)STRLEN(pattern) + (int)STRLEN(eap->arg);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003143 pat = (char *)alloc(len);
3144 if (pat == NULL)
3145 return;
3146 vim_snprintf(pat, len, pattern, eap->arg);
3147 do_in_path(p_pp, (char_u *)pat, TRUE, source_pack_plugin, NULL);
3148 vim_free(pat);
3149}
3150
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3152/*
3153 * ":options"
3154 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003156ex_options(
3157 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158{
3159 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3160}
3161#endif
3162
3163/*
3164 * ":source {fname}"
3165 */
3166 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003167ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168{
3169#ifdef FEAT_BROWSE
3170 if (cmdmod.browse)
3171 {
3172 char_u *fname = NULL;
3173
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003174 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3176 if (fname != NULL)
3177 {
3178 cmd_source(fname, eap);
3179 vim_free(fname);
3180 }
3181 }
3182 else
3183#endif
3184 cmd_source(eap->arg, eap);
3185}
3186
3187 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003188cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189{
3190 if (*fname == NUL)
3191 EMSG(_(e_argreq));
3192
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003194 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003195 * Need to execute the commands directly. This is required at least
3196 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 * - ":g" command busy
3198 * - after ":argdo", ":windo" or ":bufdo"
3199 * - another command follows
3200 * - inside a loop
3201 */
3202 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3203#ifdef FEAT_EVAL
3204 || eap->cstack->cs_idx >= 0
3205#endif
3206 );
3207
3208 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003209 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 EMSG2(_(e_notopen), fname);
3211}
3212
3213/*
3214 * ":source" and associated commands.
3215 */
3216/*
3217 * Structure used to store info for each sourced file.
3218 * It is shared between do_source() and getsourceline().
3219 * This is required, because it needs to be handed to do_cmdline() and
3220 * sourcing can be done recursively.
3221 */
3222struct source_cookie
3223{
3224 FILE *fp; /* opened file for sourcing */
3225 char_u *nextline; /* if not NULL: line that was read ahead */
3226 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003227#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3229 int error; /* TRUE if LF found after CR-LF */
3230#endif
3231#ifdef FEAT_EVAL
3232 linenr_T breakpoint; /* next line with breakpoint or zero */
3233 char_u *fname; /* name of sourced file */
3234 int dbg_tick; /* debug_tick when breakpoint was set */
3235 int level; /* top nesting level of sourced file */
3236#endif
3237#ifdef FEAT_MBYTE
3238 vimconv_T conv; /* type of conversion */
3239#endif
3240};
3241
3242#ifdef FEAT_EVAL
3243/*
3244 * Return the address holding the next breakpoint line for a source cookie.
3245 */
3246 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003247source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248{
3249 return &((struct source_cookie *)cookie)->breakpoint;
3250}
3251
3252/*
3253 * Return the address holding the debug tick for a source cookie.
3254 */
3255 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003256source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257{
3258 return &((struct source_cookie *)cookie)->dbg_tick;
3259}
3260
3261/*
3262 * Return the nesting level for a source cookie.
3263 */
3264 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003265source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266{
3267 return ((struct source_cookie *)cookie)->level;
3268}
3269#endif
3270
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003271static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003273#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3274# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003275static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003276
3277/*
3278 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003279 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280 */
3281 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003282fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003284# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003285 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3286# else
3287 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003288# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289
3290 if (fd_tmp == -1)
3291 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003292
3293# ifdef HAVE_FD_CLOEXEC
3294 {
3295 int fdflags = fcntl(fd_tmp, F_GETFD);
3296 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003297 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003298 }
3299# endif
3300
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 return fdopen(fd_tmp, READBIN);
3302}
3303#endif
3304
3305
3306/*
3307 * do_source: Read the file "fname" and execute its lines as EX commands.
3308 *
3309 * This function may be called recursively!
3310 *
3311 * return FAIL if file could not be opened, OK otherwise
3312 */
3313 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003314do_source(
3315 char_u *fname,
3316 int check_other, /* check for .vimrc and _vimrc */
3317 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318{
3319 struct source_cookie cookie;
3320 char_u *save_sourcing_name;
3321 linenr_T save_sourcing_lnum;
3322 char_u *p;
3323 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003324 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003325 int retval = FAIL;
3326#ifdef FEAT_EVAL
3327 scid_T save_current_SID;
3328 static scid_T last_current_SID = 0;
3329 void *save_funccalp;
3330 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003331 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003332# ifdef UNIX
3333 struct stat st;
3334 int stat_ok;
3335# endif
3336#endif
3337#ifdef STARTUPTIME
3338 struct timeval tv_rel;
3339 struct timeval tv_start;
3340#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003341#ifdef FEAT_PROFILE
3342 proftime_T wait_start;
3343#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346 if (p == NULL)
3347 return retval;
3348 fname_exp = fix_fname(p);
3349 vim_free(p);
3350 if (fname_exp == NULL)
3351 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 if (mch_isdir(fname_exp))
3353 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003354 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003355 goto theend;
3356 }
3357
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003358#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003359 /* Apply SourceCmd autocommands, they should get the file and source it. */
3360 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3361 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3362 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003363 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003364# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003365 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003366# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003367 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003368# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003369 goto theend;
3370 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003371
3372 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003373 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3374#endif
3375
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003376#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3378#else
3379 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3380#endif
3381 if (cookie.fp == NULL && check_other)
3382 {
3383 /*
3384 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3385 * and ".exrc" by "_exrc" or vice versa.
3386 */
3387 p = gettail(fname_exp);
3388 if ((*p == '.' || *p == '_')
3389 && (STRICMP(p + 1, "vimrc") == 0
3390 || STRICMP(p + 1, "gvimrc") == 0
3391 || STRICMP(p + 1, "exrc") == 0))
3392 {
3393 if (*p == '_')
3394 *p = '.';
3395 else
3396 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003397#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3399#else
3400 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3401#endif
3402 }
3403 }
3404
3405 if (cookie.fp == NULL)
3406 {
3407 if (p_verbose > 0)
3408 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003409 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003411 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003412 else
3413 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003414 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003415 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416 }
3417 goto theend;
3418 }
3419
3420 /*
3421 * The file exists.
3422 * - In verbose mode, give a message.
3423 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3424 */
3425 if (p_verbose > 1)
3426 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003427 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003428 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003429 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003430 else
3431 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003432 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003433 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003434 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003435 if (is_vimrc == DOSO_VIMRC)
3436 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3437 else if (is_vimrc == DOSO_GVIMRC)
3438 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003439
3440#ifdef USE_CRNL
3441 /* If no automatic file format: Set default to CR-NL. */
3442 if (*p_ffs == NUL)
3443 cookie.fileformat = EOL_DOS;
3444 else
3445 cookie.fileformat = EOL_UNKNOWN;
3446 cookie.error = FALSE;
3447#endif
3448
3449#ifdef USE_CR
3450 /* If no automatic file format: Set default to CR. */
3451 if (*p_ffs == NUL)
3452 cookie.fileformat = EOL_MAC;
3453 else
3454 cookie.fileformat = EOL_UNKNOWN;
3455 cookie.error = FALSE;
3456#endif
3457
3458 cookie.nextline = NULL;
3459 cookie.finished = FALSE;
3460
3461#ifdef FEAT_EVAL
3462 /*
3463 * Check if this script has a breakpoint.
3464 */
3465 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3466 cookie.fname = fname_exp;
3467 cookie.dbg_tick = debug_tick;
3468
3469 cookie.level = ex_nesting_level;
3470#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471
3472 /*
3473 * Keep the sourcing name/lnum, for recursive calls.
3474 */
3475 save_sourcing_name = sourcing_name;
3476 sourcing_name = fname_exp;
3477 save_sourcing_lnum = sourcing_lnum;
3478 sourcing_lnum = 0;
3479
Bram Moolenaar73881402009-02-04 16:50:47 +00003480#ifdef FEAT_MBYTE
3481 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3482
3483 /* Read the first line so we can check for a UTF-8 BOM. */
3484 firstline = getsourceline(0, (void *)&cookie, 0);
3485 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3486 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3487 {
3488 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3489 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3490 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003491 if (p == NULL)
3492 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003493 if (p != NULL)
3494 {
3495 vim_free(firstline);
3496 firstline = p;
3497 }
3498 }
3499#endif
3500
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003502 if (time_fd != NULL)
3503 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504#endif
3505
3506#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003507# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003508 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003509 prof_child_enter(&wait_start); /* entering a child now */
3510# endif
3511
3512 /* Don't use local function variables, if called from a function.
3513 * Also starts profiling timer for nested script. */
3514 save_funccalp = save_funccal();
3515
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516 /*
3517 * Check if this script was sourced before to finds its SID.
3518 * If it's new, generate a new SID.
3519 */
3520 save_current_SID = current_SID;
3521# ifdef UNIX
3522 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3523# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003524 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3525 {
3526 si = &SCRIPT_ITEM(current_SID);
3527 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003528 && (
3529# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003530 /* Compare dev/ino when possible, it catches symbolic
3531 * links. Also compare file names, the inode may change
3532 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003533 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003534 && (si->sn_dev == st.st_dev
3535 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003537 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003539 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 if (current_SID == 0)
3541 {
3542 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003543 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3544 == FAIL)
3545 goto almosttheend;
3546 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003548 ++script_items.ga_len;
3549 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3550# ifdef FEAT_PROFILE
3551 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003554 si = &SCRIPT_ITEM(current_SID);
3555 si->sn_name = fname_exp;
3556 fname_exp = NULL;
3557# ifdef UNIX
3558 if (stat_ok)
3559 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003560 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003561 si->sn_dev = st.st_dev;
3562 si->sn_ino = st.st_ino;
3563 }
3564 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003565 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003566# endif
3567
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568 /* Allocate the local script variables to use for this script. */
3569 new_script_vars(current_SID);
3570 }
3571
Bram Moolenaar05159a02005-02-26 23:04:13 +00003572# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003573 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003574 {
3575 int forceit;
3576
3577 /* Check if we do profiling for this script. */
3578 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3579 {
3580 script_do_profile(si);
3581 si->sn_pr_force = forceit;
3582 }
3583 if (si->sn_prof_on)
3584 {
3585 ++si->sn_pr_count;
3586 profile_start(&si->sn_pr_start);
3587 profile_zero(&si->sn_pr_children);
3588 }
3589 }
3590# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591#endif
3592
3593 /*
3594 * Call do_cmdline, which will call getsourceline() to get the lines.
3595 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003596 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003599
3600#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003601 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003602 {
3603 /* Get "si" again, "script_items" may have been reallocated. */
3604 si = &SCRIPT_ITEM(current_SID);
3605 if (si->sn_prof_on)
3606 {
3607 profile_end(&si->sn_pr_start);
3608 profile_sub_wait(&wait_start, &si->sn_pr_start);
3609 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003610 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3611 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003612 }
3613 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003614#endif
3615
3616 if (got_int)
3617 EMSG(_(e_interr));
3618 sourcing_name = save_sourcing_name;
3619 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003620 if (p_verbose > 1)
3621 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003622 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003623 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003625 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003626 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627 }
3628#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003629 if (time_fd != NULL)
3630 {
3631 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
3632 time_msg((char *)IObuff, &tv_start);
3633 time_pop(&tv_rel);
3634 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003635#endif
3636
3637#ifdef FEAT_EVAL
3638 /*
3639 * After a "finish" in debug mode, need to break at first command of next
3640 * sourced file.
3641 */
3642 if (save_debug_break_level > ex_nesting_level
3643 && debug_break_level == ex_nesting_level)
3644 ++debug_break_level;
3645#endif
3646
Bram Moolenaar05159a02005-02-26 23:04:13 +00003647#ifdef FEAT_EVAL
3648almosttheend:
3649 current_SID = save_current_SID;
3650 restore_funccal(save_funccalp);
3651# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003652 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003653 prof_child_exit(&wait_start); /* leaving a child now */
3654# endif
3655#endif
3656 fclose(cookie.fp);
3657 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00003658 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003659#ifdef FEAT_MBYTE
3660 convert_setup(&cookie.conv, NULL, NULL);
3661#endif
3662
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663theend:
3664 vim_free(fname_exp);
3665 return retval;
3666}
3667
3668#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003669
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670/*
3671 * ":scriptnames"
3672 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003674ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675{
3676 int i;
3677
Bram Moolenaar05159a02005-02-26 23:04:13 +00003678 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
3679 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02003680 {
3681 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
3682 NameBuff, MAXPATHL, TRUE);
3683 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01003684 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685}
3686
3687# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
3688/*
3689 * Fix slashes in the list of script names for 'shellslash'.
3690 */
3691 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003692scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693{
3694 int i;
3695
Bram Moolenaar05159a02005-02-26 23:04:13 +00003696 for (i = 1; i <= script_items.ga_len; ++i)
3697 if (SCRIPT_ITEM(i).sn_name != NULL)
3698 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699}
3700# endif
3701
3702/*
3703 * Get a pointer to a script name. Used for ":verbose set".
3704 */
3705 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003706get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707{
3708 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003709 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003711 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003713 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00003715 return (char_u *)_("environment variable");
3716 if (id == SID_ERROR)
3717 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00003718 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719}
Bram Moolenaar05159a02005-02-26 23:04:13 +00003720
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003721# if defined(EXITFREE) || defined(PROTO)
3722 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003723free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00003724{
3725 int i;
3726
3727 for (i = script_items.ga_len; i > 0; --i)
3728 vim_free(SCRIPT_ITEM(i).sn_name);
3729 ga_clear(&script_items);
3730}
3731# endif
3732
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733#endif
3734
3735#if defined(USE_CR) || defined(PROTO)
3736
3737# if defined(__MSL__) && (__MSL__ >= 22)
3738/*
3739 * Newer version of the Metrowerks library handle DOS and UNIX files
3740 * without help.
3741 * Test with earlier versions, MSL 2.2 is the library supplied with
3742 * Codewarrior Pro 2.
3743 */
3744 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003745fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746{
3747 return fgets(s, n, stream);
3748}
3749# else
3750/*
3751 * Version of fgets() which also works for lines ending in a <CR> only
3752 * (Macintosh format).
3753 * For older versions of the Metrowerks library.
3754 * At least CodeWarrior 9 needed this code.
3755 */
3756 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01003757fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758{
3759 int c = 0;
3760 int char_read = 0;
3761
3762 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
3763 {
3764 c = fgetc(stream);
3765 s[char_read++] = c;
3766 /* If the file is in DOS format, we need to skip a NL after a CR. I
3767 * thought it was the other way around, but this appears to work... */
3768 if (c == '\n')
3769 {
3770 c = fgetc(stream);
3771 if (c != '\r')
3772 ungetc(c, stream);
3773 }
3774 }
3775
3776 s[char_read] = 0;
3777 if (char_read == 0)
3778 return NULL;
3779
3780 if (feof(stream) && char_read == 1)
3781 return NULL;
3782
3783 return s;
3784}
3785# endif
3786#endif
3787
3788/*
3789 * Get one full line from a sourced file.
3790 * Called by do_cmdline() when it's called from do_source().
3791 *
3792 * Return a pointer to the line in allocated memory.
3793 * Return NULL for end-of-file or some error.
3794 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003796getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797{
3798 struct source_cookie *sp = (struct source_cookie *)cookie;
3799 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003800 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003801
3802#ifdef FEAT_EVAL
3803 /* If breakpoints have been added/deleted need to check for it. */
3804 if (sp->dbg_tick < debug_tick)
3805 {
3806 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3807 sp->dbg_tick = debug_tick;
3808 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003809# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003810 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003811 script_line_end();
3812# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813#endif
3814 /*
3815 * Get current line. If there is a read-ahead line, use it, otherwise get
3816 * one now.
3817 */
3818 if (sp->finished)
3819 line = NULL;
3820 else if (sp->nextline == NULL)
3821 line = get_one_sourceline(sp);
3822 else
3823 {
3824 line = sp->nextline;
3825 sp->nextline = NULL;
3826 ++sourcing_lnum;
3827 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003828#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003829 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00003830 script_line_start();
3831#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832
3833 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
3834 * contain the 'C' flag. */
3835 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
3836 {
3837 /* compensate for the one line read-ahead */
3838 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003839
3840 /* Get the next line and concatenate it when it starts with a
3841 * backslash. We always need to read the next line, keep it in
3842 * sp->nextline. */
3843 sp->nextline = get_one_sourceline(sp);
3844 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003846 garray_T ga;
3847
Bram Moolenaarb549a732012-02-22 18:29:33 +01003848 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003849 ga_concat(&ga, line);
3850 ga_concat(&ga, p + 1);
3851 for (;;)
3852 {
3853 vim_free(sp->nextline);
3854 sp->nextline = get_one_sourceline(sp);
3855 if (sp->nextline == NULL)
3856 break;
3857 p = skipwhite(sp->nextline);
3858 if (*p != '\\')
3859 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01003860 /* Adjust the growsize to the current length to speed up
3861 * concatenating many lines. */
3862 if (ga.ga_len > 400)
3863 {
3864 if (ga.ga_len > 8000)
3865 ga.ga_growsize = 8000;
3866 else
3867 ga.ga_growsize = ga.ga_len;
3868 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003869 ga_concat(&ga, p + 1);
3870 }
3871 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01003873 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 }
3875 }
3876
3877#ifdef FEAT_MBYTE
3878 if (line != NULL && sp->conv.vc_type != CONV_NONE)
3879 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01003880 char_u *s;
3881
Bram Moolenaar071d4272004-06-13 20:20:40 +00003882 /* Convert the encoding of the script line. */
3883 s = string_convert(&sp->conv, line, NULL);
3884 if (s != NULL)
3885 {
3886 vim_free(line);
3887 line = s;
3888 }
3889 }
3890#endif
3891
3892#ifdef FEAT_EVAL
3893 /* Did we encounter a breakpoint? */
3894 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
3895 {
3896 dbg_breakpoint(sp->fname, sourcing_lnum);
3897 /* Find next breakpoint. */
3898 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
3899 sp->dbg_tick = debug_tick;
3900 }
3901#endif
3902
3903 return line;
3904}
3905
3906 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003907get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908{
3909 garray_T ga;
3910 int len;
3911 int c;
3912 char_u *buf;
3913#ifdef USE_CRNL
3914 int has_cr; /* CR-LF found */
3915#endif
3916#ifdef USE_CR
3917 char_u *scan;
3918#endif
3919 int have_read = FALSE;
3920
3921 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003922 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923
3924 /*
3925 * Loop until there is a finished line (or end-of-file).
3926 */
3927 sourcing_lnum++;
3928 for (;;)
3929 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003930 /* make room to read at least 120 (more) characters */
3931 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932 break;
3933 buf = (char_u *)ga.ga_data;
3934
3935#ifdef USE_CR
3936 if (sp->fileformat == EOL_MAC)
3937 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00003938 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3939 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 break;
3941 }
3942 else
3943#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00003944 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
3945 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003947 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948#ifdef USE_CRNL
3949 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
3950 * CTRL-Z by its own, or after a NL. */
3951 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
3952 && sp->fileformat == EOL_DOS
3953 && buf[len - 1] == Ctrl_Z)
3954 {
3955 buf[len - 1] = NUL;
3956 break;
3957 }
3958#endif
3959
3960#ifdef USE_CR
3961 /* If the read doesn't stop on a new line, and there's
3962 * some CR then we assume a Mac format */
3963 if (sp->fileformat == EOL_UNKNOWN)
3964 {
3965 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
3966 sp->fileformat = EOL_MAC;
3967 else
3968 sp->fileformat = EOL_UNIX;
3969 }
3970
3971 if (sp->fileformat == EOL_MAC)
3972 {
3973 scan = vim_strchr(buf, '\r');
3974
3975 if (scan != NULL)
3976 {
3977 *scan = '\n';
3978 if (*(scan + 1) != 0)
3979 {
3980 *(scan + 1) = 0;
3981 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
3982 }
3983 }
3984 len = STRLEN(buf);
3985 }
3986#endif
3987
3988 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989 ga.ga_len = len;
3990
3991 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00003992 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993 continue;
3994
3995 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
3996 {
3997#ifdef USE_CRNL
3998 has_cr = (len >= 2 && buf[len - 2] == '\r');
3999 if (sp->fileformat == EOL_UNKNOWN)
4000 {
4001 if (has_cr)
4002 sp->fileformat = EOL_DOS;
4003 else
4004 sp->fileformat = EOL_UNIX;
4005 }
4006
4007 if (sp->fileformat == EOL_DOS)
4008 {
4009 if (has_cr) /* replace trailing CR */
4010 {
4011 buf[len - 2] = '\n';
4012 --len;
4013 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 }
4015 else /* lines like ":map xx yy^M" will have failed */
4016 {
4017 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004018 {
4019 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004020 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004021 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 sp->error = TRUE;
4023 sp->fileformat = EOL_UNIX;
4024 }
4025 }
4026#endif
4027 /* The '\n' is escaped if there is an odd number of ^V's just
4028 * before it, first set "c" just before the 'V's and then check
4029 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4030 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4031 ;
4032 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4033 {
4034 sourcing_lnum++;
4035 continue;
4036 }
4037
4038 buf[len - 1] = NUL; /* remove the NL */
4039 }
4040
4041 /*
4042 * Check for ^C here now and then, so recursive :so can be broken.
4043 */
4044 line_breakcheck();
4045 break;
4046 }
4047
4048 if (have_read)
4049 return (char_u *)ga.ga_data;
4050
4051 vim_free(ga.ga_data);
4052 return NULL;
4053}
4054
Bram Moolenaar05159a02005-02-26 23:04:13 +00004055#if defined(FEAT_PROFILE) || defined(PROTO)
4056/*
4057 * Called when starting to read a script line.
4058 * "sourcing_lnum" must be correct!
4059 * When skipping lines it may not actually be executed, but we won't find out
4060 * until later and we need to store the time now.
4061 */
4062 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004063script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004064{
4065 scriptitem_T *si;
4066 sn_prl_T *pp;
4067
4068 if (current_SID <= 0 || current_SID > script_items.ga_len)
4069 return;
4070 si = &SCRIPT_ITEM(current_SID);
4071 if (si->sn_prof_on && sourcing_lnum >= 1)
4072 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004073 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004074 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004075 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004076 si->sn_prl_idx = sourcing_lnum - 1;
4077 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4078 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4079 {
4080 /* Zero counters for a line that was not used before. */
4081 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4082 pp->snp_count = 0;
4083 profile_zero(&pp->sn_prl_total);
4084 profile_zero(&pp->sn_prl_self);
4085 ++si->sn_prl_ga.ga_len;
4086 }
4087 si->sn_prl_execed = FALSE;
4088 profile_start(&si->sn_prl_start);
4089 profile_zero(&si->sn_prl_children);
4090 profile_get_wait(&si->sn_prl_wait);
4091 }
4092}
4093
4094/*
4095 * Called when actually executing a function line.
4096 */
4097 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004098script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004099{
4100 scriptitem_T *si;
4101
4102 if (current_SID <= 0 || current_SID > script_items.ga_len)
4103 return;
4104 si = &SCRIPT_ITEM(current_SID);
4105 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4106 si->sn_prl_execed = TRUE;
4107}
4108
4109/*
4110 * Called when done with a function line.
4111 */
4112 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004113script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004114{
4115 scriptitem_T *si;
4116 sn_prl_T *pp;
4117
4118 if (current_SID <= 0 || current_SID > script_items.ga_len)
4119 return;
4120 si = &SCRIPT_ITEM(current_SID);
4121 if (si->sn_prof_on && si->sn_prl_idx >= 0
4122 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4123 {
4124 if (si->sn_prl_execed)
4125 {
4126 pp = &PRL_ITEM(si, si->sn_prl_idx);
4127 ++pp->snp_count;
4128 profile_end(&si->sn_prl_start);
4129 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004130 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004131 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4132 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004133 }
4134 si->sn_prl_idx = -1;
4135 }
4136}
4137#endif
4138
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139/*
4140 * ":scriptencoding": Set encoding conversion for a sourced script.
4141 * Without the multi-byte feature it's simply ignored.
4142 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004143 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004144ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145{
4146#ifdef FEAT_MBYTE
4147 struct source_cookie *sp;
4148 char_u *name;
4149
4150 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4151 {
4152 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4153 return;
4154 }
4155
4156 if (*eap->arg != NUL)
4157 {
4158 name = enc_canonize(eap->arg);
4159 if (name == NULL) /* out of memory */
4160 return;
4161 }
4162 else
4163 name = eap->arg;
4164
4165 /* Setup for conversion from the specified encoding to 'encoding'. */
4166 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4167 convert_setup(&sp->conv, name, p_enc);
4168
4169 if (name != eap->arg)
4170 vim_free(name);
4171#endif
4172}
4173
4174#if defined(FEAT_EVAL) || defined(PROTO)
4175/*
4176 * ":finish": Mark a sourced file as finished.
4177 */
4178 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004179ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180{
4181 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4182 do_finish(eap, FALSE);
4183 else
4184 EMSG(_("E168: :finish used outside of a sourced file"));
4185}
4186
4187/*
4188 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4189 * Also called for a pending finish at the ":endtry" or after returning from
4190 * an extra do_cmdline(). "reanimate" is used in the latter case.
4191 */
4192 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004193do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194{
4195 int idx;
4196
4197 if (reanimate)
4198 ((struct source_cookie *)getline_cookie(eap->getline,
4199 eap->cookie))->finished = FALSE;
4200
4201 /*
4202 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4203 * not in its finally clause (which then is to be executed next) is found.
4204 * In this case, make the ":finish" pending for execution at the ":endtry".
4205 * Otherwise, finish normally.
4206 */
4207 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4208 if (idx >= 0)
4209 {
4210 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4211 report_make_pending(CSTP_FINISH, NULL);
4212 }
4213 else
4214 ((struct source_cookie *)getline_cookie(eap->getline,
4215 eap->cookie))->finished = TRUE;
4216}
4217
4218
4219/*
4220 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4221 * message for missing ":endif".
4222 * Return FALSE when not sourcing a file.
4223 */
4224 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004225source_finished(
4226 char_u *(*fgetline)(int, void *, int),
4227 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004229 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004230 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004231 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232}
4233#endif
4234
4235#if defined(FEAT_LISTCMDS) || defined(PROTO)
4236/*
4237 * ":checktime [buffer]"
4238 */
4239 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004240ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241{
4242 buf_T *buf;
4243 int save_no_check_timestamps = no_check_timestamps;
4244
4245 no_check_timestamps = 0;
4246 if (eap->addr_count == 0) /* default is all buffers */
4247 check_timestamps(FALSE);
4248 else
4249 {
4250 buf = buflist_findnr((int)eap->line2);
4251 if (buf != NULL) /* cannot happen? */
4252 (void)buf_check_timestamp(buf, FALSE);
4253 }
4254 no_check_timestamps = save_no_check_timestamps;
4255}
4256#endif
4257
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4259 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004260# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004261static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004263 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004264get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004266 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004268 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004269 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004271# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004272 if (loc != NULL)
4273 {
4274 char_u *p;
4275
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004276 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4277 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 p = vim_strchr(loc, '=');
4279 if (p != NULL)
4280 {
4281 loc = ++p;
4282 while (*p != NUL) /* remove trailing newline */
4283 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004284 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 {
4286 *p = NUL;
4287 break;
4288 }
4289 ++p;
4290 }
4291 }
4292 }
4293# endif
4294
4295 return loc;
4296}
4297#endif
4298
4299
4300#ifdef WIN32
4301/*
4302 * On MS-Windows locale names are strings like "German_Germany.1252", but
4303 * gettext expects "de". Try to translate one into another here for a few
4304 * supported languages.
4305 */
4306 static char_u *
4307gettext_lang(char_u *name)
4308{
4309 int i;
4310 static char *(mtable[]) = {
4311 "afrikaans", "af",
4312 "czech", "cs",
4313 "dutch", "nl",
4314 "german", "de",
4315 "english_united kingdom", "en_GB",
4316 "spanish", "es",
4317 "french", "fr",
4318 "italian", "it",
4319 "japanese", "ja",
4320 "korean", "ko",
4321 "norwegian", "no",
4322 "polish", "pl",
4323 "russian", "ru",
4324 "slovak", "sk",
4325 "swedish", "sv",
4326 "ukrainian", "uk",
4327 "chinese_china", "zh_CN",
4328 "chinese_taiwan", "zh_TW",
4329 NULL};
4330
4331 for (i = 0; mtable[i] != NULL; i += 2)
4332 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004333 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334 return name;
4335}
4336#endif
4337
4338#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4339/*
4340 * Obtain the current messages language. Used to set the default for
4341 * 'helplang'. May return NULL or an empty string.
4342 */
4343 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004344get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345{
4346 char_u *p;
4347
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004348# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004350 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351# else
4352 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004353 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4354 * and LC_MONETARY may be set differently for a Japanese working in the
4355 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004356 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357# endif
4358# else
4359 p = mch_getenv((char_u *)"LC_ALL");
4360 if (p == NULL || *p == NUL)
4361 {
4362 p = mch_getenv((char_u *)"LC_MESSAGES");
4363 if (p == NULL || *p == NUL)
4364 p = mch_getenv((char_u *)"LANG");
4365 }
4366# endif
4367# ifdef WIN32
4368 p = gettext_lang(p);
4369# endif
4370 return p;
4371}
4372#endif
4373
Bram Moolenaardef9e822004-12-31 20:58:58 +00004374/* Complicated #if; matches with where get_mess_env() is used below. */
4375#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4376 && defined(LC_MESSAGES))) \
4377 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4378 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4379 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004380static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381
4382/*
4383 * Get the language used for messages from the environment.
4384 */
4385 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004386get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387{
4388 char_u *p;
4389
4390 p = mch_getenv((char_u *)"LC_ALL");
4391 if (p == NULL || *p == NUL)
4392 {
4393 p = mch_getenv((char_u *)"LC_MESSAGES");
4394 if (p == NULL || *p == NUL)
4395 {
4396 p = mch_getenv((char_u *)"LANG");
4397 if (p != NULL && VIM_ISDIGIT(*p))
4398 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004399# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004401 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402# endif
4403 }
4404 }
4405 return p;
4406}
4407#endif
4408
4409#if defined(FEAT_EVAL) || defined(PROTO)
4410
4411/*
4412 * Set the "v:lang" variable according to the current locale setting.
4413 * Also do "v:lc_time"and "v:ctype".
4414 */
4415 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004416set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417{
4418 char_u *loc;
4419
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004420# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004421 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422# else
4423 /* setlocale() not supported: use the default value */
4424 loc = (char_u *)"C";
4425# endif
4426 set_vim_var_string(VV_CTYPE, loc, -1);
4427
4428 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4429 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004430# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004431 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432# else
4433 loc = get_mess_env();
4434# endif
4435 set_vim_var_string(VV_LANG, loc, -1);
4436
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004437# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004438 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439# endif
4440 set_vim_var_string(VV_LC_TIME, loc, -1);
4441}
4442#endif
4443
4444#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4445 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4446/*
4447 * ":language": Set the language (locale).
4448 */
4449 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004450ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004451{
4452 char *loc;
4453 char_u *p;
4454 char_u *name;
4455 int what = LC_ALL;
4456 char *whatstr = "";
4457#ifdef LC_MESSAGES
4458# define VIM_LC_MESSAGES LC_MESSAGES
4459#else
4460# define VIM_LC_MESSAGES 6789
4461#endif
4462
4463 name = eap->arg;
4464
4465 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4466 * Allow abbreviation, but require at least 3 characters to avoid
4467 * confusion with a two letter language name "me" or "ct". */
4468 p = skiptowhite(eap->arg);
4469 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4470 {
4471 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4472 {
4473 what = VIM_LC_MESSAGES;
4474 name = skipwhite(p);
4475 whatstr = "messages ";
4476 }
4477 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4478 {
4479 what = LC_CTYPE;
4480 name = skipwhite(p);
4481 whatstr = "ctype ";
4482 }
4483 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4484 {
4485 what = LC_TIME;
4486 name = skipwhite(p);
4487 whatstr = "time ";
4488 }
4489 }
4490
4491 if (*name == NUL)
4492 {
4493#ifndef LC_MESSAGES
4494 if (what == VIM_LC_MESSAGES)
4495 p = get_mess_env();
4496 else
4497#endif
4498 p = (char_u *)setlocale(what, NULL);
4499 if (p == NULL || *p == NUL)
4500 p = (char_u *)"Unknown";
4501 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4502 }
4503 else
4504 {
4505#ifndef LC_MESSAGES
4506 if (what == VIM_LC_MESSAGES)
4507 loc = "";
4508 else
4509#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004510 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004512#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4513 /* Make sure strtod() uses a decimal point, not a comma. */
4514 setlocale(LC_NUMERIC, "C");
4515#endif
4516 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517 if (loc == NULL)
4518 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4519 else
4520 {
4521#ifdef HAVE_NL_MSG_CAT_CNTR
4522 /* Need to do this for GNU gettext, otherwise cached translations
4523 * will be used again. */
4524 extern int _nl_msg_cat_cntr;
4525
4526 ++_nl_msg_cat_cntr;
4527#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004528 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004529 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4530
4531 if (what != LC_TIME)
4532 {
4533 /* Tell gettext() what to translate to. It apparently doesn't
4534 * use the currently effective locale. Also do this when
4535 * FEAT_GETTEXT isn't defined, so that shell commands use this
4536 * value. */
4537 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004538 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004540
4541 /* Clear $LANGUAGE because GNU gettext uses it. */
4542 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004543# ifdef WIN32
4544 /* Apparently MS-Windows printf() may cause a crash when
4545 * we give it 8-bit text while it's expecting text in the
4546 * current locale. This call avoids that. */
4547 setlocale(LC_CTYPE, "C");
4548# endif
4549 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550 if (what != LC_CTYPE)
4551 {
4552 char_u *mname;
4553#ifdef WIN32
4554 mname = gettext_lang(name);
4555#else
4556 mname = name;
4557#endif
4558 vim_setenv((char_u *)"LC_MESSAGES", mname);
4559#ifdef FEAT_MULTI_LANG
4560 set_helplang_default(mname);
4561#endif
4562 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 }
4564
4565# ifdef FEAT_EVAL
4566 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4567 set_lang_var();
4568# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004569# ifdef FEAT_TITLE
4570 maketitle();
4571# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 }
4573 }
4574}
4575
4576# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004577
4578static char_u **locales = NULL; /* Array of all available locales */
4579static int did_init_locales = FALSE;
4580
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004581static void init_locales(void);
4582static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004583
4584/*
4585 * Lazy initialization of all available locales.
4586 */
4587 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004588init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004589{
4590 if (!did_init_locales)
4591 {
4592 did_init_locales = TRUE;
4593 locales = find_locales();
4594 }
4595}
4596
4597/* Return an array of strings for all available locales + NULL for the
4598 * last element. Return NULL in case of error. */
4599 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004600find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004601{
4602 garray_T locales_ga;
4603 char_u *loc;
4604
4605 /* Find all available locales by running command "locale -a". If this
4606 * doesn't work we won't have completion. */
4607 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004608 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004609 if (locale_a == NULL)
4610 return NULL;
4611 ga_init2(&locales_ga, sizeof(char_u *), 20);
4612
4613 /* Transform locale_a string where each locale is separated by "\n"
4614 * into an array of locale strings. */
4615 loc = (char_u *)strtok((char *)locale_a, "\n");
4616
4617 while (loc != NULL)
4618 {
4619 if (ga_grow(&locales_ga, 1) == FAIL)
4620 break;
4621 loc = vim_strsave(loc);
4622 if (loc == NULL)
4623 break;
4624
4625 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
4626 loc = (char_u *)strtok(NULL, "\n");
4627 }
4628 vim_free(locale_a);
4629 if (ga_grow(&locales_ga, 1) == FAIL)
4630 {
4631 ga_clear(&locales_ga);
4632 return NULL;
4633 }
4634 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
4635 return (char_u **)locales_ga.ga_data;
4636}
4637
4638# if defined(EXITFREE) || defined(PROTO)
4639 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004640free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004641{
4642 int i;
4643 if (locales != NULL)
4644 {
4645 for (i = 0; locales[i] != NULL; i++)
4646 vim_free(locales[i]);
4647 vim_free(locales);
4648 locales = NULL;
4649 }
4650}
4651# endif
4652
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653/*
4654 * Function given to ExpandGeneric() to obtain the possible arguments of the
4655 * ":language" command.
4656 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004658get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659{
4660 if (idx == 0)
4661 return (char_u *)"messages";
4662 if (idx == 1)
4663 return (char_u *)"ctype";
4664 if (idx == 2)
4665 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004666
4667 init_locales();
4668 if (locales == NULL)
4669 return NULL;
4670 return locales[idx - 3];
4671}
4672
4673/*
4674 * Function given to ExpandGeneric() to obtain the available locales.
4675 */
4676 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004677get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004678{
4679 init_locales();
4680 if (locales == NULL)
4681 return NULL;
4682 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683}
4684# endif
4685
4686#endif