blob: 33ad924d222348e5dab90770e1245e6581effeaa [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001091static long last_timer_id = 0;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001092
Bram Moolenaar75537a92016-09-05 22:45:28 +02001093# ifdef WIN3264
1094# define GET_TIMEDIFF(timer, now) \
1095 (long)(((double)(timer->tr_due.QuadPart - now.QuadPart) \
Bram Moolenaara7c023e2016-10-12 12:13:35 +02001096 / (double)fr.QuadPart) * 1000)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001097# else
1098# define GET_TIMEDIFF(timer, now) \
1099 (timer->tr_due.tv_sec - now.tv_sec) * 1000 \
Bram Moolenaara7c023e2016-10-12 12:13:35 +02001100 + (timer->tr_due.tv_usec - now.tv_usec) / 1000
Bram Moolenaar75537a92016-09-05 22:45:28 +02001101# endif
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001102
Bram Moolenaar975b5272016-03-15 23:10:59 +01001103/*
1104 * Insert a timer in the list of timers.
1105 */
1106 static void
1107insert_timer(timer_T *timer)
1108{
1109 timer->tr_next = first_timer;
1110 timer->tr_prev = NULL;
1111 if (first_timer != NULL)
1112 first_timer->tr_prev = timer;
1113 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001114 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001115}
1116
1117/*
1118 * Take a timer out of the list of timers.
1119 */
1120 static void
1121remove_timer(timer_T *timer)
1122{
1123 if (timer->tr_prev == NULL)
1124 first_timer = timer->tr_next;
1125 else
1126 timer->tr_prev->tr_next = timer->tr_next;
1127 if (timer->tr_next != NULL)
1128 timer->tr_next->tr_prev = timer->tr_prev;
1129}
1130
1131 static void
1132free_timer(timer_T *timer)
1133{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001134 free_callback(timer->tr_callback, timer->tr_partial);
1135 vim_free(timer);
Bram Moolenaar975b5272016-03-15 23:10:59 +01001136}
1137
1138/*
1139 * Create a timer and return it. NULL if out of memory.
1140 * Caller should set the callback.
1141 */
1142 timer_T *
1143create_timer(long msec, int repeat)
1144{
1145 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
Bram Moolenaaree39ef02016-09-10 19:17:42 +02001146 long prev_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001147
1148 if (timer == NULL)
1149 return NULL;
Bram Moolenaaree39ef02016-09-10 19:17:42 +02001150 if (++last_timer_id <= prev_id)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001151 /* Overflow! Might cause duplicates... */
1152 last_timer_id = 0;
1153 timer->tr_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001154 insert_timer(timer);
1155 if (repeat != 0)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001156 timer->tr_repeat = repeat - 1;
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001157 timer->tr_interval = msec;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001158
1159 profile_setlimit(msec, &timer->tr_due);
1160 return timer;
1161}
1162
1163/*
1164 * Invoke the callback of "timer".
1165 */
1166 static void
1167timer_callback(timer_T *timer)
1168{
1169 typval_T rettv;
1170 int dummy;
1171 typval_T argv[2];
1172
1173 argv[0].v_type = VAR_NUMBER;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001174 argv[0].vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001175 argv[1].v_type = VAR_UNKNOWN;
1176
1177 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
Bram Moolenaardf48fb42016-07-22 21:50:18 +02001178 &rettv, 1, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar975b5272016-03-15 23:10:59 +01001179 timer->tr_partial, NULL);
1180 clear_tv(&rettv);
1181}
1182
1183/*
1184 * Call timers that are due.
1185 * Return the time in msec until the next timer is due.
1186 */
1187 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001188check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001189{
1190 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001191 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001192 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001193 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001194 proftime_T now;
1195 int did_one = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001196 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001197# ifdef WIN3264
1198 LARGE_INTEGER fr;
1199
1200 QueryPerformanceFrequency(&fr);
1201# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001202 profile_start(&now);
1203 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001204 {
Bram Moolenaar75537a92016-09-05 22:45:28 +02001205 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001206
Bram Moolenaar75537a92016-09-05 22:45:28 +02001207 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
1208 continue;
1209 this_due = GET_TIMEDIFF(timer, now);
1210 if (this_due <= 1)
1211 {
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001212 int save_timer_busy = timer_busy;
1213 int save_vgetc_busy = vgetc_busy;
1214
1215 timer_busy = timer_busy > 0 || vgetc_busy > 0;
1216 vgetc_busy = 0;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001217 timer->tr_firing = TRUE;
1218 timer_callback(timer);
1219 timer->tr_firing = FALSE;
1220 timer_next = timer->tr_next;
1221 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001222 timer_busy = save_timer_busy;
1223 vgetc_busy = save_vgetc_busy;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001224
1225 /* Only fire the timer again if it repeats and stop_timer() wasn't
1226 * called while inside the callback (tr_id == -1). */
1227 if (timer->tr_repeat != 0 && timer->tr_id != -1)
1228 {
1229 profile_setlimit(timer->tr_interval, &timer->tr_due);
1230 this_due = GET_TIMEDIFF(timer, now);
1231 if (this_due < 1)
1232 this_due = 1;
1233 if (timer->tr_repeat > 0)
1234 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001235 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001236 else
1237 {
1238 this_due = -1;
1239 remove_timer(timer);
1240 free_timer(timer);
1241 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001242 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001243 if (this_due > 0 && (next_due == -1 || next_due > this_due))
1244 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001245 }
1246
1247 if (did_one)
1248 redraw_after_callback();
1249
Bram Moolenaar75537a92016-09-05 22:45:28 +02001250 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001251}
1252
1253/*
1254 * Find a timer by ID. Returns NULL if not found;
1255 */
1256 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +02001257find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001258{
1259 timer_T *timer;
1260
Bram Moolenaar75537a92016-09-05 22:45:28 +02001261 if (id >= 0)
1262 {
1263 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1264 if (timer->tr_id == id)
1265 return timer;
1266 }
1267 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001268}
1269
1270
1271/*
1272 * Stop a timer and delete it.
1273 */
1274 void
1275stop_timer(timer_T *timer)
1276{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001277 if (timer->tr_firing)
1278 /* Free the timer after the callback returns. */
1279 timer->tr_id = -1;
1280 else
1281 {
1282 remove_timer(timer);
1283 free_timer(timer);
1284 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001285}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001286
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001287 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001288stop_all_timers(void)
1289{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001290 timer_T *timer;
1291 timer_T *timer_next;
1292
1293 for (timer = first_timer; timer != NULL; timer = timer_next)
1294 {
1295 timer_next = timer->tr_next;
1296 stop_timer(timer);
1297 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001298}
1299
1300 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001301add_timer_info(typval_T *rettv, timer_T *timer)
1302{
1303 list_T *list = rettv->vval.v_list;
1304 dict_T *dict = dict_alloc();
1305 dictitem_T *di;
1306 long remaining;
1307 proftime_T now;
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001308# ifdef WIN3264
1309 LARGE_INTEGER fr;
1310#endif
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001311
1312 if (dict == NULL)
1313 return;
1314 list_append_dict(list, dict);
1315
Bram Moolenaar75537a92016-09-05 22:45:28 +02001316 dict_add_nr_str(dict, "id", timer->tr_id, NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001317 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1318
1319 profile_start(&now);
1320# ifdef WIN3264
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001321 QueryPerformanceFrequency(&fr);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001322# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001323 remaining = GET_TIMEDIFF(timer, now);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001324 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1325
1326 dict_add_nr_str(dict, "repeat",
1327 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001328 dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001329
1330 di = dictitem_alloc((char_u *)"callback");
1331 if (di != NULL)
1332 {
1333 if (dict_add(dict, di) == FAIL)
1334 vim_free(di);
1335 else if (timer->tr_partial != NULL)
1336 {
1337 di->di_tv.v_type = VAR_PARTIAL;
1338 di->di_tv.vval.v_partial = timer->tr_partial;
1339 ++timer->tr_partial->pt_refcount;
1340 }
1341 else
1342 {
1343 di->di_tv.v_type = VAR_FUNC;
1344 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1345 }
1346 di->di_tv.v_lock = 0;
1347 }
1348}
1349
1350 void
1351add_timer_info_all(typval_T *rettv)
1352{
1353 timer_T *timer;
1354
1355 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001356 if (timer->tr_id != -1)
1357 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001358}
1359
Bram Moolenaare3188e22016-05-31 21:13:04 +02001360/*
1361 * Mark references in partials of timers.
1362 */
1363 int
1364set_ref_in_timer(int copyID)
1365{
1366 int abort = FALSE;
1367 timer_T *timer;
1368 typval_T tv;
1369
1370 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1371 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001372 if (timer->tr_partial != NULL)
1373 {
1374 tv.v_type = VAR_PARTIAL;
1375 tv.vval.v_partial = timer->tr_partial;
1376 }
1377 else
1378 {
1379 tv.v_type = VAR_FUNC;
1380 tv.vval.v_string = timer->tr_callback;
1381 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001382 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1383 }
1384 return abort;
1385}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001386
1387# if defined(EXITFREE) || defined(PROTO)
1388 void
1389timer_free_all()
1390{
1391 timer_T *timer;
1392
1393 while (first_timer != NULL)
1394 {
1395 timer = first_timer;
1396 remove_timer(timer);
1397 free_timer(timer);
1398 }
1399}
1400# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001401# endif
1402
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001403#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1404# if defined(HAVE_MATH_H)
1405# include <math.h>
1406# endif
1407
1408/*
1409 * Divide the time "tm" by "count" and store in "tm2".
1410 */
1411 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001412profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001413{
1414 if (count == 0)
1415 profile_zero(tm2);
1416 else
1417 {
1418# ifdef WIN3264
1419 tm2->QuadPart = tm->QuadPart / count;
1420# else
1421 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1422
1423 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001424 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001425# endif
1426 }
1427}
1428#endif
1429
Bram Moolenaar76929292008-01-06 19:07:36 +00001430# if defined(FEAT_PROFILE) || defined(PROTO)
1431/*
1432 * Functions for profiling.
1433 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001434static void script_do_profile(scriptitem_T *si);
1435static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001436static proftime_T prof_wait_time;
1437
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001438/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001439 * Add the time "tm2" to "tm".
1440 */
1441 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001442profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001443{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001444# ifdef WIN3264
1445 tm->QuadPart += tm2->QuadPart;
1446# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001447 tm->tv_usec += tm2->tv_usec;
1448 tm->tv_sec += tm2->tv_sec;
1449 if (tm->tv_usec >= 1000000)
1450 {
1451 tm->tv_usec -= 1000000;
1452 ++tm->tv_sec;
1453 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001454# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001455}
1456
1457/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001458 * Add the "self" time from the total time and the children's time.
1459 */
1460 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001461profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001462{
1463 /* Check that the result won't be negative. Can happen with recursive
1464 * calls. */
1465#ifdef WIN3264
1466 if (total->QuadPart <= children->QuadPart)
1467 return;
1468#else
1469 if (total->tv_sec < children->tv_sec
1470 || (total->tv_sec == children->tv_sec
1471 && total->tv_usec <= children->tv_usec))
1472 return;
1473#endif
1474 profile_add(self, total);
1475 profile_sub(self, children);
1476}
1477
1478/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001479 * Get the current waittime.
1480 */
1481 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001482profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001483{
1484 *tm = prof_wait_time;
1485}
1486
1487/*
1488 * Subtract the passed waittime since "tm" from "tma".
1489 */
1490 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001491profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001492{
1493 proftime_T tm3 = prof_wait_time;
1494
1495 profile_sub(&tm3, tm);
1496 profile_sub(tma, &tm3);
1497}
1498
1499/*
1500 * Return TRUE if "tm1" and "tm2" are equal.
1501 */
1502 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001503profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001504{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001505# ifdef WIN3264
1506 return (tm1->QuadPart == tm2->QuadPart);
1507# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001508 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001509# endif
1510}
1511
1512/*
1513 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1514 */
1515 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001516profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001517{
1518# ifdef WIN3264
1519 return (int)(tm2->QuadPart - tm1->QuadPart);
1520# else
1521 if (tm1->tv_sec == tm2->tv_sec)
1522 return tm2->tv_usec - tm1->tv_usec;
1523 return tm2->tv_sec - tm1->tv_sec;
1524# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001525}
1526
Bram Moolenaar05159a02005-02-26 23:04:13 +00001527static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001528static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001529
1530/*
1531 * ":profile cmd args"
1532 */
1533 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001534ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001535{
1536 char_u *e;
1537 int len;
1538
1539 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001540 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001541 e = skipwhite(e);
1542
1543 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1544 {
1545 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001546 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001547 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001548 profile_zero(&prof_wait_time);
1549 set_vim_var_nr(VV_PROFILING, 1L);
1550 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001551 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001552 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001553 else if (STRCMP(eap->arg, "pause") == 0)
1554 {
1555 if (do_profiling == PROF_YES)
1556 profile_start(&pause_time);
1557 do_profiling = PROF_PAUSED;
1558 }
1559 else if (STRCMP(eap->arg, "continue") == 0)
1560 {
1561 if (do_profiling == PROF_PAUSED)
1562 {
1563 profile_end(&pause_time);
1564 profile_add(&prof_wait_time, &pause_time);
1565 }
1566 do_profiling = PROF_YES;
1567 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001568 else
1569 {
1570 /* The rest is similar to ":breakadd". */
1571 ex_breakadd(eap);
1572 }
1573}
1574
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001575/* Command line expansion for :profile. */
1576static enum
1577{
1578 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001579 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001580} pexpand_what;
1581
1582static char *pexpand_cmds[] = {
1583 "start",
1584#define PROFCMD_START 0
1585 "pause",
1586#define PROFCMD_PAUSE 1
1587 "continue",
1588#define PROFCMD_CONTINUE 2
1589 "func",
1590#define PROFCMD_FUNC 3
1591 "file",
1592#define PROFCMD_FILE 4
1593 NULL
1594#define PROFCMD_LAST 5
1595};
1596
1597/*
1598 * Function given to ExpandGeneric() to obtain the profile command
1599 * specific expansion.
1600 */
1601 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001602get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001603{
1604 switch (pexpand_what)
1605 {
1606 case PEXP_SUBCMD:
1607 return (char_u *)pexpand_cmds[idx];
1608 /* case PEXP_FUNC: TODO */
1609 default:
1610 return NULL;
1611 }
1612}
1613
1614/*
1615 * Handle command line completion for :profile command.
1616 */
1617 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001618set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001619{
1620 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001621
1622 /* Default: expand subcommands. */
1623 xp->xp_context = EXPAND_PROFILE;
1624 pexpand_what = PEXP_SUBCMD;
1625 xp->xp_pattern = arg;
1626
1627 end_subcmd = skiptowhite(arg);
1628 if (*end_subcmd == NUL)
1629 return;
1630
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001631 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001632 {
1633 xp->xp_context = EXPAND_FILES;
1634 xp->xp_pattern = skipwhite(end_subcmd);
1635 return;
1636 }
1637
1638 /* TODO: expand function names after "func" */
1639 xp->xp_context = EXPAND_NOTHING;
1640}
1641
Bram Moolenaar05159a02005-02-26 23:04:13 +00001642/*
1643 * Dump the profiling info.
1644 */
1645 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001646profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001647{
1648 FILE *fd;
1649
1650 if (profile_fname != NULL)
1651 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001652 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001653 if (fd == NULL)
1654 EMSG2(_(e_notopen), profile_fname);
1655 else
1656 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001657 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001658 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001659 fclose(fd);
1660 }
1661 }
1662}
1663
1664/*
1665 * Start profiling script "fp".
1666 */
1667 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001668script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001669{
1670 si->sn_pr_count = 0;
1671 profile_zero(&si->sn_pr_total);
1672 profile_zero(&si->sn_pr_self);
1673
1674 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1675 si->sn_prl_idx = -1;
1676 si->sn_prof_on = TRUE;
1677 si->sn_pr_nest = 0;
1678}
1679
1680/*
1681 * save time when starting to invoke another script or function.
1682 */
1683 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001684script_prof_save(
1685 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001686{
1687 scriptitem_T *si;
1688
1689 if (current_SID > 0 && current_SID <= script_items.ga_len)
1690 {
1691 si = &SCRIPT_ITEM(current_SID);
1692 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1693 profile_start(&si->sn_pr_child);
1694 }
1695 profile_get_wait(tm);
1696}
1697
1698/*
1699 * Count time spent in children after invoking another script or function.
1700 */
1701 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001702script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001703{
1704 scriptitem_T *si;
1705
1706 if (current_SID > 0 && current_SID <= script_items.ga_len)
1707 {
1708 si = &SCRIPT_ITEM(current_SID);
1709 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1710 {
1711 profile_end(&si->sn_pr_child);
1712 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1713 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1714 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1715 }
1716 }
1717}
1718
1719static proftime_T inchar_time;
1720
1721/*
1722 * Called when starting to wait for the user to type a character.
1723 */
1724 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001725prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001726{
1727 profile_start(&inchar_time);
1728}
1729
1730/*
1731 * Called when finished waiting for the user to type a character.
1732 */
1733 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001734prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001735{
1736 profile_end(&inchar_time);
1737 profile_add(&prof_wait_time, &inchar_time);
1738}
1739
1740/*
1741 * Dump the profiling results for all scripts in file "fd".
1742 */
1743 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001744script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001745{
1746 int id;
1747 scriptitem_T *si;
1748 int i;
1749 FILE *sfd;
1750 sn_prl_T *pp;
1751
1752 for (id = 1; id <= script_items.ga_len; ++id)
1753 {
1754 si = &SCRIPT_ITEM(id);
1755 if (si->sn_prof_on)
1756 {
1757 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1758 if (si->sn_pr_count == 1)
1759 fprintf(fd, "Sourced 1 time\n");
1760 else
1761 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1762 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1763 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1764 fprintf(fd, "\n");
1765 fprintf(fd, "count total (s) self (s)\n");
1766
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001767 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001768 if (sfd == NULL)
1769 fprintf(fd, "Cannot open file!\n");
1770 else
1771 {
1772 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1773 {
1774 if (vim_fgets(IObuff, IOSIZE, sfd))
1775 break;
1776 pp = &PRL_ITEM(si, i);
1777 if (pp->snp_count > 0)
1778 {
1779 fprintf(fd, "%5d ", pp->snp_count);
1780 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1781 fprintf(fd, " ");
1782 else
1783 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1784 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1785 }
1786 else
1787 fprintf(fd, " ");
1788 fprintf(fd, "%s", IObuff);
1789 }
1790 fclose(sfd);
1791 }
1792 fprintf(fd, "\n");
1793 }
1794 }
1795}
1796
1797/*
1798 * Return TRUE when a function defined in the current script should be
1799 * profiled.
1800 */
1801 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001802prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001803{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001804 if (current_SID > 0)
1805 return SCRIPT_ITEM(current_SID).sn_pr_force;
1806 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001807}
1808
1809# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001810#endif
1811
1812/*
1813 * If 'autowrite' option set, try to write the file.
1814 * Careful: autocommands may make "buf" invalid!
1815 *
1816 * return FAIL for failure, OK otherwise
1817 */
1818 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001819autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001821 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001822 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001823
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 if (!(p_aw || p_awa) || !p_write
1825#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001826 /* never autowrite a "nofile" or "nowrite" buffer */
1827 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001829 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001830 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001831 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001832 r = buf_write_all(buf, forceit);
1833
1834 /* Writing may succeed but the buffer still changed, e.g., when there is a
1835 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001836 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001837 r = FAIL;
1838 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839}
1840
1841/*
1842 * flush all buffers, except the ones that are readonly
1843 */
1844 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001845autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846{
1847 buf_T *buf;
1848
1849 if (!(p_aw || p_awa) || !p_write)
1850 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001851 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001852 if (bufIsChanged(buf) && !buf->b_p_ro)
1853 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001854#ifdef FEAT_AUTOCMD
1855 bufref_T bufref;
1856
1857 set_bufref(&bufref, buf);
1858#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 (void)buf_write_all(buf, FALSE);
1860#ifdef FEAT_AUTOCMD
1861 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001862 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001863 buf = firstbuf;
1864#endif
1865 }
1866}
1867
1868/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001869 * Return TRUE if buffer was changed and cannot be abandoned.
1870 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001873check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001875 int forceit = (flags & CCGD_FORCEIT);
1876#ifdef FEAT_AUTOCMD
1877 bufref_T bufref;
1878
1879 set_bufref(&bufref, buf);
1880#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001881
Bram Moolenaar071d4272004-06-13 20:20:40 +00001882 if ( !forceit
1883 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001884 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1885 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 {
1887#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1888 if ((p_confirm || cmdmod.confirm) && p_write)
1889 {
1890 buf_T *buf2;
1891 int count = 0;
1892
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001893 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001894 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001895 if (bufIsChanged(buf2)
1896 && (buf2->b_ffname != NULL
1897# ifdef FEAT_BROWSE
1898 || cmdmod.browse
1899# endif
1900 ))
1901 ++count;
1902# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001903 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 /* Autocommand deleted buffer, oops! It's not changed now. */
1905 return FALSE;
1906# endif
1907 dialog_changed(buf, count > 1);
1908# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001909 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 /* Autocommand deleted buffer, oops! It's not changed now. */
1911 return FALSE;
1912# endif
1913 return bufIsChanged(buf);
1914 }
1915#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001916 if (flags & CCGD_EXCMD)
1917 EMSG(_(e_nowrtmsg));
1918 else
1919 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 return TRUE;
1921 }
1922 return FALSE;
1923}
1924
1925#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1926
1927#if defined(FEAT_BROWSE) || defined(PROTO)
1928/*
1929 * When wanting to write a file without a file name, ask the user for a name.
1930 */
1931 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001932browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001933{
1934 if (buf->b_fname == NULL)
1935 {
1936 char_u *fname;
1937
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001938 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1939 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 if (fname != NULL)
1941 {
1942 if (setfname(buf, fname, NULL, TRUE) == OK)
1943 buf->b_flags |= BF_NOTEDITED;
1944 vim_free(fname);
1945 }
1946 }
1947}
1948#endif
1949
1950/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001951 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 * Must check 'write' option first!
1953 */
1954 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001955dialog_changed(
1956 buf_T *buf,
1957 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001959 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960 int ret;
1961 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001962 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001964 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 (buf->b_fname != NULL) ?
1966 buf->b_fname : (char_u *)_("Untitled"));
1967 if (checkall)
1968 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1969 else
1970 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1971
Bram Moolenaar8218f602012-04-25 17:32:18 +02001972 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1973 * function. */
1974 ea.append = ea.forceit = FALSE;
1975
Bram Moolenaar071d4272004-06-13 20:20:40 +00001976 if (ret == VIM_YES)
1977 {
1978#ifdef FEAT_BROWSE
1979 /* May get file name, when there is none */
1980 browse_save_fname(buf);
1981#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001982 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1983 buf->b_fname, buf->b_ffname, FALSE) == OK)
1984 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 (void)buf_write_all(buf, FALSE);
1986 }
1987 else if (ret == VIM_NO)
1988 {
1989 unchanged(buf, TRUE);
1990 }
1991 else if (ret == VIM_ALL)
1992 {
1993 /*
1994 * Write all modified files that can be written.
1995 * Skip readonly buffers, these need to be confirmed
1996 * individually.
1997 */
Bram Moolenaar29323592016-07-24 22:04:11 +02001998 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 {
2000 if (bufIsChanged(buf2)
2001 && (buf2->b_ffname != NULL
2002#ifdef FEAT_BROWSE
2003 || cmdmod.browse
2004#endif
2005 )
2006 && !buf2->b_p_ro)
2007 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002008#ifdef FEAT_AUTOCMD
2009 bufref_T bufref;
2010
2011 set_bufref(&bufref, buf2);
2012#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013#ifdef FEAT_BROWSE
2014 /* May get file name, when there is none */
2015 browse_save_fname(buf2);
2016#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02002017 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
2018 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
2019 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020 (void)buf_write_all(buf2, FALSE);
2021#ifdef FEAT_AUTOCMD
2022 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002023 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024 buf2 = firstbuf;
2025#endif
2026 }
2027 }
2028 }
2029 else if (ret == VIM_DISCARDALL)
2030 {
2031 /*
2032 * mark all buffers as unchanged
2033 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002034 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035 unchanged(buf2, TRUE);
2036 }
2037}
2038#endif
2039
2040/*
2041 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2042 * hidden, autowriting it or unloading it.
2043 */
2044 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002045can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046{
2047 return ( P_HID(buf)
2048 || !bufIsChanged(buf)
2049 || buf->b_nwindows > 1
2050 || autowrite(buf, forceit) == OK
2051 || forceit);
2052}
2053
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002054static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002055
2056/*
2057 * Add a buffer number to "bufnrs", unless it's already there.
2058 */
2059 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002060add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002061{
2062 int i;
2063
2064 for (i = 0; i < *bufnump; ++i)
2065 if (bufnrs[i] == nr)
2066 return;
2067 bufnrs[*bufnump] = nr;
2068 *bufnump = *bufnump + 1;
2069}
2070
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071/*
2072 * Return TRUE if any buffer was changed and cannot be abandoned.
2073 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002074 * When "unload" is true the current buffer is unloaded instead of making it
2075 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076 */
2077 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002078check_changed_any(
2079 int hidden, /* Only check hidden buffers */
2080 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002082 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083 buf_T *buf;
2084 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002085 int i;
2086 int bufnum = 0;
2087 int bufcount = 0;
2088 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002089#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002090 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 win_T *wp;
2092#endif
2093
Bram Moolenaar29323592016-07-24 22:04:11 +02002094 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002095 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002097 if (bufcount == 0)
2098 return FALSE;
2099
2100 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2101 if (bufnrs == NULL)
2102 return FALSE;
2103
2104 /* curbuf */
2105 bufnrs[bufnum++] = curbuf->b_fnum;
2106#ifdef FEAT_WINDOWS
2107 /* buf in curtab */
2108 FOR_ALL_WINDOWS(wp)
2109 if (wp->w_buffer != curbuf)
2110 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2111
2112 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002113 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002114 if (tp != curtab)
2115 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2116 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2117#endif
2118 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002119 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002120 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2121
2122 for (i = 0; i < bufnum; ++i)
2123 {
2124 buf = buflist_findnr(bufnrs[i]);
2125 if (buf == NULL)
2126 continue;
2127 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2128 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002129 bufref_T bufref;
2130
2131 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002132 /* Try auto-writing the buffer. If this fails but the buffer no
2133 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002134 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2135 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002136 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002137 break; /* didn't save - still changes */
2138 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139 }
2140
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002141 if (i >= bufnum)
2142 goto theend;
2143
2144 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 exiting = FALSE;
2146#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2147 /*
2148 * When ":confirm" used, don't give an error message.
2149 */
2150 if (!(p_confirm || cmdmod.confirm))
2151#endif
2152 {
2153 /* There must be a wait_return for this message, do_buffer()
2154 * may cause a redraw. But wait_return() is a no-op when vgetc()
2155 * is busy (Quit used from window menu), then make sure we don't
2156 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002157 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002158 {
2159 msg_row = cmdline_row;
2160 msg_col = 0;
2161 msg_didout = FALSE;
2162 }
2163 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002164 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 {
2166 save = no_wait_return;
2167 no_wait_return = FALSE;
2168 wait_return(FALSE);
2169 no_wait_return = save;
2170 }
2171 }
2172
2173#ifdef FEAT_WINDOWS
2174 /* Try to find a window that contains the buffer. */
2175 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002176 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002177 if (wp->w_buffer == buf)
2178 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002179# ifdef FEAT_AUTOCMD
2180 bufref_T bufref;
2181
2182 set_bufref(&bufref, buf);
2183# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002184 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185# ifdef FEAT_AUTOCMD
2186 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002187 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002188 {
2189 goto theend;
2190 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002192 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002194buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195#endif
2196
2197 /* Open the changed buffer in the current window. */
2198 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002199 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002201theend:
2202 vim_free(bufnrs);
2203 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204}
2205
2206/*
2207 * return FAIL if there is no file name, OK if there is one
2208 * give error message for FAIL
2209 */
2210 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002211check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212{
2213 if (curbuf->b_ffname == NULL)
2214 {
2215 EMSG(_(e_noname));
2216 return FAIL;
2217 }
2218 return OK;
2219}
2220
2221/*
2222 * flush the contents of a buffer, unless it has no file name
2223 *
2224 * return FAIL for failure, OK otherwise
2225 */
2226 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002227buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002228{
2229 int retval;
2230#ifdef FEAT_AUTOCMD
2231 buf_T *old_curbuf = curbuf;
2232#endif
2233
2234 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2235 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2236 FALSE, forceit, TRUE, FALSE));
2237#ifdef FEAT_AUTOCMD
2238 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002239 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01002240 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243#endif
2244 return retval;
2245}
2246
2247/*
2248 * Code to handle the argument list.
2249 */
2250
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002251static char_u *do_one_arg(char_u *str);
2252static int do_arglist(char_u *str, int what, int after);
2253static void alist_check_arg_idx(void);
2254static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002255#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002256static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002257#endif
2258#define AL_SET 1
2259#define AL_ADD 2
2260#define AL_DEL 3
2261
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002263 * Isolate one argument, taking backticks.
2264 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002265 * Return a pointer to the start of the next argument.
2266 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002267 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002268do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269{
2270 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 int inbacktick;
2272
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 inbacktick = FALSE;
2274 for (p = str; *str; ++str)
2275 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002276 /* When the backslash is used for escaping the special meaning of a
2277 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 if (rem_backslash(str))
2279 {
2280 *p++ = *str++;
2281 *p++ = *str;
2282 }
2283 else
2284 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002285 /* An item ends at a space not in backticks */
2286 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002288 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002290 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291 }
2292 }
2293 str = skipwhite(str);
2294 *p = NUL;
2295
2296 return str;
2297}
2298
Bram Moolenaar86b68352004-12-27 21:59:20 +00002299/*
2300 * Separate the arguments in "str" and return a list of pointers in the
2301 * growarray "gap".
2302 */
2303 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002304get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002305{
2306 ga_init2(gap, (int)sizeof(char_u *), 20);
2307 while (*str != NUL)
2308 {
2309 if (ga_grow(gap, 1) == FAIL)
2310 {
2311 ga_clear(gap);
2312 return FAIL;
2313 }
2314 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2315
2316 /* Isolate one argument, change it in-place, put a NUL after it. */
2317 str = do_one_arg(str);
2318 }
2319 return OK;
2320}
2321
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002322#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002323/*
2324 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002325 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002326 * Return FAIL or OK.
2327 */
2328 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002329get_arglist_exp(
2330 char_u *str,
2331 int *fcountp,
2332 char_u ***fnamesp,
2333 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002334{
2335 garray_T ga;
2336 int i;
2337
2338 if (get_arglist(&ga, str) == FAIL)
2339 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002340 if (wig == TRUE)
2341 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2342 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2343 else
2344 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2345 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2346
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002347 ga_clear(&ga);
2348 return i;
2349}
2350#endif
2351
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2353/*
2354 * Redefine the argument list.
2355 */
2356 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002357set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358{
2359 do_arglist(str, AL_SET, 0);
2360}
2361#endif
2362
2363/*
2364 * "what" == AL_SET: Redefine the argument list to 'str'.
2365 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2366 * "what" == AL_DEL: remove files in 'str' from the argument list.
2367 *
2368 * Return FAIL for failure, OK otherwise.
2369 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002371do_arglist(
2372 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002373 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002374 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375{
2376 garray_T new_ga;
2377 int exp_count;
2378 char_u **exp_files;
2379 int i;
2380#ifdef FEAT_LISTCMDS
2381 char_u *p;
2382 int match;
2383#endif
2384
2385 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002386 * Set default argument for ":argadd" command.
2387 */
2388 if (what == AL_ADD && *str == NUL)
2389 {
2390 if (curbuf->b_ffname == NULL)
2391 return FAIL;
2392 str = curbuf->b_fname;
2393 }
2394
2395 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396 * Collect all file name arguments in "new_ga".
2397 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002398 if (get_arglist(&new_ga, str) == FAIL)
2399 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400
2401#ifdef FEAT_LISTCMDS
2402 if (what == AL_DEL)
2403 {
2404 regmatch_T regmatch;
2405 int didone;
2406
2407 /*
2408 * Delete the items: use each item as a regexp and find a match in the
2409 * argument list.
2410 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002411 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2413 {
2414 p = ((char_u **)new_ga.ga_data)[i];
2415 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2416 if (p == NULL)
2417 break;
2418 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2419 if (regmatch.regprog == NULL)
2420 {
2421 vim_free(p);
2422 break;
2423 }
2424
2425 didone = FALSE;
2426 for (match = 0; match < ARGCOUNT; ++match)
2427 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2428 (colnr_T)0))
2429 {
2430 didone = TRUE;
2431 vim_free(ARGLIST[match].ae_fname);
2432 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2433 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2434 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002435 if (curwin->w_arg_idx > match)
2436 --curwin->w_arg_idx;
2437 --match;
2438 }
2439
Bram Moolenaar473de612013-06-08 18:19:48 +02002440 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441 vim_free(p);
2442 if (!didone)
2443 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2444 }
2445 ga_clear(&new_ga);
2446 }
2447 else
2448#endif
2449 {
2450 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2451 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2452 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002453 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 {
2455 EMSG(_(e_nomatch));
2456 return FAIL;
2457 }
2458
2459#ifdef FEAT_LISTCMDS
2460 if (what == AL_ADD)
2461 {
2462 (void)alist_add_list(exp_count, exp_files, after);
2463 vim_free(exp_files);
2464 }
2465 else /* what == AL_SET */
2466#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002467 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 }
2469
2470 alist_check_arg_idx();
2471
2472 return OK;
2473}
2474
2475/*
2476 * Check the validity of the arg_idx for each other window.
2477 */
2478 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002479alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480{
2481#ifdef FEAT_WINDOWS
2482 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002483 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484
Bram Moolenaarf740b292006-02-16 22:11:02 +00002485 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486 if (win->w_alist == curwin->w_alist)
2487 check_arg_idx(win);
2488#else
2489 check_arg_idx(curwin);
2490#endif
2491}
2492
2493/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002494 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002495 * index.
2496 */
2497 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002498editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002499{
2500 return !(win->w_arg_idx >= WARGCOUNT(win)
2501 || (win->w_buffer->b_fnum
2502 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2503 && (win->w_buffer->b_ffname == NULL
2504 || !(fullpathcmp(
2505 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2506 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2507}
2508
2509/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510 * Check if window "win" is editing the w_arg_idx file in its argument list.
2511 */
2512 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002513check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002515 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 {
2517 /* We are not editing the current entry in the argument list.
2518 * Set "arg_had_last" if we are editing the last one. */
2519 win->w_arg_idx_invalid = TRUE;
2520 if (win->w_arg_idx != WARGCOUNT(win) - 1
2521 && arg_had_last == FALSE
2522#ifdef FEAT_WINDOWS
2523 && ALIST(win) == &global_alist
2524#endif
2525 && GARGCOUNT > 0
2526 && win->w_arg_idx < GARGCOUNT
2527 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2528 || (win->w_buffer->b_ffname != NULL
2529 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2530 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2531 arg_had_last = TRUE;
2532 }
2533 else
2534 {
2535 /* We are editing the current entry in the argument list.
2536 * Set "arg_had_last" if it's also the last one */
2537 win->w_arg_idx_invalid = FALSE;
2538 if (win->w_arg_idx == WARGCOUNT(win) - 1
2539#ifdef FEAT_WINDOWS
2540 && win->w_alist == &global_alist
2541#endif
2542 )
2543 arg_had_last = TRUE;
2544 }
2545}
2546
2547/*
2548 * ":args", ":argslocal" and ":argsglobal".
2549 */
2550 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002551ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552{
2553 int i;
2554
2555 if (eap->cmdidx != CMD_args)
2556 {
2557#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2558 alist_unlink(ALIST(curwin));
2559 if (eap->cmdidx == CMD_argglobal)
2560 ALIST(curwin) = &global_alist;
2561 else /* eap->cmdidx == CMD_arglocal */
2562 alist_new();
2563#else
2564 ex_ni(eap);
2565 return;
2566#endif
2567 }
2568
2569 if (!ends_excmd(*eap->arg))
2570 {
2571 /*
2572 * ":args file ..": define new argument list, handle like ":next"
2573 * Also for ":argslocal file .." and ":argsglobal file ..".
2574 */
2575 ex_next(eap);
2576 }
2577 else
2578#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2579 if (eap->cmdidx == CMD_args)
2580#endif
2581 {
2582 /*
2583 * ":args": list arguments.
2584 */
2585 if (ARGCOUNT > 0)
2586 {
2587 /* Overwrite the command, for a short list there is no scrolling
2588 * required and no wait_return(). */
2589 gotocmdline(TRUE);
2590 for (i = 0; i < ARGCOUNT; ++i)
2591 {
2592 if (i == curwin->w_arg_idx)
2593 msg_putchar('[');
2594 msg_outtrans(alist_name(&ARGLIST[i]));
2595 if (i == curwin->w_arg_idx)
2596 msg_putchar(']');
2597 msg_putchar(' ');
2598 }
2599 }
2600 }
2601#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2602 else if (eap->cmdidx == CMD_arglocal)
2603 {
2604 garray_T *gap = &curwin->w_alist->al_ga;
2605
2606 /*
2607 * ":argslocal": make a local copy of the global argument list.
2608 */
2609 if (ga_grow(gap, GARGCOUNT) == OK)
2610 for (i = 0; i < GARGCOUNT; ++i)
2611 if (GARGLIST[i].ae_fname != NULL)
2612 {
2613 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2614 vim_strsave(GARGLIST[i].ae_fname);
2615 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2616 GARGLIST[i].ae_fnum;
2617 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 }
2619 }
2620#endif
2621}
2622
2623/*
2624 * ":previous", ":sprevious", ":Next" and ":sNext".
2625 */
2626 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002627ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628{
2629 /* If past the last one already, go to the last one. */
2630 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2631 do_argfile(eap, ARGCOUNT - 1);
2632 else
2633 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2634}
2635
2636/*
2637 * ":rewind", ":first", ":sfirst" and ":srewind".
2638 */
2639 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002640ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641{
2642 do_argfile(eap, 0);
2643}
2644
2645/*
2646 * ":last" and ":slast".
2647 */
2648 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002649ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650{
2651 do_argfile(eap, ARGCOUNT - 1);
2652}
2653
2654/*
2655 * ":argument" and ":sargument".
2656 */
2657 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002658ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002659{
2660 int i;
2661
2662 if (eap->addr_count > 0)
2663 i = eap->line2 - 1;
2664 else
2665 i = curwin->w_arg_idx;
2666 do_argfile(eap, i);
2667}
2668
2669/*
2670 * Edit file "argn" of the argument lists.
2671 */
2672 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002673do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002674{
2675 int other;
2676 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002677 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002678
2679 if (argn < 0 || argn >= ARGCOUNT)
2680 {
2681 if (ARGCOUNT <= 1)
2682 EMSG(_("E163: There is only one file to edit"));
2683 else if (argn < 0)
2684 EMSG(_("E164: Cannot go before first file"));
2685 else
2686 EMSG(_("E165: Cannot go beyond last file"));
2687 }
2688 else
2689 {
2690 setpcmark();
2691#ifdef FEAT_GUI
2692 need_mouse_correct = TRUE;
2693#endif
2694
2695#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002696 /* split window or create new tab page first */
2697 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 {
2699 if (win_split(0, 0) == FAIL)
2700 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002701 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002702 }
2703 else
2704#endif
2705 {
2706 /*
2707 * if 'hidden' set, only check for changed file when re-editing
2708 * the same buffer
2709 */
2710 other = TRUE;
2711 if (P_HID(curbuf))
2712 {
2713 p = fix_fname(alist_name(&ARGLIST[argn]));
2714 other = otherfile(p);
2715 vim_free(p);
2716 }
2717 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002718 && check_changed(curbuf, CCGD_AW
2719 | (other ? 0 : CCGD_MULTWIN)
2720 | (eap->forceit ? CCGD_FORCEIT : 0)
2721 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002722 return;
2723 }
2724
2725 curwin->w_arg_idx = argn;
2726 if (argn == ARGCOUNT - 1
2727#ifdef FEAT_WINDOWS
2728 && curwin->w_alist == &global_alist
2729#endif
2730 )
2731 arg_had_last = TRUE;
2732
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002733 /* Edit the file; always use the last known line number.
2734 * When it fails (e.g. Abort for already edited file) restore the
2735 * argument index. */
2736 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002737 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002738 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2739 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002740 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002742 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743 setmark('\'');
2744 }
2745}
2746
2747/*
2748 * ":next", and commands that behave like it.
2749 */
2750 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002751ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002752{
2753 int i;
2754
2755 /*
2756 * check for changed buffer now, if this fails the argument list is not
2757 * redefined.
2758 */
2759 if ( P_HID(curbuf)
2760 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002761 || !check_changed(curbuf, CCGD_AW
2762 | (eap->forceit ? CCGD_FORCEIT : 0)
2763 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 {
2765 if (*eap->arg != NUL) /* redefine file list */
2766 {
2767 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2768 return;
2769 i = 0;
2770 }
2771 else
2772 i = curwin->w_arg_idx + (int)eap->line2;
2773 do_argfile(eap, i);
2774 }
2775}
2776
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002777#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002778/*
2779 * ":argedit"
2780 */
2781 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002782ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783{
2784 int fnum;
2785 int i;
2786 char_u *s;
2787
2788 /* Add the argument to the buffer list and get the buffer number. */
2789 fnum = buflist_add(eap->arg, BLN_LISTED);
2790
2791 /* Check if this argument is already in the argument list. */
2792 for (i = 0; i < ARGCOUNT; ++i)
2793 if (ARGLIST[i].ae_fnum == fnum)
2794 break;
2795 if (i == ARGCOUNT)
2796 {
2797 /* Can't find it, add it to the argument list. */
2798 s = vim_strsave(eap->arg);
2799 if (s == NULL)
2800 return;
2801 i = alist_add_list(1, &s,
2802 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2803 if (i < 0)
2804 return;
2805 curwin->w_arg_idx = i;
2806 }
2807
2808 alist_check_arg_idx();
2809
2810 /* Edit the argument. */
2811 do_argfile(eap, i);
2812}
2813
2814/*
2815 * ":argadd"
2816 */
2817 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002818ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819{
2820 do_arglist(eap->arg, AL_ADD,
2821 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2822#ifdef FEAT_TITLE
2823 maketitle();
2824#endif
2825}
2826
2827/*
2828 * ":argdelete"
2829 */
2830 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002831ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002832{
2833 int i;
2834 int n;
2835
2836 if (eap->addr_count > 0)
2837 {
2838 /* ":1,4argdel": Delete all arguments in the range. */
2839 if (eap->line2 > ARGCOUNT)
2840 eap->line2 = ARGCOUNT;
2841 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002842 if (*eap->arg != NUL)
2843 /* Can't have both a range and an argument. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 EMSG(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002845 else if (n <= 0)
2846 {
2847 /* Don't give an error for ":%argdel" if the list is empty. */
2848 if (eap->line1 != 1 || eap->line2 != 0)
2849 EMSG(_(e_invrange));
2850 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851 else
2852 {
2853 for (i = eap->line1; i <= eap->line2; ++i)
2854 vim_free(ARGLIST[i - 1].ae_fname);
2855 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2856 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2857 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002858 if (curwin->w_arg_idx >= eap->line2)
2859 curwin->w_arg_idx -= n;
2860 else if (curwin->w_arg_idx > eap->line1)
2861 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002862 if (ARGCOUNT == 0)
2863 curwin->w_arg_idx = 0;
2864 else if (curwin->w_arg_idx >= ARGCOUNT)
2865 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866 }
2867 }
2868 else if (*eap->arg == NUL)
2869 EMSG(_(e_argreq));
2870 else
2871 do_arglist(eap->arg, AL_DEL, 0);
2872#ifdef FEAT_TITLE
2873 maketitle();
2874#endif
2875}
2876
2877/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002878 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002879 */
2880 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002881ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882{
2883 int i;
2884#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002885 win_T *wp;
2886 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002888 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002889 int next_fnum = 0;
2890#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2891 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002893 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002894#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002895 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002896 int qf_idx;
2897#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002898
2899#ifndef FEAT_WINDOWS
2900 if (eap->cmdidx == CMD_windo)
2901 {
2902 ex_ni(eap);
2903 return;
2904 }
2905#endif
2906
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002907#ifndef FEAT_QUICKFIX
2908 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2909 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2910 {
2911 ex_ni(eap);
2912 return;
2913 }
2914#endif
2915
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002917 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002918 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2919 * great speed improvement. */
2920 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002922#ifdef FEAT_CLIPBOARD
2923 start_global_changes();
2924#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002925
2926 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002927 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002929 || !check_changed(curbuf, CCGD_AW
2930 | (eap->forceit ? CCGD_FORCEIT : 0)
2931 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002934 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002935#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002936 wp = firstwin;
2937 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002939 switch (eap->cmdidx)
2940 {
2941#ifdef FEAT_WINDOWS
2942 case CMD_windo:
2943 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2944 i++;
2945 break;
2946 case CMD_tabdo:
2947 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2948 i++;
2949 break;
2950#endif
2951 case CMD_argdo:
2952 i = eap->line1 - 1;
2953 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002954 default:
2955 break;
2956 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957 /* set pcmark now */
2958 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002959 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002960 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002961 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002962 || !buf->b_p_bl); buf = buf->b_next)
2963 if (buf->b_fnum > eap->line2)
2964 {
2965 buf = NULL;
2966 break;
2967 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002968 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002969 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002970 }
2971#ifdef FEAT_QUICKFIX
2972 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2973 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2974 {
2975 qf_size = qf_get_size(eap);
2976 if (qf_size <= 0 || eap->line1 > qf_size)
2977 buf = NULL;
2978 else
2979 {
2980 ex_cc(eap);
2981
2982 buf = curbuf;
2983 i = eap->line1 - 1;
2984 if (eap->addr_count <= 0)
2985 /* default is all the quickfix/location list entries */
2986 eap->line2 = qf_size;
2987 }
2988 }
2989#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002990 else
2991 setpcmark();
2992 listcmd_busy = TRUE; /* avoids setting pcmark below */
2993
Bram Moolenaare25bb902015-02-27 20:33:37 +01002994 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995 {
2996 if (eap->cmdidx == CMD_argdo)
2997 {
2998 /* go to argument "i" */
2999 if (i == ARGCOUNT)
3000 break;
3001 /* Don't call do_argfile() when already there, it will try
3002 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003003 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003004 {
3005 /* Clear 'shm' to avoid that the file message overwrites
3006 * any output from the command. */
3007 p_shm_save = vim_strsave(p_shm);
3008 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003010 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3011 vim_free(p_shm_save);
3012 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003013 if (curwin->w_arg_idx != i)
3014 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 }
3016#ifdef FEAT_WINDOWS
3017 else if (eap->cmdidx == CMD_windo)
3018 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003019 /* go to window "wp" */
3020 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003022 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00003023 if (curwin != wp)
3024 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003025 wp = curwin->w_next;
3026 }
3027 else if (eap->cmdidx == CMD_tabdo)
3028 {
3029 /* go to window "tp" */
3030 if (!valid_tabpage(tp))
3031 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003032 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003033 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 }
3035#endif
3036 else if (eap->cmdidx == CMD_bufdo)
3037 {
3038 /* Remember the number of the next listed buffer, in case
3039 * ":bwipe" is used or autocommands do something strange. */
3040 next_fnum = -1;
3041 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3042 if (buf->b_p_bl)
3043 {
3044 next_fnum = buf->b_fnum;
3045 break;
3046 }
3047 }
3048
Bram Moolenaara162bc52015-01-07 16:54:21 +01003049 ++i;
3050
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051 /* execute the command */
3052 do_cmdline(eap->arg, eap->getline, eap->cookie,
3053 DOCMD_VERBOSE + DOCMD_NOWAIT);
3054
3055 if (eap->cmdidx == CMD_bufdo)
3056 {
3057 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003058 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003059 break;
3060 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003061 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 if (buf->b_fnum == next_fnum)
3063 break;
3064 if (buf == NULL)
3065 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003066
3067 /* Go to the next buffer. Clear 'shm' to avoid that the file
3068 * message overwrites any output from the command. */
3069 p_shm_save = vim_strsave(p_shm);
3070 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003071 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003072 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3073 vim_free(p_shm_save);
3074
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003075 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 if (curbuf->b_fnum != next_fnum)
3077 break;
3078 }
3079
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003080#ifdef FEAT_QUICKFIX
3081 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3082 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3083 {
3084 if (i >= qf_size || i >= eap->line2)
3085 break;
3086
3087 qf_idx = qf_get_cur_idx(eap);
3088
3089 ex_cnext(eap);
3090
3091 /* If jumping to the next quickfix entry fails, quit here */
3092 if (qf_get_cur_idx(eap) == qf_idx)
3093 break;
3094 }
3095#endif
3096
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097 if (eap->cmdidx == CMD_windo)
3098 {
3099 validate_cursor(); /* cursor may have moved */
3100#ifdef FEAT_SCROLLBIND
3101 /* required when 'scrollbind' has been set */
3102 if (curwin->w_p_scb)
3103 do_check_scrollbind(TRUE);
3104#endif
3105 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003106
3107#ifdef FEAT_WINDOWS
3108 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3109 if (i+1 > eap->line2)
3110 break;
3111#endif
3112 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3113 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003114 }
3115 listcmd_busy = FALSE;
3116 }
3117
3118#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003119 if (save_ei != NULL)
3120 {
3121 au_event_restore(save_ei);
3122 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3123 curbuf->b_fname, TRUE, curbuf);
3124 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003125#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003126#ifdef FEAT_CLIPBOARD
3127 end_global_changes();
3128#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129}
3130
3131/*
3132 * Add files[count] to the arglist of the current window after arg "after".
3133 * The file names in files[count] must have been allocated and are taken over.
3134 * Files[] itself is not taken over.
3135 * Returns index of first added argument. Returns -1 when failed (out of mem).
3136 */
3137 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003138alist_add_list(
3139 int count,
3140 char_u **files,
3141 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142{
3143 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003144 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145
3146 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3147 {
3148 if (after < 0)
3149 after = 0;
3150 if (after > ARGCOUNT)
3151 after = ARGCOUNT;
3152 if (after < ARGCOUNT)
3153 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3154 (ARGCOUNT - after) * sizeof(aentry_T));
3155 for (i = 0; i < count; ++i)
3156 {
3157 ARGLIST[after + i].ae_fname = files[i];
3158 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3159 }
3160 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003161 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3162 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163 return after;
3164 }
3165
3166 for (i = 0; i < count; ++i)
3167 vim_free(files[i]);
3168 return -1;
3169}
3170
3171#endif /* FEAT_LISTCMDS */
3172
3173#ifdef FEAT_EVAL
3174/*
3175 * ":compiler[!] {name}"
3176 */
3177 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003178ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179{
3180 char_u *buf;
3181 char_u *old_cur_comp = NULL;
3182 char_u *p;
3183
3184 if (*eap->arg == NUL)
3185 {
3186 /* List all compiler scripts. */
3187 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3188 /* ) keep the indenter happy... */
3189 }
3190 else
3191 {
3192 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3193 if (buf != NULL)
3194 {
3195 if (eap->forceit)
3196 {
3197 /* ":compiler! {name}" sets global options */
3198 do_cmdline_cmd((char_u *)
3199 "command -nargs=* CompilerSet set <args>");
3200 }
3201 else
3202 {
3203 /* ":compiler! {name}" sets local options.
3204 * To remain backwards compatible "current_compiler" is always
3205 * used. A user's compiler plugin may set it, the distributed
3206 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003207 * "b:current_compiler" and restore "current_compiler".
3208 * Explicitly prepend "g:" to make it work in a function. */
3209 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 if (old_cur_comp != NULL)
3211 old_cur_comp = vim_strsave(old_cur_comp);
3212 do_cmdline_cmd((char_u *)
3213 "command -nargs=* CompilerSet setlocal <args>");
3214 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003215 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003216 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217
3218 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003219 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3221 vim_free(buf);
3222
3223 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3224
3225 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003226 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 if (p != NULL)
3228 set_internal_string_var((char_u *)"b:current_compiler", p);
3229
3230 /* Restore "current_compiler" for ":compiler {name}". */
3231 if (!eap->forceit)
3232 {
3233 if (old_cur_comp != NULL)
3234 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003235 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003236 old_cur_comp);
3237 vim_free(old_cur_comp);
3238 }
3239 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003240 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 }
3242 }
3243 }
3244}
3245#endif
3246
3247/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003248 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003249 */
3250 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003251ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003253 char_u *arg = eap->arg;
3254 char_u *p = skiptowhite(arg);
3255 int len = (int)(p - arg);
3256 int flags = eap->forceit ? DIP_ALL : 0;
3257
3258 if (STRNCMP(arg, "START", len) == 0)
3259 {
3260 flags += DIP_START + DIP_NORTP;
3261 arg = skipwhite(arg + len);
3262 }
3263 else if (STRNCMP(arg, "OPT", len) == 0)
3264 {
3265 flags += DIP_OPT + DIP_NORTP;
3266 arg = skipwhite(arg + len);
3267 }
3268 else if (STRNCMP(arg, "PACK", len) == 0)
3269 {
3270 flags += DIP_START + DIP_OPT + DIP_NORTP;
3271 arg = skipwhite(arg + len);
3272 }
3273 else if (STRNCMP(arg, "ALL", len) == 0)
3274 {
3275 flags += DIP_START + DIP_OPT;
3276 arg = skipwhite(arg + len);
3277 }
3278
3279 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003280}
3281
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003283source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003284{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003285 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286}
3287
3288/*
3289 * Source the file "name" from all directories in 'runtimepath'.
3290 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003291 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003292 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293 * return FAIL when no file could be sourced, OK otherwise.
3294 */
3295 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003296source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003297{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003298 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003299}
3300
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003301/*
3302 * Find the file "name" in all directories in "path" and invoke
3303 * "callback(fname, cookie)".
3304 * "name" can contain wildcards.
3305 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3306 * When "flags" has DIP_DIR: find directories instead of files.
3307 * When "flags" has DIP_ERR: give an error message if there is no match.
3308 *
3309 * return FAIL when no file could be sourced, OK otherwise.
3310 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003311 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003312do_in_path(
3313 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003314 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003315 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003316 void (*callback)(char_u *fname, void *ck),
3317 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318{
3319 char_u *rtp;
3320 char_u *np;
3321 char_u *buf;
3322 char_u *rtp_copy;
3323 char_u *tail;
3324 int num_files;
3325 char_u **files;
3326 int i;
3327 int did_one = FALSE;
3328#ifdef AMIGA
3329 struct Process *proc = (struct Process *)FindTask(0L);
3330 APTR save_winptr = proc->pr_WindowPtr;
3331
3332 /* Avoid a requester here for a volume that doesn't exist. */
3333 proc->pr_WindowPtr = (APTR)-1L;
3334#endif
3335
3336 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3337 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003338 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 buf = alloc(MAXPATHL);
3340 if (buf != NULL && rtp_copy != NULL)
3341 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003342 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003343 {
3344 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003345 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003346 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003347 verbose_leave();
3348 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003349
Bram Moolenaar071d4272004-06-13 20:20:40 +00003350 /* Loop over all entries in 'runtimepath'. */
3351 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003352 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003353 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003354 size_t buflen;
3355
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 /* Copy the path from 'runtimepath' to buf[]. */
3357 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003358 buflen = STRLEN(buf);
3359
3360 /* Skip after or non-after directories. */
3361 if (flags & (DIP_NOAFTER | DIP_AFTER))
3362 {
3363 int is_after = buflen >= 5
3364 && STRCMP(buf + buflen - 5, "after") == 0;
3365
3366 if ((is_after && (flags & DIP_NOAFTER))
3367 || (!is_after && (flags & DIP_AFTER)))
3368 continue;
3369 }
3370
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003371 if (name == NULL)
3372 {
3373 (*callback)(buf, (void *) &cookie);
3374 if (!did_one)
3375 did_one = (cookie == NULL);
3376 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003377 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 {
3379 add_pathsep(buf);
3380 tail = buf + STRLEN(buf);
3381
3382 /* Loop over all patterns in "name" */
3383 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003384 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003385 {
3386 /* Append the pattern from "name" to buf[]. */
3387 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3388 "\t ");
3389
3390 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003391 {
3392 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003393 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003394 verbose_leave();
3395 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396
3397 /* Expand wildcards, invoke the callback for each match. */
3398 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003399 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 {
3401 for (i = 0; i < num_files; ++i)
3402 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003403 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003405 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 break;
3407 }
3408 FreeWild(num_files, files);
3409 }
3410 }
3411 }
3412 }
3413 }
3414 vim_free(buf);
3415 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003416 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003417 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003418 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3419
3420 if (flags & DIP_ERR)
3421 EMSG3(_(e_dirnotf), basepath, name);
3422 else if (p_verbose > 0)
3423 {
3424 verbose_enter();
3425 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3426 verbose_leave();
3427 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003428 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003429
3430#ifdef AMIGA
3431 proc->pr_WindowPtr = save_winptr;
3432#endif
3433
3434 return did_one ? OK : FAIL;
3435}
3436
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003437/*
3438 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3439 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003440 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3441 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003442 * Returns OK when at least one match found, FAIL otherwise.
3443 *
3444 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3445 * passed by reference in this case, setting it to NULL indicates that callback
3446 * has done its job.
3447 */
3448 int
3449do_in_runtimepath(
3450 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003451 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003452 void (*callback)(char_u *fname, void *ck),
3453 void *cookie)
3454{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003455 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003456 char_u *s;
3457 int len;
3458 char *start_dir = "pack/*/start/*/%s";
3459 char *opt_dir = "pack/*/opt/*/%s";
3460
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003461 if ((flags & DIP_NORTP) == 0)
3462 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003463
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003464 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003465 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003466 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003467 s = alloc(len);
3468 if (s == NULL)
3469 return FAIL;
3470 vim_snprintf((char *)s, len, start_dir, name);
3471 done = do_in_path(p_pp, s, flags, callback, cookie);
3472 vim_free(s);
3473 }
3474
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003475 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003476 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003477 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003478 s = alloc(len);
3479 if (s == NULL)
3480 return FAIL;
3481 vim_snprintf((char *)s, len, opt_dir, name);
3482 done = do_in_path(p_pp, s, flags, callback, cookie);
3483 vim_free(s);
3484 }
3485
3486 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003487}
3488
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003489/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003490 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003491 */
3492 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003493source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003494{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003495 int num_files;
3496 char_u **files;
3497 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003498
Bram Moolenaarf3654822016-03-04 22:12:23 +01003499 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003500 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003501 for (i = 0; i < num_files; ++i)
3502 (void)do_source(files[i], FALSE, DOSO_NONE);
3503 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003504 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003505}
3506
Bram Moolenaar49b27322016-04-05 21:13:00 +02003507/* used for "cookie" of add_pack_plugin() */
3508static int APP_ADD_DIR;
3509static int APP_LOAD;
3510static int APP_BOTH;
3511
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003512 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003513add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003514{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003515 char_u *p4, *p3, *p2, *p1, *p;
3516 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003517 int c;
3518 char_u *new_rtp;
3519 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003520 size_t oldlen;
3521 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003522 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003523 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003524 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003525 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003526 char_u *buf = NULL;
3527 char_u *rtp_ffname;
3528 int match;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003529
Bram Moolenaar91715872016-03-03 17:13:03 +01003530 if (ffname == NULL)
3531 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003532 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003533 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003534 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003535 p4 = p3 = p2 = p1 = get_past_head(ffname);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01003536 for (p = p1; *p; MB_PTR_ADV(p))
Bram Moolenaarf3654822016-03-04 22:12:23 +01003537 if (vim_ispathsep_nocolon(*p))
3538 {
3539 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3540 }
3541
3542 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003543 * rtp/pack/name/start/name
3544 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003545 *
3546 * find the part up to "pack" in 'runtimepath' */
3547 c = *p4;
3548 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003549
3550 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3551 fname_len = STRLEN(ffname);
3552 insp = p_rtp;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003553 buf = alloc(MAXPATHL);
3554 if (buf == NULL)
3555 goto theend;
3556 while (*insp != NUL)
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003557 {
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003558 copy_option_part(&insp, buf, MAXPATHL, ",");
3559 add_pathsep(buf);
3560 rtp_ffname = fix_fname(buf);
3561 if (rtp_ffname == NULL)
3562 goto theend;
3563 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
3564 vim_free(rtp_ffname);
3565 if (match)
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003566 break;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003567 }
3568
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003569 if (*insp == NUL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003570 /* not found, append at the end */
3571 insp = p_rtp + STRLEN(p_rtp);
3572 else
Bram Moolenaarf3654822016-03-04 22:12:23 +01003573 /* append after the matching directory. */
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003574 --insp;
Bram Moolenaarf3654822016-03-04 22:12:23 +01003575 *p4 = c;
3576
Bram Moolenaara5702442016-05-24 19:37:29 +02003577 /* check if rtp/pack/name/start/name/after exists */
3578 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3579 if (afterdir != NULL && mch_isdir(afterdir))
3580 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3581
Bram Moolenaarb0550662016-05-31 21:37:36 +02003582 oldlen = STRLEN(p_rtp);
3583 addlen = STRLEN(ffname) + 1; /* add one for comma */
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003584 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1));
3585 /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003586 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003587 goto theend;
3588 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003589 mch_memmove(new_rtp, p_rtp, keep);
3590 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003591 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003592 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003593 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003594 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003595 if (afterlen > 0)
3596 {
3597 STRCAT(new_rtp, ",");
3598 STRCAT(new_rtp, afterdir);
3599 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003600 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3601 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003602 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003603 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003604
Bram Moolenaar49b27322016-04-05 21:13:00 +02003605 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003606 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003607 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003608 static char *ftpat = "%s/ftdetect/*.vim";
3609 int len;
3610 char_u *pat;
3611
3612 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3613 pat = alloc(len);
3614 if (pat == NULL)
3615 goto theend;
3616 vim_snprintf((char *)pat, len, plugpat, ffname);
3617 source_all_matches(pat);
3618
3619#ifdef FEAT_AUTOCMD
3620 {
3621 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3622
3623 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3624 * found when it loads. */
3625 if (cmd != NULL && eval_to_number(cmd) > 0)
3626 {
3627 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3628 vim_snprintf((char *)pat, len, ftpat, ffname);
3629 source_all_matches(pat);
3630 do_cmdline_cmd((char_u *)"augroup END");
3631 }
3632 vim_free(cmd);
3633 }
3634#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003635 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003636 }
3637
3638theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003639 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003640 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003641}
3642
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003643/*
3644 * Add all packages in the "start" directory to 'runtimepath'.
3645 */
3646 void
3647add_pack_start_dirs(void)
3648{
3649 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3650 add_pack_plugin, &APP_ADD_DIR);
3651}
3652
3653/*
3654 * Load plugins from all packages in the "start" directory.
3655 */
3656 void
3657load_start_packages(void)
3658{
3659 did_source_packages = TRUE;
3660 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3661 add_pack_plugin, &APP_LOAD);
3662}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003663
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003664/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003665 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003666 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003667 */
3668 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003669ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003670{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003671 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003672 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02003673 /* First do a round to add all directories to 'runtimepath', then load
3674 * the plugins. This allows for plugins to use an autoload directory
3675 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003676 add_pack_start_dirs();
3677 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003678 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003679}
3680
3681/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003682 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003683 */
3684 void
3685ex_packadd(exarg_T *eap)
3686{
3687 static char *plugpat = "pack/*/opt/%s";
3688 int len;
3689 char *pat;
3690
3691 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3692 pat = (char *)alloc(len);
3693 if (pat == NULL)
3694 return;
3695 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003696 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003697 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003698 vim_free(pat);
3699}
3700
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3702/*
3703 * ":options"
3704 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003706ex_options(
3707 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708{
3709 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3710}
3711#endif
3712
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003713#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3714
3715# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3716/*
3717 * Detect Python 3 or 2, and initialize 'pyxversion'.
3718 */
3719 void
3720init_pyxversion(void)
3721{
3722 if (p_pyx == 0)
3723 {
3724 if (python3_enabled(FALSE))
3725 p_pyx = 3;
3726 else if (python_enabled(FALSE))
3727 p_pyx = 2;
3728 }
3729}
3730# endif
3731
3732/*
3733 * Does a file contain one of the following strings at the beginning of any
3734 * line?
3735 * "#!(any string)python2" => returns 2
3736 * "#!(any string)python3" => returns 3
3737 * "# requires python 2.x" => returns 2
3738 * "# requires python 3.x" => returns 3
3739 * otherwise return 0.
3740 */
3741 static int
3742requires_py_version(char_u *filename)
3743{
3744 FILE *file;
3745 int requires_py_version = 0;
3746 int i, lines;
3747
3748 lines = (int)p_mls;
3749 if (lines < 0)
3750 lines = 5;
3751
3752 file = mch_fopen((char *)filename, "r");
3753 if (file != NULL)
3754 {
3755 for (i = 0; i < lines; i++)
3756 {
3757 if (vim_fgets(IObuff, IOSIZE, file))
3758 break;
3759 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3760 {
3761 /* Check shebang. */
3762 if (strstr((char *)IObuff + 2, "python2") != NULL)
3763 {
3764 requires_py_version = 2;
3765 break;
3766 }
3767 if (strstr((char *)IObuff + 2, "python3") != NULL)
3768 {
3769 requires_py_version = 3;
3770 break;
3771 }
3772 }
3773 IObuff[21] = '\0';
3774 if (STRCMP("# requires python 2.x", IObuff) == 0)
3775 {
3776 requires_py_version = 2;
3777 break;
3778 }
3779 if (STRCMP("# requires python 3.x", IObuff) == 0)
3780 {
3781 requires_py_version = 3;
3782 break;
3783 }
3784 }
3785 fclose(file);
3786 }
3787 return requires_py_version;
3788}
3789
3790
3791/*
3792 * Source a python file using the requested python version.
3793 */
3794 static void
3795source_pyx_file(exarg_T *eap, char_u *fname)
3796{
3797 exarg_T ex;
3798 int v = requires_py_version(fname);
3799
3800# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3801 init_pyxversion();
3802# endif
3803 if (v == 0)
3804 {
3805# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3806 /* user didn't choose a preference, 'pyx' is used */
3807 v = p_pyx;
3808# elif defined(FEAT_PYTHON)
3809 v = 2;
3810# elif defined(FEAT_PYTHON3)
3811 v = 3;
3812# endif
3813 }
3814
3815 /*
3816 * now source, if required python version is not supported show
3817 * unobtrusive message.
3818 */
3819 if (eap == NULL)
3820 vim_memset(&ex, 0, sizeof(ex));
3821 else
3822 ex = *eap;
3823 ex.arg = fname;
3824 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3825
3826 if (v == 2)
3827 {
3828# ifdef FEAT_PYTHON
3829 ex_pyfile(&ex);
3830# else
3831 vim_snprintf((char *)IObuff, IOSIZE,
3832 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3833 fname);
3834 MSG(IObuff);
3835# endif
3836 return;
3837 }
3838 else
3839 {
3840# ifdef FEAT_PYTHON3
3841 ex_py3file(&ex);
3842# else
3843 vim_snprintf((char *)IObuff, IOSIZE,
3844 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3845 fname);
3846 MSG(IObuff);
3847# endif
3848 return;
3849 }
3850}
3851
3852/*
3853 * ":pyxfile {fname}"
3854 */
3855 void
3856ex_pyxfile(exarg_T *eap)
3857{
3858 source_pyx_file(eap, eap->arg);
3859}
3860
3861/*
3862 * ":pyx"
3863 */
3864 void
3865ex_pyx(exarg_T *eap)
3866{
3867# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3868 init_pyxversion();
3869 if (p_pyx == 2)
3870 ex_python(eap);
3871 else
3872 ex_py3(eap);
3873# elif defined(FEAT_PYTHON)
3874 ex_python(eap);
3875# elif defined(FEAT_PYTHON3)
3876 ex_py3(eap);
3877# endif
3878}
3879
3880/*
3881 * ":pyxdo"
3882 */
3883 void
3884ex_pyxdo(exarg_T *eap)
3885{
3886# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3887 init_pyxversion();
3888 if (p_pyx == 2)
3889 ex_pydo(eap);
3890 else
3891 ex_py3do(eap);
3892# elif defined(FEAT_PYTHON)
3893 ex_pydo(eap);
3894# elif defined(FEAT_PYTHON3)
3895 ex_py3do(eap);
3896# endif
3897}
3898
3899#endif
3900
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901/*
3902 * ":source {fname}"
3903 */
3904 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003905ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906{
3907#ifdef FEAT_BROWSE
3908 if (cmdmod.browse)
3909 {
3910 char_u *fname = NULL;
3911
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003912 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3914 if (fname != NULL)
3915 {
3916 cmd_source(fname, eap);
3917 vim_free(fname);
3918 }
3919 }
3920 else
3921#endif
3922 cmd_source(eap->arg, eap);
3923}
3924
3925 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003926cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927{
3928 if (*fname == NUL)
3929 EMSG(_(e_argreq));
3930
Bram Moolenaar071d4272004-06-13 20:20:40 +00003931 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003932 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003933 * Need to execute the commands directly. This is required at least
3934 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935 * - ":g" command busy
3936 * - after ":argdo", ":windo" or ":bufdo"
3937 * - another command follows
3938 * - inside a loop
3939 */
3940 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3941#ifdef FEAT_EVAL
3942 || eap->cstack->cs_idx >= 0
3943#endif
3944 );
3945
3946 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003947 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 EMSG2(_(e_notopen), fname);
3949}
3950
3951/*
3952 * ":source" and associated commands.
3953 */
3954/*
3955 * Structure used to store info for each sourced file.
3956 * It is shared between do_source() and getsourceline().
3957 * This is required, because it needs to be handed to do_cmdline() and
3958 * sourcing can be done recursively.
3959 */
3960struct source_cookie
3961{
3962 FILE *fp; /* opened file for sourcing */
3963 char_u *nextline; /* if not NULL: line that was read ahead */
3964 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003965#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003966 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3967 int error; /* TRUE if LF found after CR-LF */
3968#endif
3969#ifdef FEAT_EVAL
3970 linenr_T breakpoint; /* next line with breakpoint or zero */
3971 char_u *fname; /* name of sourced file */
3972 int dbg_tick; /* debug_tick when breakpoint was set */
3973 int level; /* top nesting level of sourced file */
3974#endif
3975#ifdef FEAT_MBYTE
3976 vimconv_T conv; /* type of conversion */
3977#endif
3978};
3979
3980#ifdef FEAT_EVAL
3981/*
3982 * Return the address holding the next breakpoint line for a source cookie.
3983 */
3984 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003985source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003986{
3987 return &((struct source_cookie *)cookie)->breakpoint;
3988}
3989
3990/*
3991 * Return the address holding the debug tick for a source cookie.
3992 */
3993 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003994source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995{
3996 return &((struct source_cookie *)cookie)->dbg_tick;
3997}
3998
3999/*
4000 * Return the nesting level for a source cookie.
4001 */
4002 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004003source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004{
4005 return ((struct source_cookie *)cookie)->level;
4006}
4007#endif
4008
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004009static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004011#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
4012# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004013static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014
4015/*
4016 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004017 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004018 */
4019 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004020fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004022# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01004023 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
4024# else
4025 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004026# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027
4028 if (fd_tmp == -1)
4029 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004030
4031# ifdef HAVE_FD_CLOEXEC
4032 {
4033 int fdflags = fcntl(fd_tmp, F_GETFD);
4034 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02004035 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004036 }
4037# endif
4038
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 return fdopen(fd_tmp, READBIN);
4040}
4041#endif
4042
4043
4044/*
4045 * do_source: Read the file "fname" and execute its lines as EX commands.
4046 *
4047 * This function may be called recursively!
4048 *
4049 * return FAIL if file could not be opened, OK otherwise
4050 */
4051 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004052do_source(
4053 char_u *fname,
4054 int check_other, /* check for .vimrc and _vimrc */
4055 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056{
4057 struct source_cookie cookie;
4058 char_u *save_sourcing_name;
4059 linenr_T save_sourcing_lnum;
4060 char_u *p;
4061 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00004062 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 int retval = FAIL;
4064#ifdef FEAT_EVAL
4065 scid_T save_current_SID;
4066 static scid_T last_current_SID = 0;
4067 void *save_funccalp;
4068 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004069 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004070# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02004071 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072 int stat_ok;
4073# endif
4074#endif
4075#ifdef STARTUPTIME
4076 struct timeval tv_rel;
4077 struct timeval tv_start;
4078#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004079#ifdef FEAT_PROFILE
4080 proftime_T wait_start;
4081#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082
Bram Moolenaar071d4272004-06-13 20:20:40 +00004083 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004084 if (p == NULL)
4085 return retval;
4086 fname_exp = fix_fname(p);
4087 vim_free(p);
4088 if (fname_exp == NULL)
4089 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004090 if (mch_isdir(fname_exp))
4091 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00004092 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004093 goto theend;
4094 }
4095
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004096#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004097 /* Apply SourceCmd autocommands, they should get the file and source it. */
4098 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
4099 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
4100 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004101 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004102# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004103 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004104# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004105 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004106# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004107 goto theend;
4108 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004109
4110 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004111 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
4112#endif
4113
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004114#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4116#else
4117 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4118#endif
4119 if (cookie.fp == NULL && check_other)
4120 {
4121 /*
4122 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
4123 * and ".exrc" by "_exrc" or vice versa.
4124 */
4125 p = gettail(fname_exp);
4126 if ((*p == '.' || *p == '_')
4127 && (STRICMP(p + 1, "vimrc") == 0
4128 || STRICMP(p + 1, "gvimrc") == 0
4129 || STRICMP(p + 1, "exrc") == 0))
4130 {
4131 if (*p == '_')
4132 *p = '.';
4133 else
4134 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004135#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4137#else
4138 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4139#endif
4140 }
4141 }
4142
4143 if (cookie.fp == NULL)
4144 {
4145 if (p_verbose > 0)
4146 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004147 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004149 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 else
4151 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004152 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004153 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 }
4155 goto theend;
4156 }
4157
4158 /*
4159 * The file exists.
4160 * - In verbose mode, give a message.
4161 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
4162 */
4163 if (p_verbose > 1)
4164 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004165 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004166 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004167 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 else
4169 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004170 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004171 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004173 if (is_vimrc == DOSO_VIMRC)
4174 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
4175 else if (is_vimrc == DOSO_GVIMRC)
4176 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177
4178#ifdef USE_CRNL
4179 /* If no automatic file format: Set default to CR-NL. */
4180 if (*p_ffs == NUL)
4181 cookie.fileformat = EOL_DOS;
4182 else
4183 cookie.fileformat = EOL_UNKNOWN;
4184 cookie.error = FALSE;
4185#endif
4186
4187#ifdef USE_CR
4188 /* If no automatic file format: Set default to CR. */
4189 if (*p_ffs == NUL)
4190 cookie.fileformat = EOL_MAC;
4191 else
4192 cookie.fileformat = EOL_UNKNOWN;
4193 cookie.error = FALSE;
4194#endif
4195
4196 cookie.nextline = NULL;
4197 cookie.finished = FALSE;
4198
4199#ifdef FEAT_EVAL
4200 /*
4201 * Check if this script has a breakpoint.
4202 */
4203 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
4204 cookie.fname = fname_exp;
4205 cookie.dbg_tick = debug_tick;
4206
4207 cookie.level = ex_nesting_level;
4208#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004209
4210 /*
4211 * Keep the sourcing name/lnum, for recursive calls.
4212 */
4213 save_sourcing_name = sourcing_name;
4214 sourcing_name = fname_exp;
4215 save_sourcing_lnum = sourcing_lnum;
4216 sourcing_lnum = 0;
4217
Bram Moolenaar73881402009-02-04 16:50:47 +00004218#ifdef FEAT_MBYTE
4219 cookie.conv.vc_type = CONV_NONE; /* no conversion */
4220
4221 /* Read the first line so we can check for a UTF-8 BOM. */
4222 firstline = getsourceline(0, (void *)&cookie, 0);
4223 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
4224 && firstline[1] == 0xbb && firstline[2] == 0xbf)
4225 {
4226 /* Found BOM; setup conversion, skip over BOM and recode the line. */
4227 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
4228 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00004229 if (p == NULL)
4230 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00004231 if (p != NULL)
4232 {
4233 vim_free(firstline);
4234 firstline = p;
4235 }
4236 }
4237#endif
4238
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004240 if (time_fd != NULL)
4241 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242#endif
4243
4244#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00004245# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004246 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004247 prof_child_enter(&wait_start); /* entering a child now */
4248# endif
4249
4250 /* Don't use local function variables, if called from a function.
4251 * Also starts profiling timer for nested script. */
4252 save_funccalp = save_funccal();
4253
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 /*
4255 * Check if this script was sourced before to finds its SID.
4256 * If it's new, generate a new SID.
4257 */
4258 save_current_SID = current_SID;
4259# ifdef UNIX
4260 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4261# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004262 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
4263 {
4264 si = &SCRIPT_ITEM(current_SID);
4265 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266 && (
4267# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004268 /* Compare dev/ino when possible, it catches symbolic
4269 * links. Also compare file names, the inode may change
4270 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004271 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004272 && (si->sn_dev == st.st_dev
4273 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004275 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004277 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 if (current_SID == 0)
4279 {
4280 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004281 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4282 == FAIL)
4283 goto almosttheend;
4284 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004286 ++script_items.ga_len;
4287 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4288# ifdef FEAT_PROFILE
4289 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004292 si = &SCRIPT_ITEM(current_SID);
4293 si->sn_name = fname_exp;
4294 fname_exp = NULL;
4295# ifdef UNIX
4296 if (stat_ok)
4297 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004298 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004299 si->sn_dev = st.st_dev;
4300 si->sn_ino = st.st_ino;
4301 }
4302 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004303 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004304# endif
4305
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306 /* Allocate the local script variables to use for this script. */
4307 new_script_vars(current_SID);
4308 }
4309
Bram Moolenaar05159a02005-02-26 23:04:13 +00004310# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004311 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004312 {
4313 int forceit;
4314
4315 /* Check if we do profiling for this script. */
4316 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4317 {
4318 script_do_profile(si);
4319 si->sn_pr_force = forceit;
4320 }
4321 if (si->sn_prof_on)
4322 {
4323 ++si->sn_pr_count;
4324 profile_start(&si->sn_pr_start);
4325 profile_zero(&si->sn_pr_children);
4326 }
4327 }
4328# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329#endif
4330
4331 /*
4332 * Call do_cmdline, which will call getsourceline() to get the lines.
4333 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004334 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004336 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004337
4338#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004339 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004340 {
4341 /* Get "si" again, "script_items" may have been reallocated. */
4342 si = &SCRIPT_ITEM(current_SID);
4343 if (si->sn_prof_on)
4344 {
4345 profile_end(&si->sn_pr_start);
4346 profile_sub_wait(&wait_start, &si->sn_pr_start);
4347 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004348 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4349 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004350 }
4351 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352#endif
4353
4354 if (got_int)
4355 EMSG(_(e_interr));
4356 sourcing_name = save_sourcing_name;
4357 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004358 if (p_verbose > 1)
4359 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004360 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004361 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004363 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004364 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 }
4366#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004367 if (time_fd != NULL)
4368 {
4369 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4370 time_msg((char *)IObuff, &tv_start);
4371 time_pop(&tv_rel);
4372 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373#endif
4374
4375#ifdef FEAT_EVAL
4376 /*
4377 * After a "finish" in debug mode, need to break at first command of next
4378 * sourced file.
4379 */
4380 if (save_debug_break_level > ex_nesting_level
4381 && debug_break_level == ex_nesting_level)
4382 ++debug_break_level;
4383#endif
4384
Bram Moolenaar05159a02005-02-26 23:04:13 +00004385#ifdef FEAT_EVAL
4386almosttheend:
4387 current_SID = save_current_SID;
4388 restore_funccal(save_funccalp);
4389# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004390 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004391 prof_child_exit(&wait_start); /* leaving a child now */
4392# endif
4393#endif
4394 fclose(cookie.fp);
4395 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004396 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004397#ifdef FEAT_MBYTE
4398 convert_setup(&cookie.conv, NULL, NULL);
4399#endif
4400
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401theend:
4402 vim_free(fname_exp);
4403 return retval;
4404}
4405
4406#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004407
Bram Moolenaar071d4272004-06-13 20:20:40 +00004408/*
4409 * ":scriptnames"
4410 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004411 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004412ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004413{
4414 int i;
4415
Bram Moolenaar05159a02005-02-26 23:04:13 +00004416 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4417 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004418 {
4419 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4420 NameBuff, MAXPATHL, TRUE);
4421 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004422 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423}
4424
4425# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4426/*
4427 * Fix slashes in the list of script names for 'shellslash'.
4428 */
4429 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004430scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004431{
4432 int i;
4433
Bram Moolenaar05159a02005-02-26 23:04:13 +00004434 for (i = 1; i <= script_items.ga_len; ++i)
4435 if (SCRIPT_ITEM(i).sn_name != NULL)
4436 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437}
4438# endif
4439
4440/*
4441 * Get a pointer to a script name. Used for ":verbose set".
4442 */
4443 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004444get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445{
4446 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004447 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004448 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004449 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004450 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004451 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004453 return (char_u *)_("environment variable");
4454 if (id == SID_ERROR)
4455 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004456 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004458
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004459# if defined(EXITFREE) || defined(PROTO)
4460 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004461free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004462{
4463 int i;
4464
4465 for (i = script_items.ga_len; i > 0; --i)
4466 vim_free(SCRIPT_ITEM(i).sn_name);
4467 ga_clear(&script_items);
4468}
4469# endif
4470
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471#endif
4472
4473#if defined(USE_CR) || defined(PROTO)
4474
4475# if defined(__MSL__) && (__MSL__ >= 22)
4476/*
4477 * Newer version of the Metrowerks library handle DOS and UNIX files
4478 * without help.
4479 * Test with earlier versions, MSL 2.2 is the library supplied with
4480 * Codewarrior Pro 2.
4481 */
4482 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004483fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004484{
4485 return fgets(s, n, stream);
4486}
4487# else
4488/*
4489 * Version of fgets() which also works for lines ending in a <CR> only
4490 * (Macintosh format).
4491 * For older versions of the Metrowerks library.
4492 * At least CodeWarrior 9 needed this code.
4493 */
4494 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004495fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496{
4497 int c = 0;
4498 int char_read = 0;
4499
4500 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4501 {
4502 c = fgetc(stream);
4503 s[char_read++] = c;
4504 /* If the file is in DOS format, we need to skip a NL after a CR. I
4505 * thought it was the other way around, but this appears to work... */
4506 if (c == '\n')
4507 {
4508 c = fgetc(stream);
4509 if (c != '\r')
4510 ungetc(c, stream);
4511 }
4512 }
4513
4514 s[char_read] = 0;
4515 if (char_read == 0)
4516 return NULL;
4517
4518 if (feof(stream) && char_read == 1)
4519 return NULL;
4520
4521 return s;
4522}
4523# endif
4524#endif
4525
4526/*
4527 * Get one full line from a sourced file.
4528 * Called by do_cmdline() when it's called from do_source().
4529 *
4530 * Return a pointer to the line in allocated memory.
4531 * Return NULL for end-of-file or some error.
4532 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004534getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535{
4536 struct source_cookie *sp = (struct source_cookie *)cookie;
4537 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004538 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539
4540#ifdef FEAT_EVAL
4541 /* If breakpoints have been added/deleted need to check for it. */
4542 if (sp->dbg_tick < debug_tick)
4543 {
4544 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4545 sp->dbg_tick = debug_tick;
4546 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004547# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004548 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004549 script_line_end();
4550# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551#endif
4552 /*
4553 * Get current line. If there is a read-ahead line, use it, otherwise get
4554 * one now.
4555 */
4556 if (sp->finished)
4557 line = NULL;
4558 else if (sp->nextline == NULL)
4559 line = get_one_sourceline(sp);
4560 else
4561 {
4562 line = sp->nextline;
4563 sp->nextline = NULL;
4564 ++sourcing_lnum;
4565 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004566#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004567 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004568 script_line_start();
4569#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570
4571 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4572 * contain the 'C' flag. */
4573 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4574 {
4575 /* compensate for the one line read-ahead */
4576 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004577
4578 /* Get the next line and concatenate it when it starts with a
4579 * backslash. We always need to read the next line, keep it in
4580 * sp->nextline. */
4581 sp->nextline = get_one_sourceline(sp);
4582 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004584 garray_T ga;
4585
Bram Moolenaarb549a732012-02-22 18:29:33 +01004586 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004587 ga_concat(&ga, line);
4588 ga_concat(&ga, p + 1);
4589 for (;;)
4590 {
4591 vim_free(sp->nextline);
4592 sp->nextline = get_one_sourceline(sp);
4593 if (sp->nextline == NULL)
4594 break;
4595 p = skipwhite(sp->nextline);
4596 if (*p != '\\')
4597 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004598 /* Adjust the growsize to the current length to speed up
4599 * concatenating many lines. */
4600 if (ga.ga_len > 400)
4601 {
4602 if (ga.ga_len > 8000)
4603 ga.ga_growsize = 8000;
4604 else
4605 ga.ga_growsize = ga.ga_len;
4606 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004607 ga_concat(&ga, p + 1);
4608 }
4609 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004611 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 }
4613 }
4614
4615#ifdef FEAT_MBYTE
4616 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4617 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004618 char_u *s;
4619
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 /* Convert the encoding of the script line. */
4621 s = string_convert(&sp->conv, line, NULL);
4622 if (s != NULL)
4623 {
4624 vim_free(line);
4625 line = s;
4626 }
4627 }
4628#endif
4629
4630#ifdef FEAT_EVAL
4631 /* Did we encounter a breakpoint? */
4632 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4633 {
4634 dbg_breakpoint(sp->fname, sourcing_lnum);
4635 /* Find next breakpoint. */
4636 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4637 sp->dbg_tick = debug_tick;
4638 }
4639#endif
4640
4641 return line;
4642}
4643
4644 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004645get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646{
4647 garray_T ga;
4648 int len;
4649 int c;
4650 char_u *buf;
4651#ifdef USE_CRNL
4652 int has_cr; /* CR-LF found */
4653#endif
4654#ifdef USE_CR
4655 char_u *scan;
4656#endif
4657 int have_read = FALSE;
4658
4659 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004660 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661
4662 /*
4663 * Loop until there is a finished line (or end-of-file).
4664 */
4665 sourcing_lnum++;
4666 for (;;)
4667 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004668 /* make room to read at least 120 (more) characters */
4669 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670 break;
4671 buf = (char_u *)ga.ga_data;
4672
4673#ifdef USE_CR
4674 if (sp->fileformat == EOL_MAC)
4675 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004676 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4677 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 break;
4679 }
4680 else
4681#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004682 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4683 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004684 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004685 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686#ifdef USE_CRNL
4687 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4688 * CTRL-Z by its own, or after a NL. */
4689 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4690 && sp->fileformat == EOL_DOS
4691 && buf[len - 1] == Ctrl_Z)
4692 {
4693 buf[len - 1] = NUL;
4694 break;
4695 }
4696#endif
4697
4698#ifdef USE_CR
4699 /* If the read doesn't stop on a new line, and there's
4700 * some CR then we assume a Mac format */
4701 if (sp->fileformat == EOL_UNKNOWN)
4702 {
4703 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4704 sp->fileformat = EOL_MAC;
4705 else
4706 sp->fileformat = EOL_UNIX;
4707 }
4708
4709 if (sp->fileformat == EOL_MAC)
4710 {
4711 scan = vim_strchr(buf, '\r');
4712
4713 if (scan != NULL)
4714 {
4715 *scan = '\n';
4716 if (*(scan + 1) != 0)
4717 {
4718 *(scan + 1) = 0;
4719 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4720 }
4721 }
4722 len = STRLEN(buf);
4723 }
4724#endif
4725
4726 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727 ga.ga_len = len;
4728
4729 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004730 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 continue;
4732
4733 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4734 {
4735#ifdef USE_CRNL
4736 has_cr = (len >= 2 && buf[len - 2] == '\r');
4737 if (sp->fileformat == EOL_UNKNOWN)
4738 {
4739 if (has_cr)
4740 sp->fileformat = EOL_DOS;
4741 else
4742 sp->fileformat = EOL_UNIX;
4743 }
4744
4745 if (sp->fileformat == EOL_DOS)
4746 {
4747 if (has_cr) /* replace trailing CR */
4748 {
4749 buf[len - 2] = '\n';
4750 --len;
4751 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752 }
4753 else /* lines like ":map xx yy^M" will have failed */
4754 {
4755 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004756 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004757 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004759 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760 sp->error = TRUE;
4761 sp->fileformat = EOL_UNIX;
4762 }
4763 }
4764#endif
4765 /* The '\n' is escaped if there is an odd number of ^V's just
4766 * before it, first set "c" just before the 'V's and then check
4767 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4768 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4769 ;
4770 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4771 {
4772 sourcing_lnum++;
4773 continue;
4774 }
4775
4776 buf[len - 1] = NUL; /* remove the NL */
4777 }
4778
4779 /*
4780 * Check for ^C here now and then, so recursive :so can be broken.
4781 */
4782 line_breakcheck();
4783 break;
4784 }
4785
4786 if (have_read)
4787 return (char_u *)ga.ga_data;
4788
4789 vim_free(ga.ga_data);
4790 return NULL;
4791}
4792
Bram Moolenaar05159a02005-02-26 23:04:13 +00004793#if defined(FEAT_PROFILE) || defined(PROTO)
4794/*
4795 * Called when starting to read a script line.
4796 * "sourcing_lnum" must be correct!
4797 * When skipping lines it may not actually be executed, but we won't find out
4798 * until later and we need to store the time now.
4799 */
4800 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004801script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004802{
4803 scriptitem_T *si;
4804 sn_prl_T *pp;
4805
4806 if (current_SID <= 0 || current_SID > script_items.ga_len)
4807 return;
4808 si = &SCRIPT_ITEM(current_SID);
4809 if (si->sn_prof_on && sourcing_lnum >= 1)
4810 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004811 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004812 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004813 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004814 si->sn_prl_idx = sourcing_lnum - 1;
4815 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4816 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4817 {
4818 /* Zero counters for a line that was not used before. */
4819 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4820 pp->snp_count = 0;
4821 profile_zero(&pp->sn_prl_total);
4822 profile_zero(&pp->sn_prl_self);
4823 ++si->sn_prl_ga.ga_len;
4824 }
4825 si->sn_prl_execed = FALSE;
4826 profile_start(&si->sn_prl_start);
4827 profile_zero(&si->sn_prl_children);
4828 profile_get_wait(&si->sn_prl_wait);
4829 }
4830}
4831
4832/*
4833 * Called when actually executing a function line.
4834 */
4835 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004836script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004837{
4838 scriptitem_T *si;
4839
4840 if (current_SID <= 0 || current_SID > script_items.ga_len)
4841 return;
4842 si = &SCRIPT_ITEM(current_SID);
4843 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4844 si->sn_prl_execed = TRUE;
4845}
4846
4847/*
4848 * Called when done with a function line.
4849 */
4850 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004851script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004852{
4853 scriptitem_T *si;
4854 sn_prl_T *pp;
4855
4856 if (current_SID <= 0 || current_SID > script_items.ga_len)
4857 return;
4858 si = &SCRIPT_ITEM(current_SID);
4859 if (si->sn_prof_on && si->sn_prl_idx >= 0
4860 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4861 {
4862 if (si->sn_prl_execed)
4863 {
4864 pp = &PRL_ITEM(si, si->sn_prl_idx);
4865 ++pp->snp_count;
4866 profile_end(&si->sn_prl_start);
4867 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004868 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004869 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4870 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004871 }
4872 si->sn_prl_idx = -1;
4873 }
4874}
4875#endif
4876
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877/*
4878 * ":scriptencoding": Set encoding conversion for a sourced script.
4879 * Without the multi-byte feature it's simply ignored.
4880 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004882ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004883{
4884#ifdef FEAT_MBYTE
4885 struct source_cookie *sp;
4886 char_u *name;
4887
4888 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4889 {
4890 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4891 return;
4892 }
4893
4894 if (*eap->arg != NUL)
4895 {
4896 name = enc_canonize(eap->arg);
4897 if (name == NULL) /* out of memory */
4898 return;
4899 }
4900 else
4901 name = eap->arg;
4902
4903 /* Setup for conversion from the specified encoding to 'encoding'. */
4904 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4905 convert_setup(&sp->conv, name, p_enc);
4906
4907 if (name != eap->arg)
4908 vim_free(name);
4909#endif
4910}
4911
4912#if defined(FEAT_EVAL) || defined(PROTO)
4913/*
4914 * ":finish": Mark a sourced file as finished.
4915 */
4916 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004917ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918{
4919 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4920 do_finish(eap, FALSE);
4921 else
4922 EMSG(_("E168: :finish used outside of a sourced file"));
4923}
4924
4925/*
4926 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4927 * Also called for a pending finish at the ":endtry" or after returning from
4928 * an extra do_cmdline(). "reanimate" is used in the latter case.
4929 */
4930 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004931do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004932{
4933 int idx;
4934
4935 if (reanimate)
4936 ((struct source_cookie *)getline_cookie(eap->getline,
4937 eap->cookie))->finished = FALSE;
4938
4939 /*
4940 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4941 * not in its finally clause (which then is to be executed next) is found.
4942 * In this case, make the ":finish" pending for execution at the ":endtry".
4943 * Otherwise, finish normally.
4944 */
4945 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4946 if (idx >= 0)
4947 {
4948 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4949 report_make_pending(CSTP_FINISH, NULL);
4950 }
4951 else
4952 ((struct source_cookie *)getline_cookie(eap->getline,
4953 eap->cookie))->finished = TRUE;
4954}
4955
4956
4957/*
4958 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4959 * message for missing ":endif".
4960 * Return FALSE when not sourcing a file.
4961 */
4962 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004963source_finished(
4964 char_u *(*fgetline)(int, void *, int),
4965 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004967 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004968 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004969 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004970}
4971#endif
4972
4973#if defined(FEAT_LISTCMDS) || defined(PROTO)
4974/*
4975 * ":checktime [buffer]"
4976 */
4977 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004978ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004979{
4980 buf_T *buf;
4981 int save_no_check_timestamps = no_check_timestamps;
4982
4983 no_check_timestamps = 0;
4984 if (eap->addr_count == 0) /* default is all buffers */
4985 check_timestamps(FALSE);
4986 else
4987 {
4988 buf = buflist_findnr((int)eap->line2);
4989 if (buf != NULL) /* cannot happen? */
4990 (void)buf_check_timestamp(buf, FALSE);
4991 }
4992 no_check_timestamps = save_no_check_timestamps;
4993}
4994#endif
4995
Bram Moolenaar071d4272004-06-13 20:20:40 +00004996#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4997 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004998# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004999static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005000
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005001 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005002get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005004 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005006 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005007 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005009# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010 if (loc != NULL)
5011 {
5012 char_u *p;
5013
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005014 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
5015 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 p = vim_strchr(loc, '=');
5017 if (p != NULL)
5018 {
5019 loc = ++p;
5020 while (*p != NUL) /* remove trailing newline */
5021 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005022 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00005023 {
5024 *p = NUL;
5025 break;
5026 }
5027 ++p;
5028 }
5029 }
5030 }
5031# endif
5032
5033 return loc;
5034}
5035#endif
5036
5037
5038#ifdef WIN32
5039/*
5040 * On MS-Windows locale names are strings like "German_Germany.1252", but
5041 * gettext expects "de". Try to translate one into another here for a few
5042 * supported languages.
5043 */
5044 static char_u *
5045gettext_lang(char_u *name)
5046{
5047 int i;
5048 static char *(mtable[]) = {
5049 "afrikaans", "af",
5050 "czech", "cs",
5051 "dutch", "nl",
5052 "german", "de",
5053 "english_united kingdom", "en_GB",
5054 "spanish", "es",
5055 "french", "fr",
5056 "italian", "it",
5057 "japanese", "ja",
5058 "korean", "ko",
5059 "norwegian", "no",
5060 "polish", "pl",
5061 "russian", "ru",
5062 "slovak", "sk",
5063 "swedish", "sv",
5064 "ukrainian", "uk",
5065 "chinese_china", "zh_CN",
5066 "chinese_taiwan", "zh_TW",
5067 NULL};
5068
5069 for (i = 0; mtable[i] != NULL; i += 2)
5070 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005071 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005072 return name;
5073}
5074#endif
5075
5076#if defined(FEAT_MULTI_LANG) || defined(PROTO)
5077/*
5078 * Obtain the current messages language. Used to set the default for
5079 * 'helplang'. May return NULL or an empty string.
5080 */
5081 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005082get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083{
5084 char_u *p;
5085
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005086# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005088 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089# else
5090 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005091 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
5092 * and LC_MONETARY may be set differently for a Japanese working in the
5093 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005094 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095# endif
5096# else
5097 p = mch_getenv((char_u *)"LC_ALL");
5098 if (p == NULL || *p == NUL)
5099 {
5100 p = mch_getenv((char_u *)"LC_MESSAGES");
5101 if (p == NULL || *p == NUL)
5102 p = mch_getenv((char_u *)"LANG");
5103 }
5104# endif
5105# ifdef WIN32
5106 p = gettext_lang(p);
5107# endif
5108 return p;
5109}
5110#endif
5111
Bram Moolenaardef9e822004-12-31 20:58:58 +00005112/* Complicated #if; matches with where get_mess_env() is used below. */
5113#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5114 && defined(LC_MESSAGES))) \
5115 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5116 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
5117 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005118static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119
5120/*
5121 * Get the language used for messages from the environment.
5122 */
5123 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005124get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125{
5126 char_u *p;
5127
5128 p = mch_getenv((char_u *)"LC_ALL");
5129 if (p == NULL || *p == NUL)
5130 {
5131 p = mch_getenv((char_u *)"LC_MESSAGES");
5132 if (p == NULL || *p == NUL)
5133 {
5134 p = mch_getenv((char_u *)"LANG");
5135 if (p != NULL && VIM_ISDIGIT(*p))
5136 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005137# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005139 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005140# endif
5141 }
5142 }
5143 return p;
5144}
5145#endif
5146
5147#if defined(FEAT_EVAL) || defined(PROTO)
5148
5149/*
5150 * Set the "v:lang" variable according to the current locale setting.
5151 * Also do "v:lc_time"and "v:ctype".
5152 */
5153 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005154set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005155{
5156 char_u *loc;
5157
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005158# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005159 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005160# else
5161 /* setlocale() not supported: use the default value */
5162 loc = (char_u *)"C";
5163# endif
5164 set_vim_var_string(VV_CTYPE, loc, -1);
5165
5166 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
5167 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005168# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005169 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005170# else
5171 loc = get_mess_env();
5172# endif
5173 set_vim_var_string(VV_LANG, loc, -1);
5174
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005175# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005176 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177# endif
5178 set_vim_var_string(VV_LC_TIME, loc, -1);
5179}
5180#endif
5181
5182#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5183 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
5184/*
5185 * ":language": Set the language (locale).
5186 */
5187 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005188ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189{
5190 char *loc;
5191 char_u *p;
5192 char_u *name;
5193 int what = LC_ALL;
5194 char *whatstr = "";
5195#ifdef LC_MESSAGES
5196# define VIM_LC_MESSAGES LC_MESSAGES
5197#else
5198# define VIM_LC_MESSAGES 6789
5199#endif
5200
5201 name = eap->arg;
5202
5203 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
5204 * Allow abbreviation, but require at least 3 characters to avoid
5205 * confusion with a two letter language name "me" or "ct". */
5206 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01005207 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208 {
5209 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
5210 {
5211 what = VIM_LC_MESSAGES;
5212 name = skipwhite(p);
5213 whatstr = "messages ";
5214 }
5215 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
5216 {
5217 what = LC_CTYPE;
5218 name = skipwhite(p);
5219 whatstr = "ctype ";
5220 }
5221 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
5222 {
5223 what = LC_TIME;
5224 name = skipwhite(p);
5225 whatstr = "time ";
5226 }
5227 }
5228
5229 if (*name == NUL)
5230 {
5231#ifndef LC_MESSAGES
5232 if (what == VIM_LC_MESSAGES)
5233 p = get_mess_env();
5234 else
5235#endif
5236 p = (char_u *)setlocale(what, NULL);
5237 if (p == NULL || *p == NUL)
5238 p = (char_u *)"Unknown";
5239 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
5240 }
5241 else
5242 {
5243#ifndef LC_MESSAGES
5244 if (what == VIM_LC_MESSAGES)
5245 loc = "";
5246 else
5247#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005248 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005250#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5251 /* Make sure strtod() uses a decimal point, not a comma. */
5252 setlocale(LC_NUMERIC, "C");
5253#endif
5254 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255 if (loc == NULL)
5256 EMSG2(_("E197: Cannot set language to \"%s\""), name);
5257 else
5258 {
5259#ifdef HAVE_NL_MSG_CAT_CNTR
5260 /* Need to do this for GNU gettext, otherwise cached translations
5261 * will be used again. */
5262 extern int _nl_msg_cat_cntr;
5263
5264 ++_nl_msg_cat_cntr;
5265#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005266 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005267 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5268
5269 if (what != LC_TIME)
5270 {
5271 /* Tell gettext() what to translate to. It apparently doesn't
5272 * use the currently effective locale. Also do this when
5273 * FEAT_GETTEXT isn't defined, so that shell commands use this
5274 * value. */
5275 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005276 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005277 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005278
5279 /* Clear $LANGUAGE because GNU gettext uses it. */
5280 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005281# ifdef WIN32
5282 /* Apparently MS-Windows printf() may cause a crash when
5283 * we give it 8-bit text while it's expecting text in the
5284 * current locale. This call avoids that. */
5285 setlocale(LC_CTYPE, "C");
5286# endif
5287 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288 if (what != LC_CTYPE)
5289 {
5290 char_u *mname;
5291#ifdef WIN32
5292 mname = gettext_lang(name);
5293#else
5294 mname = name;
5295#endif
5296 vim_setenv((char_u *)"LC_MESSAGES", mname);
5297#ifdef FEAT_MULTI_LANG
5298 set_helplang_default(mname);
5299#endif
5300 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005301 }
5302
5303# ifdef FEAT_EVAL
5304 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5305 set_lang_var();
5306# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005307# ifdef FEAT_TITLE
5308 maketitle();
5309# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005310 }
5311 }
5312}
5313
5314# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005315
5316static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005317
5318# ifndef WIN32
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005319static int did_init_locales = FALSE;
5320
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005321/* Return an array of strings for all available locales + NULL for the
5322 * last element. Return NULL in case of error. */
5323 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005324find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005325{
5326 garray_T locales_ga;
5327 char_u *loc;
5328
5329 /* Find all available locales by running command "locale -a". If this
5330 * doesn't work we won't have completion. */
5331 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005332 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005333 if (locale_a == NULL)
5334 return NULL;
5335 ga_init2(&locales_ga, sizeof(char_u *), 20);
5336
5337 /* Transform locale_a string where each locale is separated by "\n"
5338 * into an array of locale strings. */
5339 loc = (char_u *)strtok((char *)locale_a, "\n");
5340
5341 while (loc != NULL)
5342 {
5343 if (ga_grow(&locales_ga, 1) == FAIL)
5344 break;
5345 loc = vim_strsave(loc);
5346 if (loc == NULL)
5347 break;
5348
5349 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5350 loc = (char_u *)strtok(NULL, "\n");
5351 }
5352 vim_free(locale_a);
5353 if (ga_grow(&locales_ga, 1) == FAIL)
5354 {
5355 ga_clear(&locales_ga);
5356 return NULL;
5357 }
5358 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5359 return (char_u **)locales_ga.ga_data;
5360}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005361# endif
5362
5363/*
5364 * Lazy initialization of all available locales.
5365 */
5366 static void
5367init_locales(void)
5368{
5369# ifndef WIN32
5370 if (!did_init_locales)
5371 {
5372 did_init_locales = TRUE;
5373 locales = find_locales();
5374 }
5375# endif
5376}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005377
5378# if defined(EXITFREE) || defined(PROTO)
5379 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005380free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005381{
5382 int i;
5383 if (locales != NULL)
5384 {
5385 for (i = 0; locales[i] != NULL; i++)
5386 vim_free(locales[i]);
5387 vim_free(locales);
5388 locales = NULL;
5389 }
5390}
5391# endif
5392
Bram Moolenaar071d4272004-06-13 20:20:40 +00005393/*
5394 * Function given to ExpandGeneric() to obtain the possible arguments of the
5395 * ":language" command.
5396 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005398get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005399{
5400 if (idx == 0)
5401 return (char_u *)"messages";
5402 if (idx == 1)
5403 return (char_u *)"ctype";
5404 if (idx == 2)
5405 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005406
5407 init_locales();
5408 if (locales == NULL)
5409 return NULL;
5410 return locales[idx - 3];
5411}
5412
5413/*
5414 * Function given to ExpandGeneric() to obtain the available locales.
5415 */
5416 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005417get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005418{
5419 init_locales();
5420 if (locales == NULL)
5421 return NULL;
5422 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005423}
5424# endif
5425
5426#endif