blob: 83305b240743bd54aa55637af3576c4d1eb9dbc7 [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;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200167 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000168 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 if (typeahead_saved)
171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000173 ignore_script = save_ignore_script;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
177 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100178 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100198 case 'f':
199 last_cmd = 0;
200 if (p[1] == 'r')
201 {
202 last_cmd = CMD_FRAME;
203 tail = "rame";
204 }
205 else
206 {
207 last_cmd = CMD_FINISH;
208 tail = "inish";
209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100217 case 'b': last_cmd = CMD_BACKTRACE;
218 if (p[1] == 't')
219 tail = "t";
220 else
221 tail = "acktrace";
222 break;
223 case 'w': last_cmd = CMD_BACKTRACE;
224 tail = "here";
225 break;
226 case 'u': last_cmd = CMD_UP;
227 tail = "p";
228 break;
229 case 'd': last_cmd = CMD_DOWN;
230 tail = "own";
231 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 default: last_cmd = 0;
233 }
234 if (last_cmd != 0)
235 {
236 /* Check that the tail matches. */
237 ++p;
238 while (*p != NUL && *p == *tail)
239 {
240 ++p;
241 ++tail;
242 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100243 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 last_cmd = 0;
245 }
246 }
247
248 if (last_cmd != 0)
249 {
250 /* Execute debug command: decided where to break next and
251 * return. */
252 switch (last_cmd)
253 {
254 case CMD_CONT:
255 debug_break_level = -1;
256 break;
257 case CMD_NEXT:
258 debug_break_level = ex_nesting_level;
259 break;
260 case CMD_STEP:
261 debug_break_level = 9999;
262 break;
263 case CMD_FINISH:
264 debug_break_level = ex_nesting_level - 1;
265 break;
266 case CMD_QUIT:
267 got_int = TRUE;
268 debug_break_level = -1;
269 break;
270 case CMD_INTERRUPT:
271 got_int = TRUE;
272 debug_break_level = 9999;
273 /* Do not repeat ">interrupt" cmd, continue stepping. */
274 last_cmd = CMD_STEP;
275 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100276 case CMD_BACKTRACE:
277 do_showbacktrace(cmd);
278 continue;
279 case CMD_FRAME:
280 if (*p == NUL)
281 {
282 do_showbacktrace(cmd);
283 }
284 else
285 {
286 p = skipwhite(p);
287 do_setdebugtracelevel(p);
288 }
289 continue;
290 case CMD_UP:
291 debug_backtrace_level++;
292 do_checkbacktracelevel();
293 continue;
294 case CMD_DOWN:
295 debug_backtrace_level--;
296 do_checkbacktracelevel();
297 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100299 /* Going out reset backtrace_level */
300 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 break;
302 }
303
304 /* don't debug this command */
305 n = debug_break_level;
306 debug_break_level = -1;
307 (void)do_cmdline(cmdline, getexline, NULL,
308 DOCMD_VERBOSE|DOCMD_EXCRESET);
309 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 }
311 lines_left = Rows - 1;
312 }
313 vim_free(cmdline);
314
315 --RedrawingDisabled;
316 --no_wait_return;
317 redraw_all_later(NOT_VALID);
318 need_wait_return = FALSE;
319 msg_scroll = save_msg_scroll;
320 lines_left = Rows - 1;
321 State = save_State;
322 did_emsg = save_did_emsg;
323 cmd_silent = save_cmd_silent;
324 msg_silent = save_msg_silent;
325 emsg_silent = save_emsg_silent;
326 redir_off = save_redir_off;
327
328 /* Only print the message again when typing a command before coming back
329 * here. */
330 debug_did_msg = TRUE;
331}
332
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100333 static int
334get_maxbacktrace_level(void)
335{
336 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200337 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 if (sourcing_name != NULL)
340 {
341 p = (char *)sourcing_name;
342 while ((q = strstr(p, "..")) != NULL)
343 {
344 p = q + 2;
345 maxbacktrace++;
346 }
347 }
348 return maxbacktrace;
349}
350
351 static void
352do_setdebugtracelevel(char_u *arg)
353{
354 int level;
355
356 level = atoi((char *)arg);
357 if (*arg == '+' || level < 0)
358 debug_backtrace_level += level;
359 else
360 debug_backtrace_level = level;
361
362 do_checkbacktracelevel();
363}
364
365 static void
366do_checkbacktracelevel(void)
367{
368 if (debug_backtrace_level < 0)
369 {
370 debug_backtrace_level = 0;
371 MSG(_("frame is zero"));
372 }
373 else
374 {
375 int max = get_maxbacktrace_level();
376
377 if (debug_backtrace_level > max)
378 {
379 debug_backtrace_level = max;
380 smsg((char_u *)_("frame at highest level: %d"), max);
381 }
382 }
383}
384
385 static void
386do_showbacktrace(char_u *cmd)
387{
388 char *cur;
389 char *next;
390 int i = 0;
391 int max = get_maxbacktrace_level();
392
393 if (sourcing_name != NULL)
394 {
395 cur = (char *)sourcing_name;
396 while (!got_int)
397 {
398 next = strstr(cur, "..");
399 if (next != NULL)
400 *next = NUL;
401 if (i == max - debug_backtrace_level)
402 smsg((char_u *)"->%d %s", max - i, cur);
403 else
404 smsg((char_u *)" %d %s", max - i, cur);
405 ++i;
406 if (next == NULL)
407 break;
408 *next = '.';
409 cur = next + 2;
410 }
411 }
412 if (sourcing_lnum != 0)
413 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
414 else
415 smsg((char_u *)_("cmd: %s"), cmd);
416}
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/*
419 * ":debug".
420 */
421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100422ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423{
424 int debug_break_level_save = debug_break_level;
425
426 debug_break_level = 9999;
427 do_cmdline_cmd(eap->arg);
428 debug_break_level = debug_break_level_save;
429}
430
431static char_u *debug_breakpoint_name = NULL;
432static linenr_T debug_breakpoint_lnum;
433
434/*
435 * When debugging or a breakpoint is set on a skipped command, no debug prompt
436 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
437 * debug_skipped_name is then set to the source name in the breakpoint case. If
438 * a skipped command decides itself that a debug prompt should be displayed, it
439 * can do so by calling dbg_check_skipped().
440 */
441static int debug_skipped;
442static char_u *debug_skipped_name;
443
444/*
445 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
446 * at or below the break level. But only when the line is actually
447 * executed. Return TRUE and set breakpoint_name for skipped commands that
448 * decide to execute something themselves.
449 * Called from do_one_cmd() before executing a command.
450 */
451 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100452dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p;
455
456 debug_skipped = FALSE;
457 if (debug_breakpoint_name != NULL)
458 {
459 if (!eap->skip)
460 {
461 /* replace K_SNR with "<SNR>" */
462 if (debug_breakpoint_name[0] == K_SPECIAL
463 && debug_breakpoint_name[1] == KS_EXTRA
464 && debug_breakpoint_name[2] == (int)KE_SNR)
465 p = (char_u *)"<SNR>";
466 else
467 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000468 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
469 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 debug_breakpoint_name + (*p == NUL ? 0 : 3),
471 (long)debug_breakpoint_lnum);
472 debug_breakpoint_name = NULL;
473 do_debug(eap->cmd);
474 }
475 else
476 {
477 debug_skipped = TRUE;
478 debug_skipped_name = debug_breakpoint_name;
479 debug_breakpoint_name = NULL;
480 }
481 }
482 else if (ex_nesting_level <= debug_break_level)
483 {
484 if (!eap->skip)
485 do_debug(eap->cmd);
486 else
487 {
488 debug_skipped = TRUE;
489 debug_skipped_name = NULL;
490 }
491 }
492}
493
494/*
495 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
496 * set. Return TRUE when the debug mode is entered this time.
497 */
498 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100499dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500{
501 int prev_got_int;
502
503 if (debug_skipped)
504 {
505 /*
506 * Save the value of got_int and reset it. We don't want a previous
507 * interruption cause flushing the input buffer.
508 */
509 prev_got_int = got_int;
510 got_int = FALSE;
511 debug_breakpoint_name = debug_skipped_name;
512 /* eap->skip is TRUE */
513 eap->skip = FALSE;
514 (void)dbg_check_breakpoint(eap);
515 eap->skip = TRUE;
516 got_int |= prev_got_int;
517 return TRUE;
518 }
519 return FALSE;
520}
521
522/*
523 * The list of breakpoints: dbg_breakp.
524 * This is a grow-array of structs.
525 */
526struct debuggy
527{
528 int dbg_nr; /* breakpoint number */
529 int dbg_type; /* DBG_FUNC or DBG_FILE */
530 char_u *dbg_name; /* function or file name */
531 regprog_T *dbg_prog; /* regexp program */
532 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534};
535
536static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000537#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
538#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539static int last_breakp = 0; /* nr of last defined breakpoint */
540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541#ifdef FEAT_PROFILE
542/* Profiling uses file and func names similar to breakpoints. */
543static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545#define DBG_FUNC 1
546#define DBG_FILE 2
547
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100548static int dbg_parsearg(char_u *arg, garray_T *gap);
549static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
551/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000552 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
553 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
554 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 * Returns FAIL for failure.
556 */
557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100558dbg_parsearg(
559 char_u *arg,
560 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
562 char_u *p = arg;
563 char_u *q;
564 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000565 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570
571 /* Find "func" or "file". */
572 if (STRNCMP(p, "func", 4) == 0)
573 bp->dbg_type = DBG_FUNC;
574 else if (STRNCMP(p, "file", 4) == 0)
575 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 else if (
577#ifdef FEAT_PROFILE
578 gap != &prof_ga &&
579#endif
580 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000581 {
582 if (curbuf->b_ffname == NULL)
583 {
584 EMSG(_(e_noname));
585 return FAIL;
586 }
587 bp->dbg_type = DBG_FILE;
588 here = TRUE;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else
591 {
592 EMSG2(_(e_invarg2), p);
593 return FAIL;
594 }
595 p = skipwhite(p + 4);
596
597 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 if (here)
599 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000600 else if (
601#ifdef FEAT_PROFILE
602 gap != &prof_ga &&
603#endif
604 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
606 bp->dbg_lnum = getdigits(&p);
607 p = skipwhite(p);
608 }
609 else
610 bp->dbg_lnum = 0;
611
612 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000613 if ((!here && *p == NUL)
614 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
616 {
617 EMSG2(_(e_invarg2), arg);
618 return FAIL;
619 }
620
621 if (bp->dbg_type == DBG_FUNC)
622 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000623 else if (here)
624 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* Expand the file name in the same way as do_source(). This means
628 * doing it twice, so that $DIR/file gets expanded when $DIR is
629 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (q == NULL)
632 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 vim_free(q);
635 if (p == NULL)
636 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000637 if (*p != '*')
638 {
639 bp->dbg_name = fix_fname(p);
640 vim_free(p);
641 }
642 else
643 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
645
646 if (bp->dbg_name == NULL)
647 return FAIL;
648 return OK;
649}
650
651/*
652 * ":breakadd".
653 */
654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100655ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 struct debuggy *bp;
658 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000659 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaar05159a02005-02-26 23:04:13 +0000661 gap = &dbg_breakp;
662#ifdef FEAT_PROFILE
663 if (eap->cmdidx == CMD_profile)
664 gap = &prof_ga;
665#endif
666
667 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000669 bp = &DEBUGGY(gap, gap->ga_len);
670 bp->dbg_forceit = eap->forceit;
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
673 if (pat != NULL)
674 {
675 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
676 vim_free(pat);
677 }
678 if (pat == NULL || bp->dbg_prog == NULL)
679 vim_free(bp->dbg_name);
680 else
681 {
682 if (bp->dbg_lnum == 0) /* default line number is 1 */
683 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000684#ifdef FEAT_PROFILE
685 if (eap->cmdidx != CMD_profile)
686#endif
687 {
688 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
689 ++debug_tick;
690 }
691 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 }
693 }
694}
695
696/*
697 * ":debuggreedy".
698 */
699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100700ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701{
702 if (eap->addr_count == 0 || eap->line2 != 0)
703 debug_greedy = TRUE;
704 else
705 debug_greedy = FALSE;
706}
707
708/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000709 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 */
711 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100712ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713{
714 struct debuggy *bp, *bpi;
715 int nr;
716 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000717 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 int i;
719 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000720 garray_T *gap;
721
722 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000723 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200724 {
725#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000726 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200727#else
728 ex_ni(eap);
729 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (vim_isdigit(*eap->arg))
734 {
735 /* ":breakdel {nr}" */
736 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737 for (i = 0; i < gap->ga_len; ++i)
738 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 todel = i;
741 break;
742 }
743 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000744 else if (*eap->arg == '*')
745 {
746 todel = 0;
747 del_all = TRUE;
748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 else
750 {
751 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000752 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000754 bp = &DEBUGGY(gap, gap->ga_len);
755 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 if (bp->dbg_type == bpi->dbg_type
759 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
760 && (bp->dbg_lnum == bpi->dbg_lnum
761 || (bp->dbg_lnum == 0
762 && (best_lnum == 0
763 || bpi->dbg_lnum < best_lnum))))
764 {
765 todel = i;
766 best_lnum = bpi->dbg_lnum;
767 }
768 }
769 vim_free(bp->dbg_name);
770 }
771
772 if (todel < 0)
773 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
774 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000775 {
776 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000777 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000778 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200779 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000780 --gap->ga_len;
781 if (todel < gap->ga_len)
782 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
783 (gap->ga_len - todel) * sizeof(struct debuggy));
784#ifdef FEAT_PROFILE
785 if (eap->cmdidx == CMD_breakdel)
786#endif
787 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000788 if (!del_all)
789 break;
790 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791
792 /* If all breakpoints were removed clear the array. */
793 if (gap->ga_len == 0)
794 ga_clear(gap);
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796}
797
798/*
799 * ":breaklist".
800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100802ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803{
804 struct debuggy *bp;
805 int i;
806
807 if (dbg_breakp.ga_len == 0)
808 MSG(_("No breakpoints defined"));
809 else
810 for (i = 0; i < dbg_breakp.ga_len; ++i)
811 {
812 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200813 if (bp->dbg_type == DBG_FILE)
814 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 smsg((char_u *)_("%3d %s %s line %ld"),
816 bp->dbg_nr,
817 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200818 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 (long)bp->dbg_lnum);
820 }
821}
822
823/*
824 * Find a breakpoint for a function or sourced file.
825 * Returns line number at which to break; zero when no matching breakpoint.
826 */
827 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100828dbg_find_breakpoint(
829 int file, /* TRUE for a file, FALSE for a function */
830 char_u *fname, /* file or function name */
831 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
834}
835
836#if defined(FEAT_PROFILE) || defined(PROTO)
837/*
838 * Return TRUE if profiling is on for a function or sourced file.
839 */
840 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841has_profiling(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
847 != (linenr_T)0);
848}
849#endif
850
851/*
852 * Common code for dbg_find_breakpoint() and has_profiling().
853 */
854 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100855debuggy_find(
856 int file, /* TRUE for a file, FALSE for a function */
857 char_u *fname, /* file or function name */
858 linenr_T after, /* after this line number */
859 garray_T *gap, /* either &dbg_breakp or &prof_ga */
860 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 struct debuggy *bp;
863 int i;
864 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 char_u *name = fname;
866 int prev_got_int;
867
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868 /* Return quickly when there are no breakpoints. */
869 if (gap->ga_len == 0)
870 return (linenr_T)0;
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Replace K_SNR in function name with "<SNR>". */
873 if (!file && fname[0] == K_SPECIAL)
874 {
875 name = alloc((unsigned)STRLEN(fname) + 3);
876 if (name == NULL)
877 name = fname;
878 else
879 {
880 STRCPY(name, "<SNR>");
881 STRCPY(name + 5, fname + 3);
882 }
883 }
884
Bram Moolenaar05159a02005-02-26 23:04:13 +0000885 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000887 /* Skip entries that are not useful or are for a line that is beyond
888 * an already found breakpoint. */
889 bp = &DEBUGGY(gap, i);
890 if (((bp->dbg_type == DBG_FILE) == file && (
891#ifdef FEAT_PROFILE
892 gap == &prof_ga ||
893#endif
894 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000897 * Save the value of got_int and reset it. We don't want a
898 * previous interruption cancel matching, only hitting CTRL-C
899 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 */
901 prev_got_int = got_int;
902 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100903 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 if (fp != NULL)
907 *fp = bp->dbg_forceit;
908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 got_int |= prev_got_int;
910 }
911 }
912 if (name != fname)
913 vim_free(name);
914
915 return lnum;
916}
917
918/*
919 * Called when a breakpoint was encountered.
920 */
921 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100922dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923{
924 /* We need to check if this line is actually executed in do_one_cmd() */
925 debug_breakpoint_name = name;
926 debug_breakpoint_lnum = lnum;
927}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928
929
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000930# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000931/*
932 * Store the current time in "tm".
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000937# ifdef WIN3264
938 QueryPerformanceCounter(tm);
939# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000940 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000941# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000942}
943
944/*
945 * Compute the elapsed time from "tm" till now and store in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
950 proftime_T now;
951
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000952# ifdef WIN3264
953 QueryPerformanceCounter(&now);
954 tm->QuadPart = now.QuadPart - tm->QuadPart;
955# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956 gettimeofday(&now, NULL);
957 tm->tv_usec = now.tv_usec - tm->tv_usec;
958 tm->tv_sec = now.tv_sec - tm->tv_sec;
959 if (tm->tv_usec < 0)
960 {
961 tm->tv_usec += 1000000;
962 --tm->tv_sec;
963 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000964# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965}
966
967/*
968 * Subtract the time "tm2" from "tm".
969 */
970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100971profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000973# ifdef WIN3264
974 tm->QuadPart -= tm2->QuadPart;
975# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 tm->tv_usec -= tm2->tv_usec;
977 tm->tv_sec -= tm2->tv_sec;
978 if (tm->tv_usec < 0)
979 {
980 tm->tv_usec += 1000000;
981 --tm->tv_sec;
982 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984}
985
986/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000987 * Return a string that represents the time in "tm".
988 * Uses a static buffer!
989 */
990 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100991profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000992{
993 static char buf[50];
994
995# ifdef WIN3264
996 LARGE_INTEGER fr;
997
998 QueryPerformanceFrequency(&fr);
999 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1000# else
1001 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001002# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001003 return buf;
1004}
1005
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001006# if defined(FEAT_FLOAT) || defined(PROTO)
1007/*
1008 * Return a float that represents the time in "tm".
1009 */
1010 float_T
1011profile_float(proftime_T *tm)
1012{
1013# ifdef WIN3264
1014 LARGE_INTEGER fr;
1015
1016 QueryPerformanceFrequency(&fr);
1017 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1018# else
1019 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1020# endif
1021}
1022# endif
1023
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001024/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001025 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001026 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001027 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001028profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001029{
1030 if (msec <= 0) /* no limit */
1031 profile_zero(tm);
1032 else
1033 {
1034# ifdef WIN3264
1035 LARGE_INTEGER fr;
1036
1037 QueryPerformanceCounter(tm);
1038 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001039 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001040# else
1041 long usec;
1042
1043 gettimeofday(tm, NULL);
1044 usec = (long)tm->tv_usec + (long)msec * 1000;
1045 tm->tv_usec = usec % 1000000L;
1046 tm->tv_sec += usec / 1000000L;
1047# endif
1048 }
1049}
1050
1051/*
1052 * Return TRUE if the current time is past "tm".
1053 */
1054 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001055profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001056{
1057 proftime_T now;
1058
1059# ifdef WIN3264
1060 if (tm->QuadPart == 0) /* timer was not set */
1061 return FALSE;
1062 QueryPerformanceCounter(&now);
1063 return (now.QuadPart > tm->QuadPart);
1064# else
1065 if (tm->tv_sec == 0) /* timer was not set */
1066 return FALSE;
1067 gettimeofday(&now, NULL);
1068 return (now.tv_sec > tm->tv_sec
1069 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1070# endif
1071}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001072
1073/*
1074 * Set the time in "tm" to zero.
1075 */
1076 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001077profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001078{
1079# ifdef WIN3264
1080 tm->QuadPart = 0;
1081# else
1082 tm->tv_usec = 0;
1083 tm->tv_sec = 0;
1084# endif
1085}
1086
Bram Moolenaar76929292008-01-06 19:07:36 +00001087# endif /* FEAT_PROFILE || FEAT_RELTIME */
1088
Bram Moolenaar975b5272016-03-15 23:10:59 +01001089# if defined(FEAT_TIMERS) || defined(PROTO)
1090static timer_T *first_timer = NULL;
1091static int last_timer_id = 0;
1092
1093/*
1094 * Insert a timer in the list of timers.
1095 */
1096 static void
1097insert_timer(timer_T *timer)
1098{
1099 timer->tr_next = first_timer;
1100 timer->tr_prev = NULL;
1101 if (first_timer != NULL)
1102 first_timer->tr_prev = timer;
1103 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001104 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001105}
1106
1107/*
1108 * Take a timer out of the list of timers.
1109 */
1110 static void
1111remove_timer(timer_T *timer)
1112{
1113 if (timer->tr_prev == NULL)
1114 first_timer = timer->tr_next;
1115 else
1116 timer->tr_prev->tr_next = timer->tr_next;
1117 if (timer->tr_next != NULL)
1118 timer->tr_next->tr_prev = timer->tr_prev;
1119}
1120
1121 static void
1122free_timer(timer_T *timer)
1123{
Bram Moolenaar1436d8d2016-07-11 22:41:15 +02001124 free_callback(timer->tr_callback, timer->tr_partial);
Bram Moolenaar975b5272016-03-15 23:10:59 +01001125 vim_free(timer);
1126}
1127
1128/*
1129 * Create a timer and return it. NULL if out of memory.
1130 * Caller should set the callback.
1131 */
1132 timer_T *
1133create_timer(long msec, int repeat)
1134{
1135 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
1136
1137 if (timer == NULL)
1138 return NULL;
1139 timer->tr_id = ++last_timer_id;
1140 insert_timer(timer);
1141 if (repeat != 0)
1142 {
1143 timer->tr_repeat = repeat - 1;
1144 timer->tr_interval = msec;
1145 }
1146
1147 profile_setlimit(msec, &timer->tr_due);
1148 return timer;
1149}
1150
1151/*
1152 * Invoke the callback of "timer".
1153 */
1154 static void
1155timer_callback(timer_T *timer)
1156{
1157 typval_T rettv;
1158 int dummy;
1159 typval_T argv[2];
1160
1161 argv[0].v_type = VAR_NUMBER;
1162 argv[0].vval.v_number = timer->tr_id;
1163 argv[1].v_type = VAR_UNKNOWN;
1164
1165 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001166 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001167 timer->tr_partial, NULL);
1168 clear_tv(&rettv);
1169}
1170
1171/*
1172 * Call timers that are due.
1173 * Return the time in msec until the next timer is due.
1174 */
1175 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001176check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001177{
1178 timer_T *timer;
1179 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001180 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001181 proftime_T now;
1182 int did_one = FALSE;
1183# ifdef WIN3264
1184 LARGE_INTEGER fr;
1185
1186 QueryPerformanceFrequency(&fr);
1187# endif
1188 while (!got_int)
1189 {
1190 profile_start(&now);
1191 next_due = -1;
1192 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1193 {
1194# ifdef WIN3264
1195 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1196 / (double)fr.QuadPart) * 1000);
1197# else
1198 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1199 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1200# endif
1201 if (this_due <= 1)
1202 {
1203 remove_timer(timer);
1204 timer_callback(timer);
1205 did_one = TRUE;
1206 if (timer->tr_repeat != 0)
1207 {
1208 profile_setlimit(timer->tr_interval, &timer->tr_due);
1209 if (timer->tr_repeat > 0)
1210 --timer->tr_repeat;
1211 insert_timer(timer);
1212 }
1213 else
1214 free_timer(timer);
1215 /* the callback may do anything, start all over */
1216 break;
1217 }
1218 if (next_due == -1 || next_due > this_due)
1219 next_due = this_due;
1220 }
1221 if (timer == NULL)
1222 break;
1223 }
1224
1225 if (did_one)
1226 redraw_after_callback();
1227
1228 return next_due;
1229}
1230
1231/*
1232 * Find a timer by ID. Returns NULL if not found;
1233 */
1234 timer_T *
1235find_timer(int id)
1236{
1237 timer_T *timer;
1238
1239 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1240 if (timer->tr_id == id)
1241 break;
1242 return timer;
1243}
1244
1245
1246/*
1247 * Stop a timer and delete it.
1248 */
1249 void
1250stop_timer(timer_T *timer)
1251{
1252 remove_timer(timer);
1253 free_timer(timer);
1254}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001255
1256/*
1257 * Mark references in partials of timers.
1258 */
1259 int
1260set_ref_in_timer(int copyID)
1261{
1262 int abort = FALSE;
1263 timer_T *timer;
1264 typval_T tv;
1265
1266 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1267 {
1268 tv.v_type = VAR_PARTIAL;
1269 tv.vval.v_partial = timer->tr_partial;
1270 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1271 }
1272 return abort;
1273}
Bram Moolenaar975b5272016-03-15 23:10:59 +01001274# endif
1275
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001276#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1277# if defined(HAVE_MATH_H)
1278# include <math.h>
1279# endif
1280
1281/*
1282 * Divide the time "tm" by "count" and store in "tm2".
1283 */
1284 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001285profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001286{
1287 if (count == 0)
1288 profile_zero(tm2);
1289 else
1290 {
1291# ifdef WIN3264
1292 tm2->QuadPart = tm->QuadPart / count;
1293# else
1294 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1295
1296 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001297 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001298# endif
1299 }
1300}
1301#endif
1302
Bram Moolenaar76929292008-01-06 19:07:36 +00001303# if defined(FEAT_PROFILE) || defined(PROTO)
1304/*
1305 * Functions for profiling.
1306 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001307static void script_do_profile(scriptitem_T *si);
1308static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001309static proftime_T prof_wait_time;
1310
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001311/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001312 * Add the time "tm2" to "tm".
1313 */
1314 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001315profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001316{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001317# ifdef WIN3264
1318 tm->QuadPart += tm2->QuadPart;
1319# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001320 tm->tv_usec += tm2->tv_usec;
1321 tm->tv_sec += tm2->tv_sec;
1322 if (tm->tv_usec >= 1000000)
1323 {
1324 tm->tv_usec -= 1000000;
1325 ++tm->tv_sec;
1326 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001327# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001328}
1329
1330/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001331 * Add the "self" time from the total time and the children's time.
1332 */
1333 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001334profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001335{
1336 /* Check that the result won't be negative. Can happen with recursive
1337 * calls. */
1338#ifdef WIN3264
1339 if (total->QuadPart <= children->QuadPart)
1340 return;
1341#else
1342 if (total->tv_sec < children->tv_sec
1343 || (total->tv_sec == children->tv_sec
1344 && total->tv_usec <= children->tv_usec))
1345 return;
1346#endif
1347 profile_add(self, total);
1348 profile_sub(self, children);
1349}
1350
1351/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001352 * Get the current waittime.
1353 */
1354 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001355profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001356{
1357 *tm = prof_wait_time;
1358}
1359
1360/*
1361 * Subtract the passed waittime since "tm" from "tma".
1362 */
1363 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001364profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001365{
1366 proftime_T tm3 = prof_wait_time;
1367
1368 profile_sub(&tm3, tm);
1369 profile_sub(tma, &tm3);
1370}
1371
1372/*
1373 * Return TRUE if "tm1" and "tm2" are equal.
1374 */
1375 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001376profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001377{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001378# ifdef WIN3264
1379 return (tm1->QuadPart == tm2->QuadPart);
1380# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001381 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001382# endif
1383}
1384
1385/*
1386 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1387 */
1388 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001389profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001390{
1391# ifdef WIN3264
1392 return (int)(tm2->QuadPart - tm1->QuadPart);
1393# else
1394 if (tm1->tv_sec == tm2->tv_sec)
1395 return tm2->tv_usec - tm1->tv_usec;
1396 return tm2->tv_sec - tm1->tv_sec;
1397# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001398}
1399
Bram Moolenaar05159a02005-02-26 23:04:13 +00001400static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001401static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001402
1403/*
1404 * ":profile cmd args"
1405 */
1406 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001407ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001408{
1409 char_u *e;
1410 int len;
1411
1412 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001413 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001414 e = skipwhite(e);
1415
1416 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1417 {
1418 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001419 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001420 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001421 profile_zero(&prof_wait_time);
1422 set_vim_var_nr(VV_PROFILING, 1L);
1423 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001424 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001425 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001426 else if (STRCMP(eap->arg, "pause") == 0)
1427 {
1428 if (do_profiling == PROF_YES)
1429 profile_start(&pause_time);
1430 do_profiling = PROF_PAUSED;
1431 }
1432 else if (STRCMP(eap->arg, "continue") == 0)
1433 {
1434 if (do_profiling == PROF_PAUSED)
1435 {
1436 profile_end(&pause_time);
1437 profile_add(&prof_wait_time, &pause_time);
1438 }
1439 do_profiling = PROF_YES;
1440 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001441 else
1442 {
1443 /* The rest is similar to ":breakadd". */
1444 ex_breakadd(eap);
1445 }
1446}
1447
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001448/* Command line expansion for :profile. */
1449static enum
1450{
1451 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001452 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001453} pexpand_what;
1454
1455static char *pexpand_cmds[] = {
1456 "start",
1457#define PROFCMD_START 0
1458 "pause",
1459#define PROFCMD_PAUSE 1
1460 "continue",
1461#define PROFCMD_CONTINUE 2
1462 "func",
1463#define PROFCMD_FUNC 3
1464 "file",
1465#define PROFCMD_FILE 4
1466 NULL
1467#define PROFCMD_LAST 5
1468};
1469
1470/*
1471 * Function given to ExpandGeneric() to obtain the profile command
1472 * specific expansion.
1473 */
1474 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001475get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001476{
1477 switch (pexpand_what)
1478 {
1479 case PEXP_SUBCMD:
1480 return (char_u *)pexpand_cmds[idx];
1481 /* case PEXP_FUNC: TODO */
1482 default:
1483 return NULL;
1484 }
1485}
1486
1487/*
1488 * Handle command line completion for :profile command.
1489 */
1490 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001491set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001492{
1493 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001494
1495 /* Default: expand subcommands. */
1496 xp->xp_context = EXPAND_PROFILE;
1497 pexpand_what = PEXP_SUBCMD;
1498 xp->xp_pattern = arg;
1499
1500 end_subcmd = skiptowhite(arg);
1501 if (*end_subcmd == NUL)
1502 return;
1503
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001504 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001505 {
1506 xp->xp_context = EXPAND_FILES;
1507 xp->xp_pattern = skipwhite(end_subcmd);
1508 return;
1509 }
1510
1511 /* TODO: expand function names after "func" */
1512 xp->xp_context = EXPAND_NOTHING;
1513}
1514
Bram Moolenaar05159a02005-02-26 23:04:13 +00001515/*
1516 * Dump the profiling info.
1517 */
1518 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001519profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001520{
1521 FILE *fd;
1522
1523 if (profile_fname != NULL)
1524 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001525 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001526 if (fd == NULL)
1527 EMSG2(_(e_notopen), profile_fname);
1528 else
1529 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001530 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001531 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001532 fclose(fd);
1533 }
1534 }
1535}
1536
1537/*
1538 * Start profiling script "fp".
1539 */
1540 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001541script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001542{
1543 si->sn_pr_count = 0;
1544 profile_zero(&si->sn_pr_total);
1545 profile_zero(&si->sn_pr_self);
1546
1547 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1548 si->sn_prl_idx = -1;
1549 si->sn_prof_on = TRUE;
1550 si->sn_pr_nest = 0;
1551}
1552
1553/*
1554 * save time when starting to invoke another script or function.
1555 */
1556 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001557script_prof_save(
1558 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001559{
1560 scriptitem_T *si;
1561
1562 if (current_SID > 0 && current_SID <= script_items.ga_len)
1563 {
1564 si = &SCRIPT_ITEM(current_SID);
1565 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1566 profile_start(&si->sn_pr_child);
1567 }
1568 profile_get_wait(tm);
1569}
1570
1571/*
1572 * Count time spent in children after invoking another script or function.
1573 */
1574 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001575script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001576{
1577 scriptitem_T *si;
1578
1579 if (current_SID > 0 && current_SID <= script_items.ga_len)
1580 {
1581 si = &SCRIPT_ITEM(current_SID);
1582 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1583 {
1584 profile_end(&si->sn_pr_child);
1585 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1586 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1587 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1588 }
1589 }
1590}
1591
1592static proftime_T inchar_time;
1593
1594/*
1595 * Called when starting to wait for the user to type a character.
1596 */
1597 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001598prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001599{
1600 profile_start(&inchar_time);
1601}
1602
1603/*
1604 * Called when finished waiting for the user to type a character.
1605 */
1606 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001607prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001608{
1609 profile_end(&inchar_time);
1610 profile_add(&prof_wait_time, &inchar_time);
1611}
1612
1613/*
1614 * Dump the profiling results for all scripts in file "fd".
1615 */
1616 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001617script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001618{
1619 int id;
1620 scriptitem_T *si;
1621 int i;
1622 FILE *sfd;
1623 sn_prl_T *pp;
1624
1625 for (id = 1; id <= script_items.ga_len; ++id)
1626 {
1627 si = &SCRIPT_ITEM(id);
1628 if (si->sn_prof_on)
1629 {
1630 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1631 if (si->sn_pr_count == 1)
1632 fprintf(fd, "Sourced 1 time\n");
1633 else
1634 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1635 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1636 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1637 fprintf(fd, "\n");
1638 fprintf(fd, "count total (s) self (s)\n");
1639
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001640 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001641 if (sfd == NULL)
1642 fprintf(fd, "Cannot open file!\n");
1643 else
1644 {
1645 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1646 {
1647 if (vim_fgets(IObuff, IOSIZE, sfd))
1648 break;
1649 pp = &PRL_ITEM(si, i);
1650 if (pp->snp_count > 0)
1651 {
1652 fprintf(fd, "%5d ", pp->snp_count);
1653 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1654 fprintf(fd, " ");
1655 else
1656 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1657 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1658 }
1659 else
1660 fprintf(fd, " ");
1661 fprintf(fd, "%s", IObuff);
1662 }
1663 fclose(sfd);
1664 }
1665 fprintf(fd, "\n");
1666 }
1667 }
1668}
1669
1670/*
1671 * Return TRUE when a function defined in the current script should be
1672 * profiled.
1673 */
1674 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001675prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001676{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001677 if (current_SID > 0)
1678 return SCRIPT_ITEM(current_SID).sn_pr_force;
1679 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001680}
1681
1682# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683#endif
1684
1685/*
1686 * If 'autowrite' option set, try to write the file.
1687 * Careful: autocommands may make "buf" invalid!
1688 *
1689 * return FAIL for failure, OK otherwise
1690 */
1691 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001692autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001694 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001695 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001696
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 if (!(p_aw || p_awa) || !p_write
1698#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001699 /* never autowrite a "nofile" or "nowrite" buffer */
1700 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001701#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001702 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001703 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001704 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001705 r = buf_write_all(buf, forceit);
1706
1707 /* Writing may succeed but the buffer still changed, e.g., when there is a
1708 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001709 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001710 r = FAIL;
1711 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712}
1713
1714/*
1715 * flush all buffers, except the ones that are readonly
1716 */
1717 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001718autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719{
1720 buf_T *buf;
1721
1722 if (!(p_aw || p_awa) || !p_write)
1723 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001724 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001725 if (bufIsChanged(buf) && !buf->b_p_ro)
1726 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001727#ifdef FEAT_AUTOCMD
1728 bufref_T bufref;
1729
1730 set_bufref(&bufref, buf);
1731#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 (void)buf_write_all(buf, FALSE);
1733#ifdef FEAT_AUTOCMD
1734 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001735 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001736 buf = firstbuf;
1737#endif
1738 }
1739}
1740
1741/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001742 * Return TRUE if buffer was changed and cannot be abandoned.
1743 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001746check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001748 int forceit = (flags & CCGD_FORCEIT);
1749#ifdef FEAT_AUTOCMD
1750 bufref_T bufref;
1751
1752 set_bufref(&bufref, buf);
1753#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001754
Bram Moolenaar071d4272004-06-13 20:20:40 +00001755 if ( !forceit
1756 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001757 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1758 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 {
1760#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1761 if ((p_confirm || cmdmod.confirm) && p_write)
1762 {
1763 buf_T *buf2;
1764 int count = 0;
1765
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001766 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001767 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 if (bufIsChanged(buf2)
1769 && (buf2->b_ffname != NULL
1770# ifdef FEAT_BROWSE
1771 || cmdmod.browse
1772# endif
1773 ))
1774 ++count;
1775# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001776 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001777 /* Autocommand deleted buffer, oops! It's not changed now. */
1778 return FALSE;
1779# endif
1780 dialog_changed(buf, count > 1);
1781# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001782 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 /* Autocommand deleted buffer, oops! It's not changed now. */
1784 return FALSE;
1785# endif
1786 return bufIsChanged(buf);
1787 }
1788#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001789 if (flags & CCGD_EXCMD)
1790 EMSG(_(e_nowrtmsg));
1791 else
1792 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 return TRUE;
1794 }
1795 return FALSE;
1796}
1797
1798#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1799
1800#if defined(FEAT_BROWSE) || defined(PROTO)
1801/*
1802 * When wanting to write a file without a file name, ask the user for a name.
1803 */
1804 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001805browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806{
1807 if (buf->b_fname == NULL)
1808 {
1809 char_u *fname;
1810
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001811 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1812 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001813 if (fname != NULL)
1814 {
1815 if (setfname(buf, fname, NULL, TRUE) == OK)
1816 buf->b_flags |= BF_NOTEDITED;
1817 vim_free(fname);
1818 }
1819 }
1820}
1821#endif
1822
1823/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001824 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825 * Must check 'write' option first!
1826 */
1827 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001828dialog_changed(
1829 buf_T *buf,
1830 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001831{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001832 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833 int ret;
1834 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001835 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001836
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001837 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 (buf->b_fname != NULL) ?
1839 buf->b_fname : (char_u *)_("Untitled"));
1840 if (checkall)
1841 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1842 else
1843 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1844
Bram Moolenaar8218f602012-04-25 17:32:18 +02001845 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1846 * function. */
1847 ea.append = ea.forceit = FALSE;
1848
Bram Moolenaar071d4272004-06-13 20:20:40 +00001849 if (ret == VIM_YES)
1850 {
1851#ifdef FEAT_BROWSE
1852 /* May get file name, when there is none */
1853 browse_save_fname(buf);
1854#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001855 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1856 buf->b_fname, buf->b_ffname, FALSE) == OK)
1857 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858 (void)buf_write_all(buf, FALSE);
1859 }
1860 else if (ret == VIM_NO)
1861 {
1862 unchanged(buf, TRUE);
1863 }
1864 else if (ret == VIM_ALL)
1865 {
1866 /*
1867 * Write all modified files that can be written.
1868 * Skip readonly buffers, these need to be confirmed
1869 * individually.
1870 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001871 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 {
1873 if (bufIsChanged(buf2)
1874 && (buf2->b_ffname != NULL
1875#ifdef FEAT_BROWSE
1876 || cmdmod.browse
1877#endif
1878 )
1879 && !buf2->b_p_ro)
1880 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001881#ifdef FEAT_AUTOCMD
1882 bufref_T bufref;
1883
1884 set_bufref(&bufref, buf2);
1885#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886#ifdef FEAT_BROWSE
1887 /* May get file name, when there is none */
1888 browse_save_fname(buf2);
1889#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001890 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1891 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1892 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 (void)buf_write_all(buf2, FALSE);
1894#ifdef FEAT_AUTOCMD
1895 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001896 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001897 buf2 = firstbuf;
1898#endif
1899 }
1900 }
1901 }
1902 else if (ret == VIM_DISCARDALL)
1903 {
1904 /*
1905 * mark all buffers as unchanged
1906 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001907 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001908 unchanged(buf2, TRUE);
1909 }
1910}
1911#endif
1912
1913/*
1914 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1915 * hidden, autowriting it or unloading it.
1916 */
1917 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001918can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919{
1920 return ( P_HID(buf)
1921 || !bufIsChanged(buf)
1922 || buf->b_nwindows > 1
1923 || autowrite(buf, forceit) == OK
1924 || forceit);
1925}
1926
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001927static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001928
1929/*
1930 * Add a buffer number to "bufnrs", unless it's already there.
1931 */
1932 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001933add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001934{
1935 int i;
1936
1937 for (i = 0; i < *bufnump; ++i)
1938 if (bufnrs[i] == nr)
1939 return;
1940 bufnrs[*bufnump] = nr;
1941 *bufnump = *bufnump + 1;
1942}
1943
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944/*
1945 * Return TRUE if any buffer was changed and cannot be abandoned.
1946 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001947 * When "unload" is true the current buffer is unloaded instead of making it
1948 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 */
1950 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001951check_changed_any(
1952 int hidden, /* Only check hidden buffers */
1953 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001954{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001955 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001956 buf_T *buf;
1957 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001958 int i;
1959 int bufnum = 0;
1960 int bufcount = 0;
1961 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001963 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964 win_T *wp;
1965#endif
1966
Bram Moolenaar29323592016-07-24 22:04:11 +02001967 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001968 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001970 if (bufcount == 0)
1971 return FALSE;
1972
1973 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1974 if (bufnrs == NULL)
1975 return FALSE;
1976
1977 /* curbuf */
1978 bufnrs[bufnum++] = curbuf->b_fnum;
1979#ifdef FEAT_WINDOWS
1980 /* buf in curtab */
1981 FOR_ALL_WINDOWS(wp)
1982 if (wp->w_buffer != curbuf)
1983 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1984
1985 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02001986 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001987 if (tp != curtab)
1988 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1989 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1990#endif
1991 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02001992 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001993 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1994
1995 for (i = 0; i < bufnum; ++i)
1996 {
1997 buf = buflist_findnr(bufnrs[i]);
1998 if (buf == NULL)
1999 continue;
2000 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2001 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002002 bufref_T bufref;
2003
2004 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002005 /* Try auto-writing the buffer. If this fails but the buffer no
2006 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002007 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2008 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002009 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002010 break; /* didn't save - still changes */
2011 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012 }
2013
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002014 if (i >= bufnum)
2015 goto theend;
2016
2017 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018 exiting = FALSE;
2019#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2020 /*
2021 * When ":confirm" used, don't give an error message.
2022 */
2023 if (!(p_confirm || cmdmod.confirm))
2024#endif
2025 {
2026 /* There must be a wait_return for this message, do_buffer()
2027 * may cause a redraw. But wait_return() is a no-op when vgetc()
2028 * is busy (Quit used from window menu), then make sure we don't
2029 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002030 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 {
2032 msg_row = cmdline_row;
2033 msg_col = 0;
2034 msg_didout = FALSE;
2035 }
2036 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002037 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 {
2039 save = no_wait_return;
2040 no_wait_return = FALSE;
2041 wait_return(FALSE);
2042 no_wait_return = save;
2043 }
2044 }
2045
2046#ifdef FEAT_WINDOWS
2047 /* Try to find a window that contains the buffer. */
2048 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002049 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002050 if (wp->w_buffer == buf)
2051 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002052# ifdef FEAT_AUTOCMD
2053 bufref_T bufref;
2054
2055 set_bufref(&bufref, buf);
2056# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002057 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058# ifdef FEAT_AUTOCMD
2059 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002060 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002061 {
2062 goto theend;
2063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002064# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002065 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002066 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002067buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068#endif
2069
2070 /* Open the changed buffer in the current window. */
2071 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002072 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002074theend:
2075 vim_free(bufnrs);
2076 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077}
2078
2079/*
2080 * return FAIL if there is no file name, OK if there is one
2081 * give error message for FAIL
2082 */
2083 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002084check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085{
2086 if (curbuf->b_ffname == NULL)
2087 {
2088 EMSG(_(e_noname));
2089 return FAIL;
2090 }
2091 return OK;
2092}
2093
2094/*
2095 * flush the contents of a buffer, unless it has no file name
2096 *
2097 * return FAIL for failure, OK otherwise
2098 */
2099 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002100buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101{
2102 int retval;
2103#ifdef FEAT_AUTOCMD
2104 buf_T *old_curbuf = curbuf;
2105#endif
2106
2107 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2108 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2109 FALSE, forceit, TRUE, FALSE));
2110#ifdef FEAT_AUTOCMD
2111 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002112 {
2113 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002115 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116#endif
2117 return retval;
2118}
2119
2120/*
2121 * Code to handle the argument list.
2122 */
2123
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002124static char_u *do_one_arg(char_u *str);
2125static int do_arglist(char_u *str, int what, int after);
2126static void alist_check_arg_idx(void);
2127static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002128#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002129static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002130#endif
2131#define AL_SET 1
2132#define AL_ADD 2
2133#define AL_DEL 3
2134
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002136 * Isolate one argument, taking backticks.
2137 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138 * Return a pointer to the start of the next argument.
2139 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002140 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002141do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142{
2143 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 int inbacktick;
2145
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146 inbacktick = FALSE;
2147 for (p = str; *str; ++str)
2148 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002149 /* When the backslash is used for escaping the special meaning of a
2150 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151 if (rem_backslash(str))
2152 {
2153 *p++ = *str++;
2154 *p++ = *str;
2155 }
2156 else
2157 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002158 /* An item ends at a space not in backticks */
2159 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002161 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002162 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002163 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002164 }
2165 }
2166 str = skipwhite(str);
2167 *p = NUL;
2168
2169 return str;
2170}
2171
Bram Moolenaar86b68352004-12-27 21:59:20 +00002172/*
2173 * Separate the arguments in "str" and return a list of pointers in the
2174 * growarray "gap".
2175 */
2176 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002177get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002178{
2179 ga_init2(gap, (int)sizeof(char_u *), 20);
2180 while (*str != NUL)
2181 {
2182 if (ga_grow(gap, 1) == FAIL)
2183 {
2184 ga_clear(gap);
2185 return FAIL;
2186 }
2187 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2188
2189 /* Isolate one argument, change it in-place, put a NUL after it. */
2190 str = do_one_arg(str);
2191 }
2192 return OK;
2193}
2194
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002195#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002196/*
2197 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002198 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002199 * Return FAIL or OK.
2200 */
2201 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002202get_arglist_exp(
2203 char_u *str,
2204 int *fcountp,
2205 char_u ***fnamesp,
2206 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002207{
2208 garray_T ga;
2209 int i;
2210
2211 if (get_arglist(&ga, str) == FAIL)
2212 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002213 if (wig == TRUE)
2214 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2215 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2216 else
2217 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2218 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2219
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002220 ga_clear(&ga);
2221 return i;
2222}
2223#endif
2224
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2226/*
2227 * Redefine the argument list.
2228 */
2229 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002230set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231{
2232 do_arglist(str, AL_SET, 0);
2233}
2234#endif
2235
2236/*
2237 * "what" == AL_SET: Redefine the argument list to 'str'.
2238 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2239 * "what" == AL_DEL: remove files in 'str' from the argument list.
2240 *
2241 * Return FAIL for failure, OK otherwise.
2242 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002244do_arglist(
2245 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002246 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002247 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248{
2249 garray_T new_ga;
2250 int exp_count;
2251 char_u **exp_files;
2252 int i;
2253#ifdef FEAT_LISTCMDS
2254 char_u *p;
2255 int match;
2256#endif
2257
2258 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002259 * Set default argument for ":argadd" command.
2260 */
2261 if (what == AL_ADD && *str == NUL)
2262 {
2263 if (curbuf->b_ffname == NULL)
2264 return FAIL;
2265 str = curbuf->b_fname;
2266 }
2267
2268 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 * Collect all file name arguments in "new_ga".
2270 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002271 if (get_arglist(&new_ga, str) == FAIL)
2272 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273
2274#ifdef FEAT_LISTCMDS
2275 if (what == AL_DEL)
2276 {
2277 regmatch_T regmatch;
2278 int didone;
2279
2280 /*
2281 * Delete the items: use each item as a regexp and find a match in the
2282 * argument list.
2283 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002284 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2286 {
2287 p = ((char_u **)new_ga.ga_data)[i];
2288 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2289 if (p == NULL)
2290 break;
2291 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2292 if (regmatch.regprog == NULL)
2293 {
2294 vim_free(p);
2295 break;
2296 }
2297
2298 didone = FALSE;
2299 for (match = 0; match < ARGCOUNT; ++match)
2300 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2301 (colnr_T)0))
2302 {
2303 didone = TRUE;
2304 vim_free(ARGLIST[match].ae_fname);
2305 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2306 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2307 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 if (curwin->w_arg_idx > match)
2309 --curwin->w_arg_idx;
2310 --match;
2311 }
2312
Bram Moolenaar473de612013-06-08 18:19:48 +02002313 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314 vim_free(p);
2315 if (!didone)
2316 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2317 }
2318 ga_clear(&new_ga);
2319 }
2320 else
2321#endif
2322 {
2323 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2324 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2325 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002326 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 {
2328 EMSG(_(e_nomatch));
2329 return FAIL;
2330 }
2331
2332#ifdef FEAT_LISTCMDS
2333 if (what == AL_ADD)
2334 {
2335 (void)alist_add_list(exp_count, exp_files, after);
2336 vim_free(exp_files);
2337 }
2338 else /* what == AL_SET */
2339#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002340 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 }
2342
2343 alist_check_arg_idx();
2344
2345 return OK;
2346}
2347
2348/*
2349 * Check the validity of the arg_idx for each other window.
2350 */
2351 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002352alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353{
2354#ifdef FEAT_WINDOWS
2355 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002356 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357
Bram Moolenaarf740b292006-02-16 22:11:02 +00002358 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359 if (win->w_alist == curwin->w_alist)
2360 check_arg_idx(win);
2361#else
2362 check_arg_idx(curwin);
2363#endif
2364}
2365
2366/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002367 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002368 * index.
2369 */
2370 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002371editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002372{
2373 return !(win->w_arg_idx >= WARGCOUNT(win)
2374 || (win->w_buffer->b_fnum
2375 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2376 && (win->w_buffer->b_ffname == NULL
2377 || !(fullpathcmp(
2378 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2379 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2380}
2381
2382/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 * Check if window "win" is editing the w_arg_idx file in its argument list.
2384 */
2385 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002386check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002387{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002388 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 {
2390 /* We are not editing the current entry in the argument list.
2391 * Set "arg_had_last" if we are editing the last one. */
2392 win->w_arg_idx_invalid = TRUE;
2393 if (win->w_arg_idx != WARGCOUNT(win) - 1
2394 && arg_had_last == FALSE
2395#ifdef FEAT_WINDOWS
2396 && ALIST(win) == &global_alist
2397#endif
2398 && GARGCOUNT > 0
2399 && win->w_arg_idx < GARGCOUNT
2400 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2401 || (win->w_buffer->b_ffname != NULL
2402 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2403 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2404 arg_had_last = TRUE;
2405 }
2406 else
2407 {
2408 /* We are editing the current entry in the argument list.
2409 * Set "arg_had_last" if it's also the last one */
2410 win->w_arg_idx_invalid = FALSE;
2411 if (win->w_arg_idx == WARGCOUNT(win) - 1
2412#ifdef FEAT_WINDOWS
2413 && win->w_alist == &global_alist
2414#endif
2415 )
2416 arg_had_last = TRUE;
2417 }
2418}
2419
2420/*
2421 * ":args", ":argslocal" and ":argsglobal".
2422 */
2423 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002424ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425{
2426 int i;
2427
2428 if (eap->cmdidx != CMD_args)
2429 {
2430#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2431 alist_unlink(ALIST(curwin));
2432 if (eap->cmdidx == CMD_argglobal)
2433 ALIST(curwin) = &global_alist;
2434 else /* eap->cmdidx == CMD_arglocal */
2435 alist_new();
2436#else
2437 ex_ni(eap);
2438 return;
2439#endif
2440 }
2441
2442 if (!ends_excmd(*eap->arg))
2443 {
2444 /*
2445 * ":args file ..": define new argument list, handle like ":next"
2446 * Also for ":argslocal file .." and ":argsglobal file ..".
2447 */
2448 ex_next(eap);
2449 }
2450 else
2451#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2452 if (eap->cmdidx == CMD_args)
2453#endif
2454 {
2455 /*
2456 * ":args": list arguments.
2457 */
2458 if (ARGCOUNT > 0)
2459 {
2460 /* Overwrite the command, for a short list there is no scrolling
2461 * required and no wait_return(). */
2462 gotocmdline(TRUE);
2463 for (i = 0; i < ARGCOUNT; ++i)
2464 {
2465 if (i == curwin->w_arg_idx)
2466 msg_putchar('[');
2467 msg_outtrans(alist_name(&ARGLIST[i]));
2468 if (i == curwin->w_arg_idx)
2469 msg_putchar(']');
2470 msg_putchar(' ');
2471 }
2472 }
2473 }
2474#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2475 else if (eap->cmdidx == CMD_arglocal)
2476 {
2477 garray_T *gap = &curwin->w_alist->al_ga;
2478
2479 /*
2480 * ":argslocal": make a local copy of the global argument list.
2481 */
2482 if (ga_grow(gap, GARGCOUNT) == OK)
2483 for (i = 0; i < GARGCOUNT; ++i)
2484 if (GARGLIST[i].ae_fname != NULL)
2485 {
2486 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2487 vim_strsave(GARGLIST[i].ae_fname);
2488 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2489 GARGLIST[i].ae_fnum;
2490 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491 }
2492 }
2493#endif
2494}
2495
2496/*
2497 * ":previous", ":sprevious", ":Next" and ":sNext".
2498 */
2499 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002500ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501{
2502 /* If past the last one already, go to the last one. */
2503 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2504 do_argfile(eap, ARGCOUNT - 1);
2505 else
2506 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2507}
2508
2509/*
2510 * ":rewind", ":first", ":sfirst" and ":srewind".
2511 */
2512 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002513ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514{
2515 do_argfile(eap, 0);
2516}
2517
2518/*
2519 * ":last" and ":slast".
2520 */
2521 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002522ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523{
2524 do_argfile(eap, ARGCOUNT - 1);
2525}
2526
2527/*
2528 * ":argument" and ":sargument".
2529 */
2530 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002531ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532{
2533 int i;
2534
2535 if (eap->addr_count > 0)
2536 i = eap->line2 - 1;
2537 else
2538 i = curwin->w_arg_idx;
2539 do_argfile(eap, i);
2540}
2541
2542/*
2543 * Edit file "argn" of the argument lists.
2544 */
2545 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002546do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002547{
2548 int other;
2549 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002550 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551
2552 if (argn < 0 || argn >= ARGCOUNT)
2553 {
2554 if (ARGCOUNT <= 1)
2555 EMSG(_("E163: There is only one file to edit"));
2556 else if (argn < 0)
2557 EMSG(_("E164: Cannot go before first file"));
2558 else
2559 EMSG(_("E165: Cannot go beyond last file"));
2560 }
2561 else
2562 {
2563 setpcmark();
2564#ifdef FEAT_GUI
2565 need_mouse_correct = TRUE;
2566#endif
2567
2568#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002569 /* split window or create new tab page first */
2570 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 {
2572 if (win_split(0, 0) == FAIL)
2573 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002574 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002575 }
2576 else
2577#endif
2578 {
2579 /*
2580 * if 'hidden' set, only check for changed file when re-editing
2581 * the same buffer
2582 */
2583 other = TRUE;
2584 if (P_HID(curbuf))
2585 {
2586 p = fix_fname(alist_name(&ARGLIST[argn]));
2587 other = otherfile(p);
2588 vim_free(p);
2589 }
2590 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002591 && check_changed(curbuf, CCGD_AW
2592 | (other ? 0 : CCGD_MULTWIN)
2593 | (eap->forceit ? CCGD_FORCEIT : 0)
2594 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002595 return;
2596 }
2597
2598 curwin->w_arg_idx = argn;
2599 if (argn == ARGCOUNT - 1
2600#ifdef FEAT_WINDOWS
2601 && curwin->w_alist == &global_alist
2602#endif
2603 )
2604 arg_had_last = TRUE;
2605
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002606 /* Edit the file; always use the last known line number.
2607 * When it fails (e.g. Abort for already edited file) restore the
2608 * argument index. */
2609 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002611 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2612 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002613 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002614 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002615 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 setmark('\'');
2617 }
2618}
2619
2620/*
2621 * ":next", and commands that behave like it.
2622 */
2623 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002624ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002625{
2626 int i;
2627
2628 /*
2629 * check for changed buffer now, if this fails the argument list is not
2630 * redefined.
2631 */
2632 if ( P_HID(curbuf)
2633 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002634 || !check_changed(curbuf, CCGD_AW
2635 | (eap->forceit ? CCGD_FORCEIT : 0)
2636 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637 {
2638 if (*eap->arg != NUL) /* redefine file list */
2639 {
2640 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2641 return;
2642 i = 0;
2643 }
2644 else
2645 i = curwin->w_arg_idx + (int)eap->line2;
2646 do_argfile(eap, i);
2647 }
2648}
2649
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002650#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002651/*
2652 * ":argedit"
2653 */
2654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002655ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656{
2657 int fnum;
2658 int i;
2659 char_u *s;
2660
2661 /* Add the argument to the buffer list and get the buffer number. */
2662 fnum = buflist_add(eap->arg, BLN_LISTED);
2663
2664 /* Check if this argument is already in the argument list. */
2665 for (i = 0; i < ARGCOUNT; ++i)
2666 if (ARGLIST[i].ae_fnum == fnum)
2667 break;
2668 if (i == ARGCOUNT)
2669 {
2670 /* Can't find it, add it to the argument list. */
2671 s = vim_strsave(eap->arg);
2672 if (s == NULL)
2673 return;
2674 i = alist_add_list(1, &s,
2675 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2676 if (i < 0)
2677 return;
2678 curwin->w_arg_idx = i;
2679 }
2680
2681 alist_check_arg_idx();
2682
2683 /* Edit the argument. */
2684 do_argfile(eap, i);
2685}
2686
2687/*
2688 * ":argadd"
2689 */
2690 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002691ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692{
2693 do_arglist(eap->arg, AL_ADD,
2694 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2695#ifdef FEAT_TITLE
2696 maketitle();
2697#endif
2698}
2699
2700/*
2701 * ":argdelete"
2702 */
2703 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002704ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705{
2706 int i;
2707 int n;
2708
2709 if (eap->addr_count > 0)
2710 {
2711 /* ":1,4argdel": Delete all arguments in the range. */
2712 if (eap->line2 > ARGCOUNT)
2713 eap->line2 = ARGCOUNT;
2714 n = eap->line2 - eap->line1 + 1;
2715 if (*eap->arg != NUL || n <= 0)
2716 EMSG(_(e_invarg));
2717 else
2718 {
2719 for (i = eap->line1; i <= eap->line2; ++i)
2720 vim_free(ARGLIST[i - 1].ae_fname);
2721 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2722 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2723 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 if (curwin->w_arg_idx >= eap->line2)
2725 curwin->w_arg_idx -= n;
2726 else if (curwin->w_arg_idx > eap->line1)
2727 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002728 if (ARGCOUNT == 0)
2729 curwin->w_arg_idx = 0;
2730 else if (curwin->w_arg_idx >= ARGCOUNT)
2731 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732 }
2733 }
2734 else if (*eap->arg == NUL)
2735 EMSG(_(e_argreq));
2736 else
2737 do_arglist(eap->arg, AL_DEL, 0);
2738#ifdef FEAT_TITLE
2739 maketitle();
2740#endif
2741}
2742
2743/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002744 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 */
2746 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002747ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748{
2749 int i;
2750#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002751 win_T *wp;
2752 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002754 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002755 int next_fnum = 0;
2756#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2757 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002759 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002760#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002761 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002762 int qf_idx;
2763#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764
2765#ifndef FEAT_WINDOWS
2766 if (eap->cmdidx == CMD_windo)
2767 {
2768 ex_ni(eap);
2769 return;
2770 }
2771#endif
2772
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002773#ifndef FEAT_QUICKFIX
2774 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2775 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2776 {
2777 ex_ni(eap);
2778 return;
2779 }
2780#endif
2781
Bram Moolenaar071d4272004-06-13 20:20:40 +00002782#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002783 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002784 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2785 * great speed improvement. */
2786 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002788#ifdef FEAT_CLIPBOARD
2789 start_global_changes();
2790#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791
2792 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002793 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002795 || !check_changed(curbuf, CCGD_AW
2796 | (eap->forceit ? CCGD_FORCEIT : 0)
2797 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002800 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002802 wp = firstwin;
2803 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002804#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002805 switch (eap->cmdidx)
2806 {
2807#ifdef FEAT_WINDOWS
2808 case CMD_windo:
2809 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2810 i++;
2811 break;
2812 case CMD_tabdo:
2813 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2814 i++;
2815 break;
2816#endif
2817 case CMD_argdo:
2818 i = eap->line1 - 1;
2819 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002820 default:
2821 break;
2822 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002823 /* set pcmark now */
2824 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002825 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002826 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002827 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002828 || !buf->b_p_bl); buf = buf->b_next)
2829 if (buf->b_fnum > eap->line2)
2830 {
2831 buf = NULL;
2832 break;
2833 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002834 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002835 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002836 }
2837#ifdef FEAT_QUICKFIX
2838 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2839 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2840 {
2841 qf_size = qf_get_size(eap);
2842 if (qf_size <= 0 || eap->line1 > qf_size)
2843 buf = NULL;
2844 else
2845 {
2846 ex_cc(eap);
2847
2848 buf = curbuf;
2849 i = eap->line1 - 1;
2850 if (eap->addr_count <= 0)
2851 /* default is all the quickfix/location list entries */
2852 eap->line2 = qf_size;
2853 }
2854 }
2855#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856 else
2857 setpcmark();
2858 listcmd_busy = TRUE; /* avoids setting pcmark below */
2859
Bram Moolenaare25bb902015-02-27 20:33:37 +01002860 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861 {
2862 if (eap->cmdidx == CMD_argdo)
2863 {
2864 /* go to argument "i" */
2865 if (i == ARGCOUNT)
2866 break;
2867 /* Don't call do_argfile() when already there, it will try
2868 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002869 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002870 {
2871 /* Clear 'shm' to avoid that the file message overwrites
2872 * any output from the command. */
2873 p_shm_save = vim_strsave(p_shm);
2874 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002875 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002876 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2877 vim_free(p_shm_save);
2878 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 if (curwin->w_arg_idx != i)
2880 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881 }
2882#ifdef FEAT_WINDOWS
2883 else if (eap->cmdidx == CMD_windo)
2884 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002885 /* go to window "wp" */
2886 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002888 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002889 if (curwin != wp)
2890 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002891 wp = curwin->w_next;
2892 }
2893 else if (eap->cmdidx == CMD_tabdo)
2894 {
2895 /* go to window "tp" */
2896 if (!valid_tabpage(tp))
2897 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002898 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002899 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900 }
2901#endif
2902 else if (eap->cmdidx == CMD_bufdo)
2903 {
2904 /* Remember the number of the next listed buffer, in case
2905 * ":bwipe" is used or autocommands do something strange. */
2906 next_fnum = -1;
2907 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2908 if (buf->b_p_bl)
2909 {
2910 next_fnum = buf->b_fnum;
2911 break;
2912 }
2913 }
2914
Bram Moolenaara162bc52015-01-07 16:54:21 +01002915 ++i;
2916
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 /* execute the command */
2918 do_cmdline(eap->arg, eap->getline, eap->cookie,
2919 DOCMD_VERBOSE + DOCMD_NOWAIT);
2920
2921 if (eap->cmdidx == CMD_bufdo)
2922 {
2923 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002924 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925 break;
2926 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02002927 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 if (buf->b_fnum == next_fnum)
2929 break;
2930 if (buf == NULL)
2931 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002932
2933 /* Go to the next buffer. Clear 'shm' to avoid that the file
2934 * message overwrites any output from the command. */
2935 p_shm_save = vim_strsave(p_shm);
2936 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002938 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2939 vim_free(p_shm_save);
2940
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002941 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002942 if (curbuf->b_fnum != next_fnum)
2943 break;
2944 }
2945
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002946#ifdef FEAT_QUICKFIX
2947 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2948 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2949 {
2950 if (i >= qf_size || i >= eap->line2)
2951 break;
2952
2953 qf_idx = qf_get_cur_idx(eap);
2954
2955 ex_cnext(eap);
2956
2957 /* If jumping to the next quickfix entry fails, quit here */
2958 if (qf_get_cur_idx(eap) == qf_idx)
2959 break;
2960 }
2961#endif
2962
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963 if (eap->cmdidx == CMD_windo)
2964 {
2965 validate_cursor(); /* cursor may have moved */
2966#ifdef FEAT_SCROLLBIND
2967 /* required when 'scrollbind' has been set */
2968 if (curwin->w_p_scb)
2969 do_check_scrollbind(TRUE);
2970#endif
2971 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002972
2973#ifdef FEAT_WINDOWS
2974 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2975 if (i+1 > eap->line2)
2976 break;
2977#endif
2978 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2979 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002980 }
2981 listcmd_busy = FALSE;
2982 }
2983
2984#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002985 if (save_ei != NULL)
2986 {
2987 au_event_restore(save_ei);
2988 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2989 curbuf->b_fname, TRUE, curbuf);
2990 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002991#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002992#ifdef FEAT_CLIPBOARD
2993 end_global_changes();
2994#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995}
2996
2997/*
2998 * Add files[count] to the arglist of the current window after arg "after".
2999 * The file names in files[count] must have been allocated and are taken over.
3000 * Files[] itself is not taken over.
3001 * Returns index of first added argument. Returns -1 when failed (out of mem).
3002 */
3003 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003004alist_add_list(
3005 int count,
3006 char_u **files,
3007 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008{
3009 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003010 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011
3012 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3013 {
3014 if (after < 0)
3015 after = 0;
3016 if (after > ARGCOUNT)
3017 after = ARGCOUNT;
3018 if (after < ARGCOUNT)
3019 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3020 (ARGCOUNT - after) * sizeof(aentry_T));
3021 for (i = 0; i < count; ++i)
3022 {
3023 ARGLIST[after + i].ae_fname = files[i];
3024 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3025 }
3026 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003027 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3028 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003029 return after;
3030 }
3031
3032 for (i = 0; i < count; ++i)
3033 vim_free(files[i]);
3034 return -1;
3035}
3036
3037#endif /* FEAT_LISTCMDS */
3038
3039#ifdef FEAT_EVAL
3040/*
3041 * ":compiler[!] {name}"
3042 */
3043 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003044ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045{
3046 char_u *buf;
3047 char_u *old_cur_comp = NULL;
3048 char_u *p;
3049
3050 if (*eap->arg == NUL)
3051 {
3052 /* List all compiler scripts. */
3053 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3054 /* ) keep the indenter happy... */
3055 }
3056 else
3057 {
3058 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3059 if (buf != NULL)
3060 {
3061 if (eap->forceit)
3062 {
3063 /* ":compiler! {name}" sets global options */
3064 do_cmdline_cmd((char_u *)
3065 "command -nargs=* CompilerSet set <args>");
3066 }
3067 else
3068 {
3069 /* ":compiler! {name}" sets local options.
3070 * To remain backwards compatible "current_compiler" is always
3071 * used. A user's compiler plugin may set it, the distributed
3072 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003073 * "b:current_compiler" and restore "current_compiler".
3074 * Explicitly prepend "g:" to make it work in a function. */
3075 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 if (old_cur_comp != NULL)
3077 old_cur_comp = vim_strsave(old_cur_comp);
3078 do_cmdline_cmd((char_u *)
3079 "command -nargs=* CompilerSet setlocal <args>");
3080 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003081 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003082 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003083
3084 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003085 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3087 vim_free(buf);
3088
3089 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3090
3091 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003092 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093 if (p != NULL)
3094 set_internal_string_var((char_u *)"b:current_compiler", p);
3095
3096 /* Restore "current_compiler" for ":compiler {name}". */
3097 if (!eap->forceit)
3098 {
3099 if (old_cur_comp != NULL)
3100 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003101 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 old_cur_comp);
3103 vim_free(old_cur_comp);
3104 }
3105 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003106 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 }
3108 }
3109 }
3110}
3111#endif
3112
3113/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003114 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115 */
3116 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003117ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003119 char_u *arg = eap->arg;
3120 char_u *p = skiptowhite(arg);
3121 int len = (int)(p - arg);
3122 int flags = eap->forceit ? DIP_ALL : 0;
3123
3124 if (STRNCMP(arg, "START", len) == 0)
3125 {
3126 flags += DIP_START + DIP_NORTP;
3127 arg = skipwhite(arg + len);
3128 }
3129 else if (STRNCMP(arg, "OPT", len) == 0)
3130 {
3131 flags += DIP_OPT + DIP_NORTP;
3132 arg = skipwhite(arg + len);
3133 }
3134 else if (STRNCMP(arg, "PACK", len) == 0)
3135 {
3136 flags += DIP_START + DIP_OPT + DIP_NORTP;
3137 arg = skipwhite(arg + len);
3138 }
3139 else if (STRNCMP(arg, "ALL", len) == 0)
3140 {
3141 flags += DIP_START + DIP_OPT;
3142 arg = skipwhite(arg + len);
3143 }
3144
3145 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003146}
3147
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003149source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003151 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152}
3153
3154/*
3155 * Source the file "name" from all directories in 'runtimepath'.
3156 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003157 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003158 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 * return FAIL when no file could be sourced, OK otherwise.
3160 */
3161 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003162source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003164 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003165}
3166
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003167/*
3168 * Find the file "name" in all directories in "path" and invoke
3169 * "callback(fname, cookie)".
3170 * "name" can contain wildcards.
3171 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3172 * When "flags" has DIP_DIR: find directories instead of files.
3173 * When "flags" has DIP_ERR: give an error message if there is no match.
3174 *
3175 * return FAIL when no file could be sourced, OK otherwise.
3176 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003177 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003178do_in_path(
3179 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003180 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003181 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003182 void (*callback)(char_u *fname, void *ck),
3183 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184{
3185 char_u *rtp;
3186 char_u *np;
3187 char_u *buf;
3188 char_u *rtp_copy;
3189 char_u *tail;
3190 int num_files;
3191 char_u **files;
3192 int i;
3193 int did_one = FALSE;
3194#ifdef AMIGA
3195 struct Process *proc = (struct Process *)FindTask(0L);
3196 APTR save_winptr = proc->pr_WindowPtr;
3197
3198 /* Avoid a requester here for a volume that doesn't exist. */
3199 proc->pr_WindowPtr = (APTR)-1L;
3200#endif
3201
3202 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3203 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003204 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003205 buf = alloc(MAXPATHL);
3206 if (buf != NULL && rtp_copy != NULL)
3207 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003208 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003209 {
3210 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003211 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003212 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003213 verbose_leave();
3214 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003215
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 /* Loop over all entries in 'runtimepath'. */
3217 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003218 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 {
3220 /* Copy the path from 'runtimepath' to buf[]. */
3221 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003222 if (name == NULL)
3223 {
3224 (*callback)(buf, (void *) &cookie);
3225 if (!did_one)
3226 did_one = (cookie == NULL);
3227 }
3228 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229 {
3230 add_pathsep(buf);
3231 tail = buf + STRLEN(buf);
3232
3233 /* Loop over all patterns in "name" */
3234 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003235 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 {
3237 /* Append the pattern from "name" to buf[]. */
3238 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3239 "\t ");
3240
3241 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003242 {
3243 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003244 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003245 verbose_leave();
3246 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247
3248 /* Expand wildcards, invoke the callback for each match. */
3249 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003250 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003251 {
3252 for (i = 0; i < num_files; ++i)
3253 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003254 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003256 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257 break;
3258 }
3259 FreeWild(num_files, files);
3260 }
3261 }
3262 }
3263 }
3264 }
3265 vim_free(buf);
3266 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003267 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003268 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003269 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3270
3271 if (flags & DIP_ERR)
3272 EMSG3(_(e_dirnotf), basepath, name);
3273 else if (p_verbose > 0)
3274 {
3275 verbose_enter();
3276 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3277 verbose_leave();
3278 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003279 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280
3281#ifdef AMIGA
3282 proc->pr_WindowPtr = save_winptr;
3283#endif
3284
3285 return did_one ? OK : FAIL;
3286}
3287
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003288/*
3289 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3290 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003291 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3292 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003293 * Returns OK when at least one match found, FAIL otherwise.
3294 *
3295 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3296 * passed by reference in this case, setting it to NULL indicates that callback
3297 * has done its job.
3298 */
3299 int
3300do_in_runtimepath(
3301 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003302 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003303 void (*callback)(char_u *fname, void *ck),
3304 void *cookie)
3305{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003306 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003307 char_u *s;
3308 int len;
3309 char *start_dir = "pack/*/start/*/%s";
3310 char *opt_dir = "pack/*/opt/*/%s";
3311
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003312 if ((flags & DIP_NORTP) == 0)
3313 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003314
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003315 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003316 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003317 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003318 s = alloc(len);
3319 if (s == NULL)
3320 return FAIL;
3321 vim_snprintf((char *)s, len, start_dir, name);
3322 done = do_in_path(p_pp, s, flags, callback, cookie);
3323 vim_free(s);
3324 }
3325
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003326 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003327 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003328 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003329 s = alloc(len);
3330 if (s == NULL)
3331 return FAIL;
3332 vim_snprintf((char *)s, len, opt_dir, name);
3333 done = do_in_path(p_pp, s, flags, callback, cookie);
3334 vim_free(s);
3335 }
3336
3337 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003338}
3339
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003340/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003341 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003342 */
3343 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003344source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003345{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003346 int num_files;
3347 char_u **files;
3348 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003349
Bram Moolenaarf3654822016-03-04 22:12:23 +01003350 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003351 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003352 for (i = 0; i < num_files; ++i)
3353 (void)do_source(files[i], FALSE, DOSO_NONE);
3354 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003355 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003356}
3357
Bram Moolenaar49b27322016-04-05 21:13:00 +02003358/* used for "cookie" of add_pack_plugin() */
3359static int APP_ADD_DIR;
3360static int APP_LOAD;
3361static int APP_BOTH;
3362
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003363 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003364add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003365{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003366 char_u *p4, *p3, *p2, *p1, *p;
3367 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003368 int c;
3369 char_u *new_rtp;
3370 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003371 size_t oldlen;
3372 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003373 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003374 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003375 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003376 size_t fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003377
Bram Moolenaar91715872016-03-03 17:13:03 +01003378 if (ffname == NULL)
3379 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003380 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003381 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003382 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003383 p4 = p3 = p2 = p1 = get_past_head(ffname);
3384 for (p = p1; *p; mb_ptr_adv(p))
3385 if (vim_ispathsep_nocolon(*p))
3386 {
3387 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3388 }
3389
3390 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003391 * rtp/pack/name/start/name
3392 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003393 *
3394 * find the part up to "pack" in 'runtimepath' */
3395 c = *p4;
3396 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003397
3398 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3399 fname_len = STRLEN(ffname);
3400 insp = p_rtp;
3401 for (;;)
3402 {
3403 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3404 break;
3405 insp = vim_strchr(insp, ',');
3406 if (insp == NULL)
3407 break;
3408 ++insp;
3409 }
3410
Bram Moolenaarf3654822016-03-04 22:12:23 +01003411 if (insp == NULL)
3412 /* not found, append at the end */
3413 insp = p_rtp + STRLEN(p_rtp);
3414 else
3415 {
3416 /* append after the matching directory. */
3417 insp += STRLEN(ffname);
3418 while (*insp != NUL && *insp != ',')
3419 ++insp;
3420 }
3421 *p4 = c;
3422
Bram Moolenaara5702442016-05-24 19:37:29 +02003423 /* check if rtp/pack/name/start/name/after exists */
3424 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3425 if (afterdir != NULL && mch_isdir(afterdir))
3426 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3427
Bram Moolenaarb0550662016-05-31 21:37:36 +02003428 oldlen = STRLEN(p_rtp);
3429 addlen = STRLEN(ffname) + 1; /* add one for comma */
3430 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003431 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003432 goto theend;
3433 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003434 mch_memmove(new_rtp, p_rtp, keep);
3435 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003436 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003437 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003438 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003439 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003440 if (afterlen > 0)
3441 {
3442 STRCAT(new_rtp, ",");
3443 STRCAT(new_rtp, afterdir);
3444 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003445 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3446 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003447 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003448 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003449
Bram Moolenaar49b27322016-04-05 21:13:00 +02003450 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003451 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003452 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003453 static char *ftpat = "%s/ftdetect/*.vim";
3454 int len;
3455 char_u *pat;
3456
3457 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3458 pat = alloc(len);
3459 if (pat == NULL)
3460 goto theend;
3461 vim_snprintf((char *)pat, len, plugpat, ffname);
3462 source_all_matches(pat);
3463
3464#ifdef FEAT_AUTOCMD
3465 {
3466 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3467
3468 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3469 * found when it loads. */
3470 if (cmd != NULL && eval_to_number(cmd) > 0)
3471 {
3472 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3473 vim_snprintf((char *)pat, len, ftpat, ffname);
3474 source_all_matches(pat);
3475 do_cmdline_cmd((char_u *)"augroup END");
3476 }
3477 vim_free(cmd);
3478 }
3479#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003480 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003481 }
3482
3483theend:
3484 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003485}
3486
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003487static int did_source_packages = FALSE;
3488
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003489/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003490 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003491 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003492 */
3493 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003494ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003495{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003496 if (!did_source_packages || (eap != NULL && eap->forceit))
3497 {
3498 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003499
3500 /* First do a round to add all directories to 'runtimepath', then load
3501 * the plugins. This allows for plugins to use an autoload directory
3502 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003503 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003504 add_pack_plugin, &APP_ADD_DIR);
3505 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3506 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003507 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003508}
3509
3510/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003511 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003512 */
3513 void
3514ex_packadd(exarg_T *eap)
3515{
3516 static char *plugpat = "pack/*/opt/%s";
3517 int len;
3518 char *pat;
3519
3520 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3521 pat = (char *)alloc(len);
3522 if (pat == NULL)
3523 return;
3524 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003525 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003526 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003527 vim_free(pat);
3528}
3529
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3531/*
3532 * ":options"
3533 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003535ex_options(
3536 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537{
3538 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3539}
3540#endif
3541
3542/*
3543 * ":source {fname}"
3544 */
3545 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003546ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547{
3548#ifdef FEAT_BROWSE
3549 if (cmdmod.browse)
3550 {
3551 char_u *fname = NULL;
3552
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003553 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3555 if (fname != NULL)
3556 {
3557 cmd_source(fname, eap);
3558 vim_free(fname);
3559 }
3560 }
3561 else
3562#endif
3563 cmd_source(eap->arg, eap);
3564}
3565
3566 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003567cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568{
3569 if (*fname == NUL)
3570 EMSG(_(e_argreq));
3571
Bram Moolenaar071d4272004-06-13 20:20:40 +00003572 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003573 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003574 * Need to execute the commands directly. This is required at least
3575 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576 * - ":g" command busy
3577 * - after ":argdo", ":windo" or ":bufdo"
3578 * - another command follows
3579 * - inside a loop
3580 */
3581 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3582#ifdef FEAT_EVAL
3583 || eap->cstack->cs_idx >= 0
3584#endif
3585 );
3586
3587 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003588 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589 EMSG2(_(e_notopen), fname);
3590}
3591
3592/*
3593 * ":source" and associated commands.
3594 */
3595/*
3596 * Structure used to store info for each sourced file.
3597 * It is shared between do_source() and getsourceline().
3598 * This is required, because it needs to be handed to do_cmdline() and
3599 * sourcing can be done recursively.
3600 */
3601struct source_cookie
3602{
3603 FILE *fp; /* opened file for sourcing */
3604 char_u *nextline; /* if not NULL: line that was read ahead */
3605 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003606#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3608 int error; /* TRUE if LF found after CR-LF */
3609#endif
3610#ifdef FEAT_EVAL
3611 linenr_T breakpoint; /* next line with breakpoint or zero */
3612 char_u *fname; /* name of sourced file */
3613 int dbg_tick; /* debug_tick when breakpoint was set */
3614 int level; /* top nesting level of sourced file */
3615#endif
3616#ifdef FEAT_MBYTE
3617 vimconv_T conv; /* type of conversion */
3618#endif
3619};
3620
3621#ifdef FEAT_EVAL
3622/*
3623 * Return the address holding the next breakpoint line for a source cookie.
3624 */
3625 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003626source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627{
3628 return &((struct source_cookie *)cookie)->breakpoint;
3629}
3630
3631/*
3632 * Return the address holding the debug tick for a source cookie.
3633 */
3634 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003635source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636{
3637 return &((struct source_cookie *)cookie)->dbg_tick;
3638}
3639
3640/*
3641 * Return the nesting level for a source cookie.
3642 */
3643 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003644source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645{
3646 return ((struct source_cookie *)cookie)->level;
3647}
3648#endif
3649
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003650static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003652#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3653# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003654static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655
3656/*
3657 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003658 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 */
3660 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003661fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003663# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003664 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3665# else
3666 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003667# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668
3669 if (fd_tmp == -1)
3670 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003671
3672# ifdef HAVE_FD_CLOEXEC
3673 {
3674 int fdflags = fcntl(fd_tmp, F_GETFD);
3675 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003676 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003677 }
3678# endif
3679
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 return fdopen(fd_tmp, READBIN);
3681}
3682#endif
3683
3684
3685/*
3686 * do_source: Read the file "fname" and execute its lines as EX commands.
3687 *
3688 * This function may be called recursively!
3689 *
3690 * return FAIL if file could not be opened, OK otherwise
3691 */
3692 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003693do_source(
3694 char_u *fname,
3695 int check_other, /* check for .vimrc and _vimrc */
3696 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697{
3698 struct source_cookie cookie;
3699 char_u *save_sourcing_name;
3700 linenr_T save_sourcing_lnum;
3701 char_u *p;
3702 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003703 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704 int retval = FAIL;
3705#ifdef FEAT_EVAL
3706 scid_T save_current_SID;
3707 static scid_T last_current_SID = 0;
3708 void *save_funccalp;
3709 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003710 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003711# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003712 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003713 int stat_ok;
3714# endif
3715#endif
3716#ifdef STARTUPTIME
3717 struct timeval tv_rel;
3718 struct timeval tv_start;
3719#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003720#ifdef FEAT_PROFILE
3721 proftime_T wait_start;
3722#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 if (p == NULL)
3726 return retval;
3727 fname_exp = fix_fname(p);
3728 vim_free(p);
3729 if (fname_exp == NULL)
3730 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731 if (mch_isdir(fname_exp))
3732 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003733 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734 goto theend;
3735 }
3736
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003737#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003738 /* Apply SourceCmd autocommands, they should get the file and source it. */
3739 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3740 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3741 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003742 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003743# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003744 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003745# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003746 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003747# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003748 goto theend;
3749 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003750
3751 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003752 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3753#endif
3754
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003755#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3757#else
3758 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3759#endif
3760 if (cookie.fp == NULL && check_other)
3761 {
3762 /*
3763 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3764 * and ".exrc" by "_exrc" or vice versa.
3765 */
3766 p = gettail(fname_exp);
3767 if ((*p == '.' || *p == '_')
3768 && (STRICMP(p + 1, "vimrc") == 0
3769 || STRICMP(p + 1, "gvimrc") == 0
3770 || STRICMP(p + 1, "exrc") == 0))
3771 {
3772 if (*p == '_')
3773 *p = '.';
3774 else
3775 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003776#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3778#else
3779 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3780#endif
3781 }
3782 }
3783
3784 if (cookie.fp == NULL)
3785 {
3786 if (p_verbose > 0)
3787 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003788 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003790 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791 else
3792 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003793 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003794 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 }
3796 goto theend;
3797 }
3798
3799 /*
3800 * The file exists.
3801 * - In verbose mode, give a message.
3802 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3803 */
3804 if (p_verbose > 1)
3805 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003806 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003807 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003808 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809 else
3810 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003811 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003812 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003814 if (is_vimrc == DOSO_VIMRC)
3815 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3816 else if (is_vimrc == DOSO_GVIMRC)
3817 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818
3819#ifdef USE_CRNL
3820 /* If no automatic file format: Set default to CR-NL. */
3821 if (*p_ffs == NUL)
3822 cookie.fileformat = EOL_DOS;
3823 else
3824 cookie.fileformat = EOL_UNKNOWN;
3825 cookie.error = FALSE;
3826#endif
3827
3828#ifdef USE_CR
3829 /* If no automatic file format: Set default to CR. */
3830 if (*p_ffs == NUL)
3831 cookie.fileformat = EOL_MAC;
3832 else
3833 cookie.fileformat = EOL_UNKNOWN;
3834 cookie.error = FALSE;
3835#endif
3836
3837 cookie.nextline = NULL;
3838 cookie.finished = FALSE;
3839
3840#ifdef FEAT_EVAL
3841 /*
3842 * Check if this script has a breakpoint.
3843 */
3844 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3845 cookie.fname = fname_exp;
3846 cookie.dbg_tick = debug_tick;
3847
3848 cookie.level = ex_nesting_level;
3849#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850
3851 /*
3852 * Keep the sourcing name/lnum, for recursive calls.
3853 */
3854 save_sourcing_name = sourcing_name;
3855 sourcing_name = fname_exp;
3856 save_sourcing_lnum = sourcing_lnum;
3857 sourcing_lnum = 0;
3858
Bram Moolenaar73881402009-02-04 16:50:47 +00003859#ifdef FEAT_MBYTE
3860 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3861
3862 /* Read the first line so we can check for a UTF-8 BOM. */
3863 firstline = getsourceline(0, (void *)&cookie, 0);
3864 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3865 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3866 {
3867 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3868 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3869 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003870 if (p == NULL)
3871 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003872 if (p != NULL)
3873 {
3874 vim_free(firstline);
3875 firstline = p;
3876 }
3877 }
3878#endif
3879
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003881 if (time_fd != NULL)
3882 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883#endif
3884
3885#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003886# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003887 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003888 prof_child_enter(&wait_start); /* entering a child now */
3889# endif
3890
3891 /* Don't use local function variables, if called from a function.
3892 * Also starts profiling timer for nested script. */
3893 save_funccalp = save_funccal();
3894
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 /*
3896 * Check if this script was sourced before to finds its SID.
3897 * If it's new, generate a new SID.
3898 */
3899 save_current_SID = current_SID;
3900# ifdef UNIX
3901 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3902# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003903 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3904 {
3905 si = &SCRIPT_ITEM(current_SID);
3906 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003907 && (
3908# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003909 /* Compare dev/ino when possible, it catches symbolic
3910 * links. Also compare file names, the inode may change
3911 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003912 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003913 && (si->sn_dev == st.st_dev
3914 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003916 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003918 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 if (current_SID == 0)
3920 {
3921 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003922 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3923 == FAIL)
3924 goto almosttheend;
3925 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003927 ++script_items.ga_len;
3928 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3929# ifdef FEAT_PROFILE
3930 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003931# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003933 si = &SCRIPT_ITEM(current_SID);
3934 si->sn_name = fname_exp;
3935 fname_exp = NULL;
3936# ifdef UNIX
3937 if (stat_ok)
3938 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003939 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003940 si->sn_dev = st.st_dev;
3941 si->sn_ino = st.st_ino;
3942 }
3943 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003944 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003945# endif
3946
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947 /* Allocate the local script variables to use for this script. */
3948 new_script_vars(current_SID);
3949 }
3950
Bram Moolenaar05159a02005-02-26 23:04:13 +00003951# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003952 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003953 {
3954 int forceit;
3955
3956 /* Check if we do profiling for this script. */
3957 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3958 {
3959 script_do_profile(si);
3960 si->sn_pr_force = forceit;
3961 }
3962 if (si->sn_prof_on)
3963 {
3964 ++si->sn_pr_count;
3965 profile_start(&si->sn_pr_start);
3966 profile_zero(&si->sn_pr_children);
3967 }
3968 }
3969# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970#endif
3971
3972 /*
3973 * Call do_cmdline, which will call getsourceline() to get the lines.
3974 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003975 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003978
3979#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003980 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003981 {
3982 /* Get "si" again, "script_items" may have been reallocated. */
3983 si = &SCRIPT_ITEM(current_SID);
3984 if (si->sn_prof_on)
3985 {
3986 profile_end(&si->sn_pr_start);
3987 profile_sub_wait(&wait_start, &si->sn_pr_start);
3988 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003989 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3990 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003991 }
3992 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993#endif
3994
3995 if (got_int)
3996 EMSG(_(e_interr));
3997 sourcing_name = save_sourcing_name;
3998 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 if (p_verbose > 1)
4000 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004001 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004002 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004004 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004005 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004006 }
4007#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004008 if (time_fd != NULL)
4009 {
4010 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4011 time_msg((char *)IObuff, &tv_start);
4012 time_pop(&tv_rel);
4013 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014#endif
4015
4016#ifdef FEAT_EVAL
4017 /*
4018 * After a "finish" in debug mode, need to break at first command of next
4019 * sourced file.
4020 */
4021 if (save_debug_break_level > ex_nesting_level
4022 && debug_break_level == ex_nesting_level)
4023 ++debug_break_level;
4024#endif
4025
Bram Moolenaar05159a02005-02-26 23:04:13 +00004026#ifdef FEAT_EVAL
4027almosttheend:
4028 current_SID = save_current_SID;
4029 restore_funccal(save_funccalp);
4030# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004031 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004032 prof_child_exit(&wait_start); /* leaving a child now */
4033# endif
4034#endif
4035 fclose(cookie.fp);
4036 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004037 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004038#ifdef FEAT_MBYTE
4039 convert_setup(&cookie.conv, NULL, NULL);
4040#endif
4041
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042theend:
4043 vim_free(fname_exp);
4044 return retval;
4045}
4046
4047#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004048
Bram Moolenaar071d4272004-06-13 20:20:40 +00004049/*
4050 * ":scriptnames"
4051 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004052 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004053ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054{
4055 int i;
4056
Bram Moolenaar05159a02005-02-26 23:04:13 +00004057 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4058 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004059 {
4060 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4061 NameBuff, MAXPATHL, TRUE);
4062 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064}
4065
4066# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4067/*
4068 * Fix slashes in the list of script names for 'shellslash'.
4069 */
4070 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004071scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072{
4073 int i;
4074
Bram Moolenaar05159a02005-02-26 23:04:13 +00004075 for (i = 1; i <= script_items.ga_len; ++i)
4076 if (SCRIPT_ITEM(i).sn_name != NULL)
4077 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004078}
4079# endif
4080
4081/*
4082 * Get a pointer to a script name. Used for ":verbose set".
4083 */
4084 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004085get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086{
4087 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004088 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004090 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004092 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004093 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004094 return (char_u *)_("environment variable");
4095 if (id == SID_ERROR)
4096 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004097 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004099
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004100# if defined(EXITFREE) || defined(PROTO)
4101 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004102free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004103{
4104 int i;
4105
4106 for (i = script_items.ga_len; i > 0; --i)
4107 vim_free(SCRIPT_ITEM(i).sn_name);
4108 ga_clear(&script_items);
4109}
4110# endif
4111
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112#endif
4113
4114#if defined(USE_CR) || defined(PROTO)
4115
4116# if defined(__MSL__) && (__MSL__ >= 22)
4117/*
4118 * Newer version of the Metrowerks library handle DOS and UNIX files
4119 * without help.
4120 * Test with earlier versions, MSL 2.2 is the library supplied with
4121 * Codewarrior Pro 2.
4122 */
4123 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004124fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125{
4126 return fgets(s, n, stream);
4127}
4128# else
4129/*
4130 * Version of fgets() which also works for lines ending in a <CR> only
4131 * (Macintosh format).
4132 * For older versions of the Metrowerks library.
4133 * At least CodeWarrior 9 needed this code.
4134 */
4135 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004136fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004137{
4138 int c = 0;
4139 int char_read = 0;
4140
4141 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4142 {
4143 c = fgetc(stream);
4144 s[char_read++] = c;
4145 /* If the file is in DOS format, we need to skip a NL after a CR. I
4146 * thought it was the other way around, but this appears to work... */
4147 if (c == '\n')
4148 {
4149 c = fgetc(stream);
4150 if (c != '\r')
4151 ungetc(c, stream);
4152 }
4153 }
4154
4155 s[char_read] = 0;
4156 if (char_read == 0)
4157 return NULL;
4158
4159 if (feof(stream) && char_read == 1)
4160 return NULL;
4161
4162 return s;
4163}
4164# endif
4165#endif
4166
4167/*
4168 * Get one full line from a sourced file.
4169 * Called by do_cmdline() when it's called from do_source().
4170 *
4171 * Return a pointer to the line in allocated memory.
4172 * Return NULL for end-of-file or some error.
4173 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004175getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176{
4177 struct source_cookie *sp = (struct source_cookie *)cookie;
4178 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004179 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180
4181#ifdef FEAT_EVAL
4182 /* If breakpoints have been added/deleted need to check for it. */
4183 if (sp->dbg_tick < debug_tick)
4184 {
4185 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4186 sp->dbg_tick = debug_tick;
4187 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004188# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004189 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004190 script_line_end();
4191# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192#endif
4193 /*
4194 * Get current line. If there is a read-ahead line, use it, otherwise get
4195 * one now.
4196 */
4197 if (sp->finished)
4198 line = NULL;
4199 else if (sp->nextline == NULL)
4200 line = get_one_sourceline(sp);
4201 else
4202 {
4203 line = sp->nextline;
4204 sp->nextline = NULL;
4205 ++sourcing_lnum;
4206 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004207#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004208 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004209 script_line_start();
4210#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211
4212 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4213 * contain the 'C' flag. */
4214 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4215 {
4216 /* compensate for the one line read-ahead */
4217 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004218
4219 /* Get the next line and concatenate it when it starts with a
4220 * backslash. We always need to read the next line, keep it in
4221 * sp->nextline. */
4222 sp->nextline = get_one_sourceline(sp);
4223 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004225 garray_T ga;
4226
Bram Moolenaarb549a732012-02-22 18:29:33 +01004227 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004228 ga_concat(&ga, line);
4229 ga_concat(&ga, p + 1);
4230 for (;;)
4231 {
4232 vim_free(sp->nextline);
4233 sp->nextline = get_one_sourceline(sp);
4234 if (sp->nextline == NULL)
4235 break;
4236 p = skipwhite(sp->nextline);
4237 if (*p != '\\')
4238 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004239 /* Adjust the growsize to the current length to speed up
4240 * concatenating many lines. */
4241 if (ga.ga_len > 400)
4242 {
4243 if (ga.ga_len > 8000)
4244 ga.ga_growsize = 8000;
4245 else
4246 ga.ga_growsize = ga.ga_len;
4247 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004248 ga_concat(&ga, p + 1);
4249 }
4250 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004251 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004252 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 }
4254 }
4255
4256#ifdef FEAT_MBYTE
4257 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4258 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004259 char_u *s;
4260
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 /* Convert the encoding of the script line. */
4262 s = string_convert(&sp->conv, line, NULL);
4263 if (s != NULL)
4264 {
4265 vim_free(line);
4266 line = s;
4267 }
4268 }
4269#endif
4270
4271#ifdef FEAT_EVAL
4272 /* Did we encounter a breakpoint? */
4273 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4274 {
4275 dbg_breakpoint(sp->fname, sourcing_lnum);
4276 /* Find next breakpoint. */
4277 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4278 sp->dbg_tick = debug_tick;
4279 }
4280#endif
4281
4282 return line;
4283}
4284
4285 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004286get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287{
4288 garray_T ga;
4289 int len;
4290 int c;
4291 char_u *buf;
4292#ifdef USE_CRNL
4293 int has_cr; /* CR-LF found */
4294#endif
4295#ifdef USE_CR
4296 char_u *scan;
4297#endif
4298 int have_read = FALSE;
4299
4300 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004301 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302
4303 /*
4304 * Loop until there is a finished line (or end-of-file).
4305 */
4306 sourcing_lnum++;
4307 for (;;)
4308 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004309 /* make room to read at least 120 (more) characters */
4310 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311 break;
4312 buf = (char_u *)ga.ga_data;
4313
4314#ifdef USE_CR
4315 if (sp->fileformat == EOL_MAC)
4316 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004317 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4318 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 break;
4320 }
4321 else
4322#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004323 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4324 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004326 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327#ifdef USE_CRNL
4328 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4329 * CTRL-Z by its own, or after a NL. */
4330 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4331 && sp->fileformat == EOL_DOS
4332 && buf[len - 1] == Ctrl_Z)
4333 {
4334 buf[len - 1] = NUL;
4335 break;
4336 }
4337#endif
4338
4339#ifdef USE_CR
4340 /* If the read doesn't stop on a new line, and there's
4341 * some CR then we assume a Mac format */
4342 if (sp->fileformat == EOL_UNKNOWN)
4343 {
4344 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4345 sp->fileformat = EOL_MAC;
4346 else
4347 sp->fileformat = EOL_UNIX;
4348 }
4349
4350 if (sp->fileformat == EOL_MAC)
4351 {
4352 scan = vim_strchr(buf, '\r');
4353
4354 if (scan != NULL)
4355 {
4356 *scan = '\n';
4357 if (*(scan + 1) != 0)
4358 {
4359 *(scan + 1) = 0;
4360 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4361 }
4362 }
4363 len = STRLEN(buf);
4364 }
4365#endif
4366
4367 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368 ga.ga_len = len;
4369
4370 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004371 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372 continue;
4373
4374 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4375 {
4376#ifdef USE_CRNL
4377 has_cr = (len >= 2 && buf[len - 2] == '\r');
4378 if (sp->fileformat == EOL_UNKNOWN)
4379 {
4380 if (has_cr)
4381 sp->fileformat = EOL_DOS;
4382 else
4383 sp->fileformat = EOL_UNIX;
4384 }
4385
4386 if (sp->fileformat == EOL_DOS)
4387 {
4388 if (has_cr) /* replace trailing CR */
4389 {
4390 buf[len - 2] = '\n';
4391 --len;
4392 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393 }
4394 else /* lines like ":map xx yy^M" will have failed */
4395 {
4396 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004397 {
4398 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004399 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004400 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401 sp->error = TRUE;
4402 sp->fileformat = EOL_UNIX;
4403 }
4404 }
4405#endif
4406 /* The '\n' is escaped if there is an odd number of ^V's just
4407 * before it, first set "c" just before the 'V's and then check
4408 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4409 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4410 ;
4411 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4412 {
4413 sourcing_lnum++;
4414 continue;
4415 }
4416
4417 buf[len - 1] = NUL; /* remove the NL */
4418 }
4419
4420 /*
4421 * Check for ^C here now and then, so recursive :so can be broken.
4422 */
4423 line_breakcheck();
4424 break;
4425 }
4426
4427 if (have_read)
4428 return (char_u *)ga.ga_data;
4429
4430 vim_free(ga.ga_data);
4431 return NULL;
4432}
4433
Bram Moolenaar05159a02005-02-26 23:04:13 +00004434#if defined(FEAT_PROFILE) || defined(PROTO)
4435/*
4436 * Called when starting to read a script line.
4437 * "sourcing_lnum" must be correct!
4438 * When skipping lines it may not actually be executed, but we won't find out
4439 * until later and we need to store the time now.
4440 */
4441 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004442script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004443{
4444 scriptitem_T *si;
4445 sn_prl_T *pp;
4446
4447 if (current_SID <= 0 || current_SID > script_items.ga_len)
4448 return;
4449 si = &SCRIPT_ITEM(current_SID);
4450 if (si->sn_prof_on && sourcing_lnum >= 1)
4451 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004452 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004453 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004454 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004455 si->sn_prl_idx = sourcing_lnum - 1;
4456 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4457 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4458 {
4459 /* Zero counters for a line that was not used before. */
4460 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4461 pp->snp_count = 0;
4462 profile_zero(&pp->sn_prl_total);
4463 profile_zero(&pp->sn_prl_self);
4464 ++si->sn_prl_ga.ga_len;
4465 }
4466 si->sn_prl_execed = FALSE;
4467 profile_start(&si->sn_prl_start);
4468 profile_zero(&si->sn_prl_children);
4469 profile_get_wait(&si->sn_prl_wait);
4470 }
4471}
4472
4473/*
4474 * Called when actually executing a function line.
4475 */
4476 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004477script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004478{
4479 scriptitem_T *si;
4480
4481 if (current_SID <= 0 || current_SID > script_items.ga_len)
4482 return;
4483 si = &SCRIPT_ITEM(current_SID);
4484 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4485 si->sn_prl_execed = TRUE;
4486}
4487
4488/*
4489 * Called when done with a function line.
4490 */
4491 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004492script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004493{
4494 scriptitem_T *si;
4495 sn_prl_T *pp;
4496
4497 if (current_SID <= 0 || current_SID > script_items.ga_len)
4498 return;
4499 si = &SCRIPT_ITEM(current_SID);
4500 if (si->sn_prof_on && si->sn_prl_idx >= 0
4501 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4502 {
4503 if (si->sn_prl_execed)
4504 {
4505 pp = &PRL_ITEM(si, si->sn_prl_idx);
4506 ++pp->snp_count;
4507 profile_end(&si->sn_prl_start);
4508 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004509 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004510 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4511 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004512 }
4513 si->sn_prl_idx = -1;
4514 }
4515}
4516#endif
4517
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518/*
4519 * ":scriptencoding": Set encoding conversion for a sourced script.
4520 * Without the multi-byte feature it's simply ignored.
4521 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004523ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524{
4525#ifdef FEAT_MBYTE
4526 struct source_cookie *sp;
4527 char_u *name;
4528
4529 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4530 {
4531 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4532 return;
4533 }
4534
4535 if (*eap->arg != NUL)
4536 {
4537 name = enc_canonize(eap->arg);
4538 if (name == NULL) /* out of memory */
4539 return;
4540 }
4541 else
4542 name = eap->arg;
4543
4544 /* Setup for conversion from the specified encoding to 'encoding'. */
4545 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4546 convert_setup(&sp->conv, name, p_enc);
4547
4548 if (name != eap->arg)
4549 vim_free(name);
4550#endif
4551}
4552
4553#if defined(FEAT_EVAL) || defined(PROTO)
4554/*
4555 * ":finish": Mark a sourced file as finished.
4556 */
4557 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004558ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559{
4560 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4561 do_finish(eap, FALSE);
4562 else
4563 EMSG(_("E168: :finish used outside of a sourced file"));
4564}
4565
4566/*
4567 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4568 * Also called for a pending finish at the ":endtry" or after returning from
4569 * an extra do_cmdline(). "reanimate" is used in the latter case.
4570 */
4571 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004572do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573{
4574 int idx;
4575
4576 if (reanimate)
4577 ((struct source_cookie *)getline_cookie(eap->getline,
4578 eap->cookie))->finished = FALSE;
4579
4580 /*
4581 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4582 * not in its finally clause (which then is to be executed next) is found.
4583 * In this case, make the ":finish" pending for execution at the ":endtry".
4584 * Otherwise, finish normally.
4585 */
4586 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4587 if (idx >= 0)
4588 {
4589 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4590 report_make_pending(CSTP_FINISH, NULL);
4591 }
4592 else
4593 ((struct source_cookie *)getline_cookie(eap->getline,
4594 eap->cookie))->finished = TRUE;
4595}
4596
4597
4598/*
4599 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4600 * message for missing ":endif".
4601 * Return FALSE when not sourcing a file.
4602 */
4603 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004604source_finished(
4605 char_u *(*fgetline)(int, void *, int),
4606 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004608 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004610 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611}
4612#endif
4613
4614#if defined(FEAT_LISTCMDS) || defined(PROTO)
4615/*
4616 * ":checktime [buffer]"
4617 */
4618 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004619ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620{
4621 buf_T *buf;
4622 int save_no_check_timestamps = no_check_timestamps;
4623
4624 no_check_timestamps = 0;
4625 if (eap->addr_count == 0) /* default is all buffers */
4626 check_timestamps(FALSE);
4627 else
4628 {
4629 buf = buflist_findnr((int)eap->line2);
4630 if (buf != NULL) /* cannot happen? */
4631 (void)buf_check_timestamp(buf, FALSE);
4632 }
4633 no_check_timestamps = save_no_check_timestamps;
4634}
4635#endif
4636
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4638 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004639# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004640static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004642 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004643get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004645 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004647 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004648 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004650# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651 if (loc != NULL)
4652 {
4653 char_u *p;
4654
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004655 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4656 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 p = vim_strchr(loc, '=');
4658 if (p != NULL)
4659 {
4660 loc = ++p;
4661 while (*p != NUL) /* remove trailing newline */
4662 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004663 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 {
4665 *p = NUL;
4666 break;
4667 }
4668 ++p;
4669 }
4670 }
4671 }
4672# endif
4673
4674 return loc;
4675}
4676#endif
4677
4678
4679#ifdef WIN32
4680/*
4681 * On MS-Windows locale names are strings like "German_Germany.1252", but
4682 * gettext expects "de". Try to translate one into another here for a few
4683 * supported languages.
4684 */
4685 static char_u *
4686gettext_lang(char_u *name)
4687{
4688 int i;
4689 static char *(mtable[]) = {
4690 "afrikaans", "af",
4691 "czech", "cs",
4692 "dutch", "nl",
4693 "german", "de",
4694 "english_united kingdom", "en_GB",
4695 "spanish", "es",
4696 "french", "fr",
4697 "italian", "it",
4698 "japanese", "ja",
4699 "korean", "ko",
4700 "norwegian", "no",
4701 "polish", "pl",
4702 "russian", "ru",
4703 "slovak", "sk",
4704 "swedish", "sv",
4705 "ukrainian", "uk",
4706 "chinese_china", "zh_CN",
4707 "chinese_taiwan", "zh_TW",
4708 NULL};
4709
4710 for (i = 0; mtable[i] != NULL; i += 2)
4711 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004712 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713 return name;
4714}
4715#endif
4716
4717#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4718/*
4719 * Obtain the current messages language. Used to set the default for
4720 * 'helplang'. May return NULL or an empty string.
4721 */
4722 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004723get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004724{
4725 char_u *p;
4726
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004727# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004729 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730# else
4731 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004732 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4733 * and LC_MONETARY may be set differently for a Japanese working in the
4734 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004735 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736# endif
4737# else
4738 p = mch_getenv((char_u *)"LC_ALL");
4739 if (p == NULL || *p == NUL)
4740 {
4741 p = mch_getenv((char_u *)"LC_MESSAGES");
4742 if (p == NULL || *p == NUL)
4743 p = mch_getenv((char_u *)"LANG");
4744 }
4745# endif
4746# ifdef WIN32
4747 p = gettext_lang(p);
4748# endif
4749 return p;
4750}
4751#endif
4752
Bram Moolenaardef9e822004-12-31 20:58:58 +00004753/* Complicated #if; matches with where get_mess_env() is used below. */
4754#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4755 && defined(LC_MESSAGES))) \
4756 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4757 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4758 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004759static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760
4761/*
4762 * Get the language used for messages from the environment.
4763 */
4764 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004765get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766{
4767 char_u *p;
4768
4769 p = mch_getenv((char_u *)"LC_ALL");
4770 if (p == NULL || *p == NUL)
4771 {
4772 p = mch_getenv((char_u *)"LC_MESSAGES");
4773 if (p == NULL || *p == NUL)
4774 {
4775 p = mch_getenv((char_u *)"LANG");
4776 if (p != NULL && VIM_ISDIGIT(*p))
4777 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004778# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004780 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781# endif
4782 }
4783 }
4784 return p;
4785}
4786#endif
4787
4788#if defined(FEAT_EVAL) || defined(PROTO)
4789
4790/*
4791 * Set the "v:lang" variable according to the current locale setting.
4792 * Also do "v:lc_time"and "v:ctype".
4793 */
4794 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004795set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796{
4797 char_u *loc;
4798
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004799# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004800 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801# else
4802 /* setlocale() not supported: use the default value */
4803 loc = (char_u *)"C";
4804# endif
4805 set_vim_var_string(VV_CTYPE, loc, -1);
4806
4807 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4808 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004809# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004810 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811# else
4812 loc = get_mess_env();
4813# endif
4814 set_vim_var_string(VV_LANG, loc, -1);
4815
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004816# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004817 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004818# endif
4819 set_vim_var_string(VV_LC_TIME, loc, -1);
4820}
4821#endif
4822
4823#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4824 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4825/*
4826 * ":language": Set the language (locale).
4827 */
4828 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004829ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004830{
4831 char *loc;
4832 char_u *p;
4833 char_u *name;
4834 int what = LC_ALL;
4835 char *whatstr = "";
4836#ifdef LC_MESSAGES
4837# define VIM_LC_MESSAGES LC_MESSAGES
4838#else
4839# define VIM_LC_MESSAGES 6789
4840#endif
4841
4842 name = eap->arg;
4843
4844 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4845 * Allow abbreviation, but require at least 3 characters to avoid
4846 * confusion with a two letter language name "me" or "ct". */
4847 p = skiptowhite(eap->arg);
4848 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4849 {
4850 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4851 {
4852 what = VIM_LC_MESSAGES;
4853 name = skipwhite(p);
4854 whatstr = "messages ";
4855 }
4856 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4857 {
4858 what = LC_CTYPE;
4859 name = skipwhite(p);
4860 whatstr = "ctype ";
4861 }
4862 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4863 {
4864 what = LC_TIME;
4865 name = skipwhite(p);
4866 whatstr = "time ";
4867 }
4868 }
4869
4870 if (*name == NUL)
4871 {
4872#ifndef LC_MESSAGES
4873 if (what == VIM_LC_MESSAGES)
4874 p = get_mess_env();
4875 else
4876#endif
4877 p = (char_u *)setlocale(what, NULL);
4878 if (p == NULL || *p == NUL)
4879 p = (char_u *)"Unknown";
4880 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4881 }
4882 else
4883 {
4884#ifndef LC_MESSAGES
4885 if (what == VIM_LC_MESSAGES)
4886 loc = "";
4887 else
4888#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004889 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004890 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004891#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4892 /* Make sure strtod() uses a decimal point, not a comma. */
4893 setlocale(LC_NUMERIC, "C");
4894#endif
4895 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896 if (loc == NULL)
4897 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4898 else
4899 {
4900#ifdef HAVE_NL_MSG_CAT_CNTR
4901 /* Need to do this for GNU gettext, otherwise cached translations
4902 * will be used again. */
4903 extern int _nl_msg_cat_cntr;
4904
4905 ++_nl_msg_cat_cntr;
4906#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004907 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004908 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4909
4910 if (what != LC_TIME)
4911 {
4912 /* Tell gettext() what to translate to. It apparently doesn't
4913 * use the currently effective locale. Also do this when
4914 * FEAT_GETTEXT isn't defined, so that shell commands use this
4915 * value. */
4916 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004917 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004919
4920 /* Clear $LANGUAGE because GNU gettext uses it. */
4921 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004922# ifdef WIN32
4923 /* Apparently MS-Windows printf() may cause a crash when
4924 * we give it 8-bit text while it's expecting text in the
4925 * current locale. This call avoids that. */
4926 setlocale(LC_CTYPE, "C");
4927# endif
4928 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004929 if (what != LC_CTYPE)
4930 {
4931 char_u *mname;
4932#ifdef WIN32
4933 mname = gettext_lang(name);
4934#else
4935 mname = name;
4936#endif
4937 vim_setenv((char_u *)"LC_MESSAGES", mname);
4938#ifdef FEAT_MULTI_LANG
4939 set_helplang_default(mname);
4940#endif
4941 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942 }
4943
4944# ifdef FEAT_EVAL
4945 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4946 set_lang_var();
4947# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004948# ifdef FEAT_TITLE
4949 maketitle();
4950# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 }
4952 }
4953}
4954
4955# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004956
4957static char_u **locales = NULL; /* Array of all available locales */
4958static int did_init_locales = FALSE;
4959
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004960static void init_locales(void);
4961static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004962
4963/*
4964 * Lazy initialization of all available locales.
4965 */
4966 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004967init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004968{
4969 if (!did_init_locales)
4970 {
4971 did_init_locales = TRUE;
4972 locales = find_locales();
4973 }
4974}
4975
4976/* Return an array of strings for all available locales + NULL for the
4977 * last element. Return NULL in case of error. */
4978 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004979find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004980{
4981 garray_T locales_ga;
4982 char_u *loc;
4983
4984 /* Find all available locales by running command "locale -a". If this
4985 * doesn't work we won't have completion. */
4986 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004987 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004988 if (locale_a == NULL)
4989 return NULL;
4990 ga_init2(&locales_ga, sizeof(char_u *), 20);
4991
4992 /* Transform locale_a string where each locale is separated by "\n"
4993 * into an array of locale strings. */
4994 loc = (char_u *)strtok((char *)locale_a, "\n");
4995
4996 while (loc != NULL)
4997 {
4998 if (ga_grow(&locales_ga, 1) == FAIL)
4999 break;
5000 loc = vim_strsave(loc);
5001 if (loc == NULL)
5002 break;
5003
5004 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5005 loc = (char_u *)strtok(NULL, "\n");
5006 }
5007 vim_free(locale_a);
5008 if (ga_grow(&locales_ga, 1) == FAIL)
5009 {
5010 ga_clear(&locales_ga);
5011 return NULL;
5012 }
5013 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5014 return (char_u **)locales_ga.ga_data;
5015}
5016
5017# if defined(EXITFREE) || defined(PROTO)
5018 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005019free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005020{
5021 int i;
5022 if (locales != NULL)
5023 {
5024 for (i = 0; locales[i] != NULL; i++)
5025 vim_free(locales[i]);
5026 vim_free(locales);
5027 locales = NULL;
5028 }
5029}
5030# endif
5031
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032/*
5033 * Function given to ExpandGeneric() to obtain the possible arguments of the
5034 * ":language" command.
5035 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005037get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038{
5039 if (idx == 0)
5040 return (char_u *)"messages";
5041 if (idx == 1)
5042 return (char_u *)"ctype";
5043 if (idx == 2)
5044 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005045
5046 init_locales();
5047 if (locales == NULL)
5048 return NULL;
5049 return locales[idx - 3];
5050}
5051
5052/*
5053 * Function given to ExpandGeneric() to obtain the available locales.
5054 */
5055 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005056get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005057{
5058 init_locales();
5059 if (locales == NULL)
5060 return NULL;
5061 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062}
5063# endif
5064
5065#endif