blob: 3efa8ca2e5be1afa3f6509f5bfd79dd27b64ffce [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.
Bram Moolenaarc4f83382017-07-07 14:50:44 +02001186 * Returns -1 if there are no pending timers.
Bram Moolenaar975b5272016-03-15 23:10:59 +01001187 */
1188 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001189check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001190{
1191 timer_T *timer;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001192 timer_T *timer_next;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001193 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001194 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001195 proftime_T now;
1196 int did_one = FALSE;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001197 long current_id = last_timer_id;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001198# ifdef WIN3264
1199 LARGE_INTEGER fr;
1200
Bram Moolenaarc4f83382017-07-07 14:50:44 +02001201 /* Don't run any timers while exiting. */
1202 if (exiting)
1203 return next_due;
1204
Bram Moolenaar975b5272016-03-15 23:10:59 +01001205 QueryPerformanceFrequency(&fr);
1206# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001207 profile_start(&now);
1208 for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001209 {
Bram Moolenaar75537a92016-09-05 22:45:28 +02001210 timer_next = timer->tr_next;
Bram Moolenaar417ccd72016-09-01 21:26:20 +02001211
Bram Moolenaar75537a92016-09-05 22:45:28 +02001212 if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
1213 continue;
1214 this_due = GET_TIMEDIFF(timer, now);
1215 if (this_due <= 1)
1216 {
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001217 int save_timer_busy = timer_busy;
1218 int save_vgetc_busy = vgetc_busy;
1219
1220 timer_busy = timer_busy > 0 || vgetc_busy > 0;
1221 vgetc_busy = 0;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001222 timer->tr_firing = TRUE;
1223 timer_callback(timer);
1224 timer->tr_firing = FALSE;
1225 timer_next = timer->tr_next;
1226 did_one = TRUE;
Bram Moolenaar1e8e1452017-06-24 16:03:06 +02001227 timer_busy = save_timer_busy;
1228 vgetc_busy = save_vgetc_busy;
Bram Moolenaar75537a92016-09-05 22:45:28 +02001229
1230 /* Only fire the timer again if it repeats and stop_timer() wasn't
1231 * called while inside the callback (tr_id == -1). */
1232 if (timer->tr_repeat != 0 && timer->tr_id != -1)
1233 {
1234 profile_setlimit(timer->tr_interval, &timer->tr_due);
1235 this_due = GET_TIMEDIFF(timer, now);
1236 if (this_due < 1)
1237 this_due = 1;
1238 if (timer->tr_repeat > 0)
1239 --timer->tr_repeat;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001240 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001241 else
1242 {
1243 this_due = -1;
1244 remove_timer(timer);
1245 free_timer(timer);
1246 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001247 }
Bram Moolenaar75537a92016-09-05 22:45:28 +02001248 if (this_due > 0 && (next_due == -1 || next_due > this_due))
1249 next_due = this_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001250 }
1251
1252 if (did_one)
1253 redraw_after_callback();
1254
Bram Moolenaar75537a92016-09-05 22:45:28 +02001255 return current_id != last_timer_id ? 1 : next_due;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001256}
1257
1258/*
1259 * Find a timer by ID. Returns NULL if not found;
1260 */
1261 timer_T *
Bram Moolenaar75537a92016-09-05 22:45:28 +02001262find_timer(long id)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001263{
1264 timer_T *timer;
1265
Bram Moolenaar75537a92016-09-05 22:45:28 +02001266 if (id >= 0)
1267 {
1268 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1269 if (timer->tr_id == id)
1270 return timer;
1271 }
1272 return NULL;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001273}
1274
1275
1276/*
1277 * Stop a timer and delete it.
1278 */
1279 void
1280stop_timer(timer_T *timer)
1281{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001282 if (timer->tr_firing)
1283 /* Free the timer after the callback returns. */
1284 timer->tr_id = -1;
1285 else
1286 {
1287 remove_timer(timer);
1288 free_timer(timer);
1289 }
Bram Moolenaar975b5272016-03-15 23:10:59 +01001290}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001291
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001292 void
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001293stop_all_timers(void)
1294{
Bram Moolenaar75537a92016-09-05 22:45:28 +02001295 timer_T *timer;
1296 timer_T *timer_next;
1297
1298 for (timer = first_timer; timer != NULL; timer = timer_next)
1299 {
1300 timer_next = timer->tr_next;
1301 stop_timer(timer);
1302 }
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001303}
1304
1305 void
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001306add_timer_info(typval_T *rettv, timer_T *timer)
1307{
1308 list_T *list = rettv->vval.v_list;
1309 dict_T *dict = dict_alloc();
1310 dictitem_T *di;
1311 long remaining;
1312 proftime_T now;
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001313# ifdef WIN3264
1314 LARGE_INTEGER fr;
1315#endif
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001316
1317 if (dict == NULL)
1318 return;
1319 list_append_dict(list, dict);
1320
Bram Moolenaar75537a92016-09-05 22:45:28 +02001321 dict_add_nr_str(dict, "id", timer->tr_id, NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001322 dict_add_nr_str(dict, "time", (long)timer->tr_interval, NULL);
1323
1324 profile_start(&now);
1325# ifdef WIN3264
Bram Moolenaar00ff3802016-08-06 22:27:28 +02001326 QueryPerformanceFrequency(&fr);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001327# endif
Bram Moolenaar75537a92016-09-05 22:45:28 +02001328 remaining = GET_TIMEDIFF(timer, now);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001329 dict_add_nr_str(dict, "remaining", (long)remaining, NULL);
1330
1331 dict_add_nr_str(dict, "repeat",
1332 (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1), NULL);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02001333 dict_add_nr_str(dict, "paused", (long)(timer->tr_paused), NULL);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001334
1335 di = dictitem_alloc((char_u *)"callback");
1336 if (di != NULL)
1337 {
1338 if (dict_add(dict, di) == FAIL)
1339 vim_free(di);
1340 else if (timer->tr_partial != NULL)
1341 {
1342 di->di_tv.v_type = VAR_PARTIAL;
1343 di->di_tv.vval.v_partial = timer->tr_partial;
1344 ++timer->tr_partial->pt_refcount;
1345 }
1346 else
1347 {
1348 di->di_tv.v_type = VAR_FUNC;
1349 di->di_tv.vval.v_string = vim_strsave(timer->tr_callback);
1350 }
1351 di->di_tv.v_lock = 0;
1352 }
1353}
1354
1355 void
1356add_timer_info_all(typval_T *rettv)
1357{
1358 timer_T *timer;
1359
1360 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
Bram Moolenaar75537a92016-09-05 22:45:28 +02001361 if (timer->tr_id != -1)
1362 add_timer_info(rettv, timer);
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02001363}
1364
Bram Moolenaare3188e22016-05-31 21:13:04 +02001365/*
1366 * Mark references in partials of timers.
1367 */
1368 int
1369set_ref_in_timer(int copyID)
1370{
1371 int abort = FALSE;
1372 timer_T *timer;
1373 typval_T tv;
1374
1375 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1376 {
Bram Moolenaar1e96d9b2016-07-29 22:15:09 +02001377 if (timer->tr_partial != NULL)
1378 {
1379 tv.v_type = VAR_PARTIAL;
1380 tv.vval.v_partial = timer->tr_partial;
1381 }
1382 else
1383 {
1384 tv.v_type = VAR_FUNC;
1385 tv.vval.v_string = timer->tr_callback;
1386 }
Bram Moolenaare3188e22016-05-31 21:13:04 +02001387 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1388 }
1389 return abort;
1390}
Bram Moolenaar623e2632016-07-30 22:47:56 +02001391
1392# if defined(EXITFREE) || defined(PROTO)
1393 void
1394timer_free_all()
1395{
1396 timer_T *timer;
1397
1398 while (first_timer != NULL)
1399 {
1400 timer = first_timer;
1401 remove_timer(timer);
1402 free_timer(timer);
1403 }
1404}
1405# endif
Bram Moolenaar975b5272016-03-15 23:10:59 +01001406# endif
1407
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001408#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1409# if defined(HAVE_MATH_H)
1410# include <math.h>
1411# endif
1412
1413/*
1414 * Divide the time "tm" by "count" and store in "tm2".
1415 */
1416 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001417profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001418{
1419 if (count == 0)
1420 profile_zero(tm2);
1421 else
1422 {
1423# ifdef WIN3264
1424 tm2->QuadPart = tm->QuadPart / count;
1425# else
1426 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1427
1428 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001429 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001430# endif
1431 }
1432}
1433#endif
1434
Bram Moolenaar76929292008-01-06 19:07:36 +00001435# if defined(FEAT_PROFILE) || defined(PROTO)
1436/*
1437 * Functions for profiling.
1438 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001439static void script_do_profile(scriptitem_T *si);
1440static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001441static proftime_T prof_wait_time;
1442
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001443/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001444 * Add the time "tm2" to "tm".
1445 */
1446 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001447profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001448{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001449# ifdef WIN3264
1450 tm->QuadPart += tm2->QuadPart;
1451# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001452 tm->tv_usec += tm2->tv_usec;
1453 tm->tv_sec += tm2->tv_sec;
1454 if (tm->tv_usec >= 1000000)
1455 {
1456 tm->tv_usec -= 1000000;
1457 ++tm->tv_sec;
1458 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001459# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001460}
1461
1462/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001463 * Add the "self" time from the total time and the children's time.
1464 */
1465 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001466profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001467{
1468 /* Check that the result won't be negative. Can happen with recursive
1469 * calls. */
1470#ifdef WIN3264
1471 if (total->QuadPart <= children->QuadPart)
1472 return;
1473#else
1474 if (total->tv_sec < children->tv_sec
1475 || (total->tv_sec == children->tv_sec
1476 && total->tv_usec <= children->tv_usec))
1477 return;
1478#endif
1479 profile_add(self, total);
1480 profile_sub(self, children);
1481}
1482
1483/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001484 * Get the current waittime.
1485 */
1486 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001487profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001488{
1489 *tm = prof_wait_time;
1490}
1491
1492/*
1493 * Subtract the passed waittime since "tm" from "tma".
1494 */
1495 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001496profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001497{
1498 proftime_T tm3 = prof_wait_time;
1499
1500 profile_sub(&tm3, tm);
1501 profile_sub(tma, &tm3);
1502}
1503
1504/*
1505 * Return TRUE if "tm1" and "tm2" are equal.
1506 */
1507 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001508profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001509{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001510# ifdef WIN3264
1511 return (tm1->QuadPart == tm2->QuadPart);
1512# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001513 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001514# endif
1515}
1516
1517/*
1518 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1519 */
1520 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001521profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001522{
1523# ifdef WIN3264
1524 return (int)(tm2->QuadPart - tm1->QuadPart);
1525# else
1526 if (tm1->tv_sec == tm2->tv_sec)
1527 return tm2->tv_usec - tm1->tv_usec;
1528 return tm2->tv_sec - tm1->tv_sec;
1529# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001530}
1531
Bram Moolenaar05159a02005-02-26 23:04:13 +00001532static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001533static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001534
1535/*
1536 * ":profile cmd args"
1537 */
1538 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001539ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001540{
1541 char_u *e;
1542 int len;
1543
1544 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001545 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001546 e = skipwhite(e);
1547
1548 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1549 {
1550 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001551 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001552 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001553 profile_zero(&prof_wait_time);
1554 set_vim_var_nr(VV_PROFILING, 1L);
1555 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001556 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001557 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001558 else if (STRCMP(eap->arg, "pause") == 0)
1559 {
1560 if (do_profiling == PROF_YES)
1561 profile_start(&pause_time);
1562 do_profiling = PROF_PAUSED;
1563 }
1564 else if (STRCMP(eap->arg, "continue") == 0)
1565 {
1566 if (do_profiling == PROF_PAUSED)
1567 {
1568 profile_end(&pause_time);
1569 profile_add(&prof_wait_time, &pause_time);
1570 }
1571 do_profiling = PROF_YES;
1572 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001573 else
1574 {
1575 /* The rest is similar to ":breakadd". */
1576 ex_breakadd(eap);
1577 }
1578}
1579
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001580/* Command line expansion for :profile. */
1581static enum
1582{
1583 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001584 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001585} pexpand_what;
1586
1587static char *pexpand_cmds[] = {
1588 "start",
1589#define PROFCMD_START 0
1590 "pause",
1591#define PROFCMD_PAUSE 1
1592 "continue",
1593#define PROFCMD_CONTINUE 2
1594 "func",
1595#define PROFCMD_FUNC 3
1596 "file",
1597#define PROFCMD_FILE 4
1598 NULL
1599#define PROFCMD_LAST 5
1600};
1601
1602/*
1603 * Function given to ExpandGeneric() to obtain the profile command
1604 * specific expansion.
1605 */
1606 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001607get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001608{
1609 switch (pexpand_what)
1610 {
1611 case PEXP_SUBCMD:
1612 return (char_u *)pexpand_cmds[idx];
1613 /* case PEXP_FUNC: TODO */
1614 default:
1615 return NULL;
1616 }
1617}
1618
1619/*
1620 * Handle command line completion for :profile command.
1621 */
1622 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001623set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001624{
1625 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001626
1627 /* Default: expand subcommands. */
1628 xp->xp_context = EXPAND_PROFILE;
1629 pexpand_what = PEXP_SUBCMD;
1630 xp->xp_pattern = arg;
1631
1632 end_subcmd = skiptowhite(arg);
1633 if (*end_subcmd == NUL)
1634 return;
1635
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001636 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001637 {
1638 xp->xp_context = EXPAND_FILES;
1639 xp->xp_pattern = skipwhite(end_subcmd);
1640 return;
1641 }
1642
1643 /* TODO: expand function names after "func" */
1644 xp->xp_context = EXPAND_NOTHING;
1645}
1646
Bram Moolenaar05159a02005-02-26 23:04:13 +00001647/*
1648 * Dump the profiling info.
1649 */
1650 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001651profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001652{
1653 FILE *fd;
1654
1655 if (profile_fname != NULL)
1656 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001657 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001658 if (fd == NULL)
1659 EMSG2(_(e_notopen), profile_fname);
1660 else
1661 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001662 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001663 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001664 fclose(fd);
1665 }
1666 }
1667}
1668
1669/*
1670 * Start profiling script "fp".
1671 */
1672 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001673script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001674{
1675 si->sn_pr_count = 0;
1676 profile_zero(&si->sn_pr_total);
1677 profile_zero(&si->sn_pr_self);
1678
1679 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1680 si->sn_prl_idx = -1;
1681 si->sn_prof_on = TRUE;
1682 si->sn_pr_nest = 0;
1683}
1684
1685/*
1686 * save time when starting to invoke another script or function.
1687 */
1688 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001689script_prof_save(
1690 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001691{
1692 scriptitem_T *si;
1693
1694 if (current_SID > 0 && current_SID <= script_items.ga_len)
1695 {
1696 si = &SCRIPT_ITEM(current_SID);
1697 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1698 profile_start(&si->sn_pr_child);
1699 }
1700 profile_get_wait(tm);
1701}
1702
1703/*
1704 * Count time spent in children after invoking another script or function.
1705 */
1706 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001707script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001708{
1709 scriptitem_T *si;
1710
1711 if (current_SID > 0 && current_SID <= script_items.ga_len)
1712 {
1713 si = &SCRIPT_ITEM(current_SID);
1714 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1715 {
1716 profile_end(&si->sn_pr_child);
1717 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1718 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1719 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1720 }
1721 }
1722}
1723
1724static proftime_T inchar_time;
1725
1726/*
1727 * Called when starting to wait for the user to type a character.
1728 */
1729 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001730prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001731{
1732 profile_start(&inchar_time);
1733}
1734
1735/*
1736 * Called when finished waiting for the user to type a character.
1737 */
1738 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001739prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001740{
1741 profile_end(&inchar_time);
1742 profile_add(&prof_wait_time, &inchar_time);
1743}
1744
1745/*
1746 * Dump the profiling results for all scripts in file "fd".
1747 */
1748 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001749script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001750{
1751 int id;
1752 scriptitem_T *si;
1753 int i;
1754 FILE *sfd;
1755 sn_prl_T *pp;
1756
1757 for (id = 1; id <= script_items.ga_len; ++id)
1758 {
1759 si = &SCRIPT_ITEM(id);
1760 if (si->sn_prof_on)
1761 {
1762 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1763 if (si->sn_pr_count == 1)
1764 fprintf(fd, "Sourced 1 time\n");
1765 else
1766 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1767 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1768 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1769 fprintf(fd, "\n");
1770 fprintf(fd, "count total (s) self (s)\n");
1771
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001772 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001773 if (sfd == NULL)
1774 fprintf(fd, "Cannot open file!\n");
1775 else
1776 {
1777 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1778 {
1779 if (vim_fgets(IObuff, IOSIZE, sfd))
1780 break;
1781 pp = &PRL_ITEM(si, i);
1782 if (pp->snp_count > 0)
1783 {
1784 fprintf(fd, "%5d ", pp->snp_count);
1785 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1786 fprintf(fd, " ");
1787 else
1788 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1789 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1790 }
1791 else
1792 fprintf(fd, " ");
1793 fprintf(fd, "%s", IObuff);
1794 }
1795 fclose(sfd);
1796 }
1797 fprintf(fd, "\n");
1798 }
1799 }
1800}
1801
1802/*
1803 * Return TRUE when a function defined in the current script should be
1804 * profiled.
1805 */
1806 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001807prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001808{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001809 if (current_SID > 0)
1810 return SCRIPT_ITEM(current_SID).sn_pr_force;
1811 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001812}
1813
1814# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815#endif
1816
1817/*
1818 * If 'autowrite' option set, try to write the file.
1819 * Careful: autocommands may make "buf" invalid!
1820 *
1821 * return FAIL for failure, OK otherwise
1822 */
1823 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001824autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001825{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001826 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001827 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001828
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829 if (!(p_aw || p_awa) || !p_write
1830#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001831 /* never autowrite a "nofile" or "nowrite" buffer */
1832 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001833#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001834 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001836 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001837 r = buf_write_all(buf, forceit);
1838
1839 /* Writing may succeed but the buffer still changed, e.g., when there is a
1840 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001841 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001842 r = FAIL;
1843 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844}
1845
1846/*
1847 * flush all buffers, except the ones that are readonly
1848 */
1849 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001850autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001851{
1852 buf_T *buf;
1853
1854 if (!(p_aw || p_awa) || !p_write)
1855 return;
Bram Moolenaar29323592016-07-24 22:04:11 +02001856 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 if (bufIsChanged(buf) && !buf->b_p_ro)
1858 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001859#ifdef FEAT_AUTOCMD
1860 bufref_T bufref;
1861
1862 set_bufref(&bufref, buf);
1863#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864 (void)buf_write_all(buf, FALSE);
1865#ifdef FEAT_AUTOCMD
1866 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001867 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001868 buf = firstbuf;
1869#endif
1870 }
1871}
1872
1873/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001874 * Return TRUE if buffer was changed and cannot be abandoned.
1875 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001878check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001880 int forceit = (flags & CCGD_FORCEIT);
1881#ifdef FEAT_AUTOCMD
1882 bufref_T bufref;
1883
1884 set_bufref(&bufref, buf);
1885#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001886
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 if ( !forceit
1888 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001889 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1890 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001891 {
1892#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1893 if ((p_confirm || cmdmod.confirm) && p_write)
1894 {
1895 buf_T *buf2;
1896 int count = 0;
1897
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001898 if (flags & CCGD_ALLBUF)
Bram Moolenaar29323592016-07-24 22:04:11 +02001899 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 if (bufIsChanged(buf2)
1901 && (buf2->b_ffname != NULL
1902# ifdef FEAT_BROWSE
1903 || cmdmod.browse
1904# endif
1905 ))
1906 ++count;
1907# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001908 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001909 /* Autocommand deleted buffer, oops! It's not changed now. */
1910 return FALSE;
1911# endif
1912 dialog_changed(buf, count > 1);
1913# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001914 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915 /* Autocommand deleted buffer, oops! It's not changed now. */
1916 return FALSE;
1917# endif
1918 return bufIsChanged(buf);
1919 }
1920#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001921 if (flags & CCGD_EXCMD)
1922 EMSG(_(e_nowrtmsg));
1923 else
1924 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001925 return TRUE;
1926 }
1927 return FALSE;
1928}
1929
1930#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1931
1932#if defined(FEAT_BROWSE) || defined(PROTO)
1933/*
1934 * When wanting to write a file without a file name, ask the user for a name.
1935 */
1936 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001937browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938{
1939 if (buf->b_fname == NULL)
1940 {
1941 char_u *fname;
1942
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001943 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1944 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 if (fname != NULL)
1946 {
1947 if (setfname(buf, fname, NULL, TRUE) == OK)
1948 buf->b_flags |= BF_NOTEDITED;
1949 vim_free(fname);
1950 }
1951 }
1952}
1953#endif
1954
1955/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001956 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 * Must check 'write' option first!
1958 */
1959 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001960dialog_changed(
1961 buf_T *buf,
1962 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001964 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 int ret;
1966 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001967 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001969 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 (buf->b_fname != NULL) ?
1971 buf->b_fname : (char_u *)_("Untitled"));
1972 if (checkall)
1973 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1974 else
1975 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1976
Bram Moolenaar8218f602012-04-25 17:32:18 +02001977 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1978 * function. */
1979 ea.append = ea.forceit = FALSE;
1980
Bram Moolenaar071d4272004-06-13 20:20:40 +00001981 if (ret == VIM_YES)
1982 {
1983#ifdef FEAT_BROWSE
1984 /* May get file name, when there is none */
1985 browse_save_fname(buf);
1986#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001987 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1988 buf->b_fname, buf->b_ffname, FALSE) == OK)
1989 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001990 (void)buf_write_all(buf, FALSE);
1991 }
1992 else if (ret == VIM_NO)
1993 {
1994 unchanged(buf, TRUE);
1995 }
1996 else if (ret == VIM_ALL)
1997 {
1998 /*
1999 * Write all modified files that can be written.
2000 * Skip readonly buffers, these need to be confirmed
2001 * individually.
2002 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002003 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004 {
2005 if (bufIsChanged(buf2)
2006 && (buf2->b_ffname != NULL
2007#ifdef FEAT_BROWSE
2008 || cmdmod.browse
2009#endif
2010 )
2011 && !buf2->b_p_ro)
2012 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002013#ifdef FEAT_AUTOCMD
2014 bufref_T bufref;
2015
2016 set_bufref(&bufref, buf2);
2017#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002018#ifdef FEAT_BROWSE
2019 /* May get file name, when there is none */
2020 browse_save_fname(buf2);
2021#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02002022 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
2023 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
2024 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025 (void)buf_write_all(buf2, FALSE);
2026#ifdef FEAT_AUTOCMD
2027 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002028 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 buf2 = firstbuf;
2030#endif
2031 }
2032 }
2033 }
2034 else if (ret == VIM_DISCARDALL)
2035 {
2036 /*
2037 * mark all buffers as unchanged
2038 */
Bram Moolenaar29323592016-07-24 22:04:11 +02002039 FOR_ALL_BUFFERS(buf2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040 unchanged(buf2, TRUE);
2041 }
2042}
2043#endif
2044
2045/*
2046 * Return TRUE if the buffer "buf" can be abandoned, either by making it
2047 * hidden, autowriting it or unloading it.
2048 */
2049 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002050can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051{
2052 return ( P_HID(buf)
2053 || !bufIsChanged(buf)
2054 || buf->b_nwindows > 1
2055 || autowrite(buf, forceit) == OK
2056 || forceit);
2057}
2058
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002059static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002060
2061/*
2062 * Add a buffer number to "bufnrs", unless it's already there.
2063 */
2064 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002065add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002066{
2067 int i;
2068
2069 for (i = 0; i < *bufnump; ++i)
2070 if (bufnrs[i] == nr)
2071 return;
2072 bufnrs[*bufnump] = nr;
2073 *bufnump = *bufnump + 1;
2074}
2075
Bram Moolenaar071d4272004-06-13 20:20:40 +00002076/*
2077 * Return TRUE if any buffer was changed and cannot be abandoned.
2078 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01002079 * When "unload" is true the current buffer is unloaded instead of making it
2080 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 */
2082 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002083check_changed_any(
2084 int hidden, /* Only check hidden buffers */
2085 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002087 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 buf_T *buf;
2089 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002090 int i;
2091 int bufnum = 0;
2092 int bufcount = 0;
2093 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002095 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002096 win_T *wp;
2097#endif
2098
Bram Moolenaar29323592016-07-24 22:04:11 +02002099 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002100 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002102 if (bufcount == 0)
2103 return FALSE;
2104
2105 bufnrs = (int *)alloc(sizeof(int) * bufcount);
2106 if (bufnrs == NULL)
2107 return FALSE;
2108
2109 /* curbuf */
2110 bufnrs[bufnum++] = curbuf->b_fnum;
2111#ifdef FEAT_WINDOWS
2112 /* buf in curtab */
2113 FOR_ALL_WINDOWS(wp)
2114 if (wp->w_buffer != curbuf)
2115 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2116
2117 /* buf in other tab */
Bram Moolenaar29323592016-07-24 22:04:11 +02002118 FOR_ALL_TABPAGES(tp)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002119 if (tp != curtab)
2120 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
2121 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
2122#endif
2123 /* any other buf */
Bram Moolenaar29323592016-07-24 22:04:11 +02002124 FOR_ALL_BUFFERS(buf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002125 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
2126
2127 for (i = 0; i < bufnum; ++i)
2128 {
2129 buf = buflist_findnr(bufnrs[i]);
2130 if (buf == NULL)
2131 continue;
2132 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2133 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002134 bufref_T bufref;
2135
2136 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002137 /* Try auto-writing the buffer. If this fails but the buffer no
2138 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002139 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2140 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002141 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002142 break; /* didn't save - still changes */
2143 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144 }
2145
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002146 if (i >= bufnum)
2147 goto theend;
2148
2149 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002150 exiting = FALSE;
2151#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2152 /*
2153 * When ":confirm" used, don't give an error message.
2154 */
2155 if (!(p_confirm || cmdmod.confirm))
2156#endif
2157 {
2158 /* There must be a wait_return for this message, do_buffer()
2159 * may cause a redraw. But wait_return() is a no-op when vgetc()
2160 * is busy (Quit used from window menu), then make sure we don't
2161 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002162 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002163 {
2164 msg_row = cmdline_row;
2165 msg_col = 0;
2166 msg_didout = FALSE;
2167 }
2168 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002169 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170 {
2171 save = no_wait_return;
2172 no_wait_return = FALSE;
2173 wait_return(FALSE);
2174 no_wait_return = save;
2175 }
2176 }
2177
2178#ifdef FEAT_WINDOWS
2179 /* Try to find a window that contains the buffer. */
2180 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002181 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182 if (wp->w_buffer == buf)
2183 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002184# ifdef FEAT_AUTOCMD
2185 bufref_T bufref;
2186
2187 set_bufref(&bufref, buf);
2188# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002189 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190# ifdef FEAT_AUTOCMD
2191 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002192 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002193 {
2194 goto theend;
2195 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002196# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002197 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002198 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002199buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200#endif
2201
2202 /* Open the changed buffer in the current window. */
2203 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002204 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002206theend:
2207 vim_free(bufnrs);
2208 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209}
2210
2211/*
2212 * return FAIL if there is no file name, OK if there is one
2213 * give error message for FAIL
2214 */
2215 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002216check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217{
2218 if (curbuf->b_ffname == NULL)
2219 {
2220 EMSG(_(e_noname));
2221 return FAIL;
2222 }
2223 return OK;
2224}
2225
2226/*
2227 * flush the contents of a buffer, unless it has no file name
2228 *
2229 * return FAIL for failure, OK otherwise
2230 */
2231 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002232buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233{
2234 int retval;
2235#ifdef FEAT_AUTOCMD
2236 buf_T *old_curbuf = curbuf;
2237#endif
2238
2239 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2240 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2241 FALSE, forceit, TRUE, FALSE));
2242#ifdef FEAT_AUTOCMD
2243 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002244 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01002245 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002247 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248#endif
2249 return retval;
2250}
2251
2252/*
2253 * Code to handle the argument list.
2254 */
2255
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002256static char_u *do_one_arg(char_u *str);
2257static int do_arglist(char_u *str, int what, int after);
2258static void alist_check_arg_idx(void);
2259static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002260#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002261static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002262#endif
2263#define AL_SET 1
2264#define AL_ADD 2
2265#define AL_DEL 3
2266
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002268 * Isolate one argument, taking backticks.
2269 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 * Return a pointer to the start of the next argument.
2271 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002272 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002273do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274{
2275 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 int inbacktick;
2277
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278 inbacktick = FALSE;
2279 for (p = str; *str; ++str)
2280 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002281 /* When the backslash is used for escaping the special meaning of a
2282 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 if (rem_backslash(str))
2284 {
2285 *p++ = *str++;
2286 *p++ = *str;
2287 }
2288 else
2289 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002290 /* An item ends at a space not in backticks */
2291 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002293 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002295 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 }
2297 }
2298 str = skipwhite(str);
2299 *p = NUL;
2300
2301 return str;
2302}
2303
Bram Moolenaar86b68352004-12-27 21:59:20 +00002304/*
2305 * Separate the arguments in "str" and return a list of pointers in the
2306 * growarray "gap".
2307 */
2308 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002309get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002310{
2311 ga_init2(gap, (int)sizeof(char_u *), 20);
2312 while (*str != NUL)
2313 {
2314 if (ga_grow(gap, 1) == FAIL)
2315 {
2316 ga_clear(gap);
2317 return FAIL;
2318 }
2319 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2320
2321 /* Isolate one argument, change it in-place, put a NUL after it. */
2322 str = do_one_arg(str);
2323 }
2324 return OK;
2325}
2326
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002327#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002328/*
2329 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002330 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002331 * Return FAIL or OK.
2332 */
2333 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002334get_arglist_exp(
2335 char_u *str,
2336 int *fcountp,
2337 char_u ***fnamesp,
2338 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002339{
2340 garray_T ga;
2341 int i;
2342
2343 if (get_arglist(&ga, str) == FAIL)
2344 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002345 if (wig == TRUE)
2346 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2347 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2348 else
2349 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2350 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2351
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002352 ga_clear(&ga);
2353 return i;
2354}
2355#endif
2356
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2358/*
2359 * Redefine the argument list.
2360 */
2361 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002362set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363{
2364 do_arglist(str, AL_SET, 0);
2365}
2366#endif
2367
2368/*
2369 * "what" == AL_SET: Redefine the argument list to 'str'.
2370 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2371 * "what" == AL_DEL: remove files in 'str' from the argument list.
2372 *
2373 * Return FAIL for failure, OK otherwise.
2374 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002376do_arglist(
2377 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002378 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002379 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380{
2381 garray_T new_ga;
2382 int exp_count;
2383 char_u **exp_files;
2384 int i;
2385#ifdef FEAT_LISTCMDS
2386 char_u *p;
2387 int match;
2388#endif
2389
2390 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002391 * Set default argument for ":argadd" command.
2392 */
2393 if (what == AL_ADD && *str == NUL)
2394 {
2395 if (curbuf->b_ffname == NULL)
2396 return FAIL;
2397 str = curbuf->b_fname;
2398 }
2399
2400 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002401 * Collect all file name arguments in "new_ga".
2402 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002403 if (get_arglist(&new_ga, str) == FAIL)
2404 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405
2406#ifdef FEAT_LISTCMDS
2407 if (what == AL_DEL)
2408 {
2409 regmatch_T regmatch;
2410 int didone;
2411
2412 /*
2413 * Delete the items: use each item as a regexp and find a match in the
2414 * argument list.
2415 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002416 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2418 {
2419 p = ((char_u **)new_ga.ga_data)[i];
2420 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2421 if (p == NULL)
2422 break;
2423 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2424 if (regmatch.regprog == NULL)
2425 {
2426 vim_free(p);
2427 break;
2428 }
2429
2430 didone = FALSE;
2431 for (match = 0; match < ARGCOUNT; ++match)
2432 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2433 (colnr_T)0))
2434 {
2435 didone = TRUE;
2436 vim_free(ARGLIST[match].ae_fname);
2437 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2438 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2439 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 if (curwin->w_arg_idx > match)
2441 --curwin->w_arg_idx;
2442 --match;
2443 }
2444
Bram Moolenaar473de612013-06-08 18:19:48 +02002445 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446 vim_free(p);
2447 if (!didone)
2448 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2449 }
2450 ga_clear(&new_ga);
2451 }
2452 else
2453#endif
2454 {
2455 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2456 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2457 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002458 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 {
2460 EMSG(_(e_nomatch));
2461 return FAIL;
2462 }
2463
2464#ifdef FEAT_LISTCMDS
2465 if (what == AL_ADD)
2466 {
2467 (void)alist_add_list(exp_count, exp_files, after);
2468 vim_free(exp_files);
2469 }
2470 else /* what == AL_SET */
2471#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002472 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 }
2474
2475 alist_check_arg_idx();
2476
2477 return OK;
2478}
2479
2480/*
2481 * Check the validity of the arg_idx for each other window.
2482 */
2483 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002484alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485{
2486#ifdef FEAT_WINDOWS
2487 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002488 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002489
Bram Moolenaarf740b292006-02-16 22:11:02 +00002490 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491 if (win->w_alist == curwin->w_alist)
2492 check_arg_idx(win);
2493#else
2494 check_arg_idx(curwin);
2495#endif
2496}
2497
2498/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002499 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002500 * index.
2501 */
2502 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002503editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002504{
2505 return !(win->w_arg_idx >= WARGCOUNT(win)
2506 || (win->w_buffer->b_fnum
2507 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2508 && (win->w_buffer->b_ffname == NULL
2509 || !(fullpathcmp(
2510 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2511 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2512}
2513
2514/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 * Check if window "win" is editing the w_arg_idx file in its argument list.
2516 */
2517 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002518check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002520 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002521 {
2522 /* We are not editing the current entry in the argument list.
2523 * Set "arg_had_last" if we are editing the last one. */
2524 win->w_arg_idx_invalid = TRUE;
2525 if (win->w_arg_idx != WARGCOUNT(win) - 1
2526 && arg_had_last == FALSE
2527#ifdef FEAT_WINDOWS
2528 && ALIST(win) == &global_alist
2529#endif
2530 && GARGCOUNT > 0
2531 && win->w_arg_idx < GARGCOUNT
2532 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2533 || (win->w_buffer->b_ffname != NULL
2534 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2535 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2536 arg_had_last = TRUE;
2537 }
2538 else
2539 {
2540 /* We are editing the current entry in the argument list.
2541 * Set "arg_had_last" if it's also the last one */
2542 win->w_arg_idx_invalid = FALSE;
2543 if (win->w_arg_idx == WARGCOUNT(win) - 1
2544#ifdef FEAT_WINDOWS
2545 && win->w_alist == &global_alist
2546#endif
2547 )
2548 arg_had_last = TRUE;
2549 }
2550}
2551
2552/*
2553 * ":args", ":argslocal" and ":argsglobal".
2554 */
2555 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002556ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557{
2558 int i;
2559
2560 if (eap->cmdidx != CMD_args)
2561 {
2562#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2563 alist_unlink(ALIST(curwin));
2564 if (eap->cmdidx == CMD_argglobal)
2565 ALIST(curwin) = &global_alist;
2566 else /* eap->cmdidx == CMD_arglocal */
2567 alist_new();
2568#else
2569 ex_ni(eap);
2570 return;
2571#endif
2572 }
2573
2574 if (!ends_excmd(*eap->arg))
2575 {
2576 /*
2577 * ":args file ..": define new argument list, handle like ":next"
2578 * Also for ":argslocal file .." and ":argsglobal file ..".
2579 */
2580 ex_next(eap);
2581 }
2582 else
2583#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2584 if (eap->cmdidx == CMD_args)
2585#endif
2586 {
2587 /*
2588 * ":args": list arguments.
2589 */
2590 if (ARGCOUNT > 0)
2591 {
2592 /* Overwrite the command, for a short list there is no scrolling
2593 * required and no wait_return(). */
2594 gotocmdline(TRUE);
2595 for (i = 0; i < ARGCOUNT; ++i)
2596 {
2597 if (i == curwin->w_arg_idx)
2598 msg_putchar('[');
2599 msg_outtrans(alist_name(&ARGLIST[i]));
2600 if (i == curwin->w_arg_idx)
2601 msg_putchar(']');
2602 msg_putchar(' ');
2603 }
2604 }
2605 }
2606#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2607 else if (eap->cmdidx == CMD_arglocal)
2608 {
2609 garray_T *gap = &curwin->w_alist->al_ga;
2610
2611 /*
2612 * ":argslocal": make a local copy of the global argument list.
2613 */
2614 if (ga_grow(gap, GARGCOUNT) == OK)
2615 for (i = 0; i < GARGCOUNT; ++i)
2616 if (GARGLIST[i].ae_fname != NULL)
2617 {
2618 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2619 vim_strsave(GARGLIST[i].ae_fname);
2620 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2621 GARGLIST[i].ae_fnum;
2622 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 }
2624 }
2625#endif
2626}
2627
2628/*
2629 * ":previous", ":sprevious", ":Next" and ":sNext".
2630 */
2631 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002632ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633{
2634 /* If past the last one already, go to the last one. */
2635 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2636 do_argfile(eap, ARGCOUNT - 1);
2637 else
2638 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2639}
2640
2641/*
2642 * ":rewind", ":first", ":sfirst" and ":srewind".
2643 */
2644 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002645ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002646{
2647 do_argfile(eap, 0);
2648}
2649
2650/*
2651 * ":last" and ":slast".
2652 */
2653 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002654ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002655{
2656 do_argfile(eap, ARGCOUNT - 1);
2657}
2658
2659/*
2660 * ":argument" and ":sargument".
2661 */
2662 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002663ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664{
2665 int i;
2666
2667 if (eap->addr_count > 0)
2668 i = eap->line2 - 1;
2669 else
2670 i = curwin->w_arg_idx;
2671 do_argfile(eap, i);
2672}
2673
2674/*
2675 * Edit file "argn" of the argument lists.
2676 */
2677 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002678do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679{
2680 int other;
2681 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002682 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683
2684 if (argn < 0 || argn >= ARGCOUNT)
2685 {
2686 if (ARGCOUNT <= 1)
2687 EMSG(_("E163: There is only one file to edit"));
2688 else if (argn < 0)
2689 EMSG(_("E164: Cannot go before first file"));
2690 else
2691 EMSG(_("E165: Cannot go beyond last file"));
2692 }
2693 else
2694 {
2695 setpcmark();
2696#ifdef FEAT_GUI
2697 need_mouse_correct = TRUE;
2698#endif
2699
2700#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002701 /* split window or create new tab page first */
2702 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 {
2704 if (win_split(0, 0) == FAIL)
2705 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002706 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 }
2708 else
2709#endif
2710 {
2711 /*
2712 * if 'hidden' set, only check for changed file when re-editing
2713 * the same buffer
2714 */
2715 other = TRUE;
2716 if (P_HID(curbuf))
2717 {
2718 p = fix_fname(alist_name(&ARGLIST[argn]));
2719 other = otherfile(p);
2720 vim_free(p);
2721 }
2722 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002723 && check_changed(curbuf, CCGD_AW
2724 | (other ? 0 : CCGD_MULTWIN)
2725 | (eap->forceit ? CCGD_FORCEIT : 0)
2726 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 return;
2728 }
2729
2730 curwin->w_arg_idx = argn;
2731 if (argn == ARGCOUNT - 1
2732#ifdef FEAT_WINDOWS
2733 && curwin->w_alist == &global_alist
2734#endif
2735 )
2736 arg_had_last = TRUE;
2737
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002738 /* Edit the file; always use the last known line number.
2739 * When it fails (e.g. Abort for already edited file) restore the
2740 * argument index. */
2741 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002742 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002743 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2744 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002745 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002747 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 setmark('\'');
2749 }
2750}
2751
2752/*
2753 * ":next", and commands that behave like it.
2754 */
2755 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002756ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002757{
2758 int i;
2759
2760 /*
2761 * check for changed buffer now, if this fails the argument list is not
2762 * redefined.
2763 */
2764 if ( P_HID(curbuf)
2765 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002766 || !check_changed(curbuf, CCGD_AW
2767 | (eap->forceit ? CCGD_FORCEIT : 0)
2768 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 {
2770 if (*eap->arg != NUL) /* redefine file list */
2771 {
2772 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2773 return;
2774 i = 0;
2775 }
2776 else
2777 i = curwin->w_arg_idx + (int)eap->line2;
2778 do_argfile(eap, i);
2779 }
2780}
2781
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002782#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783/*
2784 * ":argedit"
2785 */
2786 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002787ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788{
2789 int fnum;
2790 int i;
2791 char_u *s;
2792
2793 /* Add the argument to the buffer list and get the buffer number. */
2794 fnum = buflist_add(eap->arg, BLN_LISTED);
2795
2796 /* Check if this argument is already in the argument list. */
2797 for (i = 0; i < ARGCOUNT; ++i)
2798 if (ARGLIST[i].ae_fnum == fnum)
2799 break;
2800 if (i == ARGCOUNT)
2801 {
2802 /* Can't find it, add it to the argument list. */
2803 s = vim_strsave(eap->arg);
2804 if (s == NULL)
2805 return;
2806 i = alist_add_list(1, &s,
2807 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2808 if (i < 0)
2809 return;
2810 curwin->w_arg_idx = i;
2811 }
2812
2813 alist_check_arg_idx();
2814
2815 /* Edit the argument. */
2816 do_argfile(eap, i);
2817}
2818
2819/*
2820 * ":argadd"
2821 */
2822 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002823ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824{
2825 do_arglist(eap->arg, AL_ADD,
2826 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2827#ifdef FEAT_TITLE
2828 maketitle();
2829#endif
2830}
2831
2832/*
2833 * ":argdelete"
2834 */
2835 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002836ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837{
2838 int i;
2839 int n;
2840
2841 if (eap->addr_count > 0)
2842 {
2843 /* ":1,4argdel": Delete all arguments in the range. */
2844 if (eap->line2 > ARGCOUNT)
2845 eap->line2 = ARGCOUNT;
2846 n = eap->line2 - eap->line1 + 1;
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002847 if (*eap->arg != NUL)
2848 /* Can't have both a range and an argument. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002849 EMSG(_(e_invarg));
Bram Moolenaar69a92fb2017-03-09 15:58:30 +01002850 else if (n <= 0)
2851 {
2852 /* Don't give an error for ":%argdel" if the list is empty. */
2853 if (eap->line1 != 1 || eap->line2 != 0)
2854 EMSG(_(e_invrange));
2855 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856 else
2857 {
2858 for (i = eap->line1; i <= eap->line2; ++i)
2859 vim_free(ARGLIST[i - 1].ae_fname);
2860 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2861 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2862 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 if (curwin->w_arg_idx >= eap->line2)
2864 curwin->w_arg_idx -= n;
2865 else if (curwin->w_arg_idx > eap->line1)
2866 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002867 if (ARGCOUNT == 0)
2868 curwin->w_arg_idx = 0;
2869 else if (curwin->w_arg_idx >= ARGCOUNT)
2870 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 }
2872 }
2873 else if (*eap->arg == NUL)
2874 EMSG(_(e_argreq));
2875 else
2876 do_arglist(eap->arg, AL_DEL, 0);
2877#ifdef FEAT_TITLE
2878 maketitle();
2879#endif
2880}
2881
2882/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002883 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884 */
2885 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002886ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887{
2888 int i;
2889#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002890 win_T *wp;
2891 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002892#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002893 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002894 int next_fnum = 0;
2895#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2896 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002897#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002898 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002899#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002900 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002901 int qf_idx;
2902#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903
2904#ifndef FEAT_WINDOWS
2905 if (eap->cmdidx == CMD_windo)
2906 {
2907 ex_ni(eap);
2908 return;
2909 }
2910#endif
2911
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002912#ifndef FEAT_QUICKFIX
2913 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2914 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2915 {
2916 ex_ni(eap);
2917 return;
2918 }
2919#endif
2920
Bram Moolenaar071d4272004-06-13 20:20:40 +00002921#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002922 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002923 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2924 * great speed improvement. */
2925 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002927#ifdef FEAT_CLIPBOARD
2928 start_global_changes();
2929#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930
2931 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002932 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002933 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002934 || !check_changed(curbuf, CCGD_AW
2935 | (eap->forceit ? CCGD_FORCEIT : 0)
2936 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002937 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002939 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002941 wp = firstwin;
2942 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002944 switch (eap->cmdidx)
2945 {
2946#ifdef FEAT_WINDOWS
2947 case CMD_windo:
2948 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2949 i++;
2950 break;
2951 case CMD_tabdo:
2952 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2953 i++;
2954 break;
2955#endif
2956 case CMD_argdo:
2957 i = eap->line1 - 1;
2958 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002959 default:
2960 break;
2961 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002962 /* set pcmark now */
2963 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002964 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002965 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002966 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002967 || !buf->b_p_bl); buf = buf->b_next)
2968 if (buf->b_fnum > eap->line2)
2969 {
2970 buf = NULL;
2971 break;
2972 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002973 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002974 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002975 }
2976#ifdef FEAT_QUICKFIX
2977 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2978 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2979 {
2980 qf_size = qf_get_size(eap);
2981 if (qf_size <= 0 || eap->line1 > qf_size)
2982 buf = NULL;
2983 else
2984 {
2985 ex_cc(eap);
2986
2987 buf = curbuf;
2988 i = eap->line1 - 1;
2989 if (eap->addr_count <= 0)
2990 /* default is all the quickfix/location list entries */
2991 eap->line2 = qf_size;
2992 }
2993 }
2994#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995 else
2996 setpcmark();
2997 listcmd_busy = TRUE; /* avoids setting pcmark below */
2998
Bram Moolenaare25bb902015-02-27 20:33:37 +01002999 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 {
3001 if (eap->cmdidx == CMD_argdo)
3002 {
3003 /* go to argument "i" */
3004 if (i == ARGCOUNT)
3005 break;
3006 /* Don't call do_argfile() when already there, it will try
3007 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00003008 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003009 {
3010 /* Clear 'shm' to avoid that the file message overwrites
3011 * any output from the command. */
3012 p_shm_save = vim_strsave(p_shm);
3013 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003015 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3016 vim_free(p_shm_save);
3017 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003018 if (curwin->w_arg_idx != i)
3019 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020 }
3021#ifdef FEAT_WINDOWS
3022 else if (eap->cmdidx == CMD_windo)
3023 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003024 /* go to window "wp" */
3025 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003027 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00003028 if (curwin != wp)
3029 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003030 wp = curwin->w_next;
3031 }
3032 else if (eap->cmdidx == CMD_tabdo)
3033 {
3034 /* go to window "tp" */
3035 if (!valid_tabpage(tp))
3036 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02003037 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00003038 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003039 }
3040#endif
3041 else if (eap->cmdidx == CMD_bufdo)
3042 {
3043 /* Remember the number of the next listed buffer, in case
3044 * ":bwipe" is used or autocommands do something strange. */
3045 next_fnum = -1;
3046 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
3047 if (buf->b_p_bl)
3048 {
3049 next_fnum = buf->b_fnum;
3050 break;
3051 }
3052 }
3053
Bram Moolenaara162bc52015-01-07 16:54:21 +01003054 ++i;
3055
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 /* execute the command */
3057 do_cmdline(eap->arg, eap->getline, eap->cookie,
3058 DOCMD_VERBOSE + DOCMD_NOWAIT);
3059
3060 if (eap->cmdidx == CMD_bufdo)
3061 {
3062 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01003063 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003064 break;
3065 /* Check if the buffer still exists. */
Bram Moolenaar29323592016-07-24 22:04:11 +02003066 FOR_ALL_BUFFERS(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067 if (buf->b_fnum == next_fnum)
3068 break;
3069 if (buf == NULL)
3070 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003071
3072 /* Go to the next buffer. Clear 'shm' to avoid that the file
3073 * message overwrites any output from the command. */
3074 p_shm_save = vim_strsave(p_shm);
3075 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003077 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
3078 vim_free(p_shm_save);
3079
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003080 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003081 if (curbuf->b_fnum != next_fnum)
3082 break;
3083 }
3084
Bram Moolenaaraa23b372015-09-08 18:46:31 +02003085#ifdef FEAT_QUICKFIX
3086 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
3087 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
3088 {
3089 if (i >= qf_size || i >= eap->line2)
3090 break;
3091
3092 qf_idx = qf_get_cur_idx(eap);
3093
3094 ex_cnext(eap);
3095
3096 /* If jumping to the next quickfix entry fails, quit here */
3097 if (qf_get_cur_idx(eap) == qf_idx)
3098 break;
3099 }
3100#endif
3101
Bram Moolenaar071d4272004-06-13 20:20:40 +00003102 if (eap->cmdidx == CMD_windo)
3103 {
3104 validate_cursor(); /* cursor may have moved */
3105#ifdef FEAT_SCROLLBIND
3106 /* required when 'scrollbind' has been set */
3107 if (curwin->w_p_scb)
3108 do_check_scrollbind(TRUE);
3109#endif
3110 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01003111
3112#ifdef FEAT_WINDOWS
3113 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
3114 if (i+1 > eap->line2)
3115 break;
3116#endif
3117 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
3118 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119 }
3120 listcmd_busy = FALSE;
3121 }
3122
3123#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00003124 if (save_ei != NULL)
3125 {
3126 au_event_restore(save_ei);
3127 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
3128 curbuf->b_fname, TRUE, curbuf);
3129 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02003131#ifdef FEAT_CLIPBOARD
3132 end_global_changes();
3133#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134}
3135
3136/*
3137 * Add files[count] to the arglist of the current window after arg "after".
3138 * The file names in files[count] must have been allocated and are taken over.
3139 * Files[] itself is not taken over.
3140 * Returns index of first added argument. Returns -1 when failed (out of mem).
3141 */
3142 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003143alist_add_list(
3144 int count,
3145 char_u **files,
3146 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147{
3148 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003149 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003150
3151 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3152 {
3153 if (after < 0)
3154 after = 0;
3155 if (after > ARGCOUNT)
3156 after = ARGCOUNT;
3157 if (after < ARGCOUNT)
3158 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3159 (ARGCOUNT - after) * sizeof(aentry_T));
3160 for (i = 0; i < count; ++i)
3161 {
3162 ARGLIST[after + i].ae_fname = files[i];
3163 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3164 }
3165 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003166 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3167 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168 return after;
3169 }
3170
3171 for (i = 0; i < count; ++i)
3172 vim_free(files[i]);
3173 return -1;
3174}
3175
3176#endif /* FEAT_LISTCMDS */
3177
3178#ifdef FEAT_EVAL
3179/*
3180 * ":compiler[!] {name}"
3181 */
3182 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003183ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184{
3185 char_u *buf;
3186 char_u *old_cur_comp = NULL;
3187 char_u *p;
3188
3189 if (*eap->arg == NUL)
3190 {
3191 /* List all compiler scripts. */
3192 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3193 /* ) keep the indenter happy... */
3194 }
3195 else
3196 {
3197 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3198 if (buf != NULL)
3199 {
3200 if (eap->forceit)
3201 {
3202 /* ":compiler! {name}" sets global options */
3203 do_cmdline_cmd((char_u *)
3204 "command -nargs=* CompilerSet set <args>");
3205 }
3206 else
3207 {
3208 /* ":compiler! {name}" sets local options.
3209 * To remain backwards compatible "current_compiler" is always
3210 * used. A user's compiler plugin may set it, the distributed
3211 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003212 * "b:current_compiler" and restore "current_compiler".
3213 * Explicitly prepend "g:" to make it work in a function. */
3214 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003215 if (old_cur_comp != NULL)
3216 old_cur_comp = vim_strsave(old_cur_comp);
3217 do_cmdline_cmd((char_u *)
3218 "command -nargs=* CompilerSet setlocal <args>");
3219 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003220 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003221 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222
3223 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003224 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3226 vim_free(buf);
3227
3228 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3229
3230 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003231 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003232 if (p != NULL)
3233 set_internal_string_var((char_u *)"b:current_compiler", p);
3234
3235 /* Restore "current_compiler" for ":compiler {name}". */
3236 if (!eap->forceit)
3237 {
3238 if (old_cur_comp != NULL)
3239 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003240 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 old_cur_comp);
3242 vim_free(old_cur_comp);
3243 }
3244 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003245 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246 }
3247 }
3248 }
3249}
3250#endif
3251
3252/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003253 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003254 */
3255 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003256ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003258 char_u *arg = eap->arg;
3259 char_u *p = skiptowhite(arg);
3260 int len = (int)(p - arg);
3261 int flags = eap->forceit ? DIP_ALL : 0;
3262
3263 if (STRNCMP(arg, "START", len) == 0)
3264 {
3265 flags += DIP_START + DIP_NORTP;
3266 arg = skipwhite(arg + len);
3267 }
3268 else if (STRNCMP(arg, "OPT", len) == 0)
3269 {
3270 flags += DIP_OPT + DIP_NORTP;
3271 arg = skipwhite(arg + len);
3272 }
3273 else if (STRNCMP(arg, "PACK", len) == 0)
3274 {
3275 flags += DIP_START + DIP_OPT + DIP_NORTP;
3276 arg = skipwhite(arg + len);
3277 }
3278 else if (STRNCMP(arg, "ALL", len) == 0)
3279 {
3280 flags += DIP_START + DIP_OPT;
3281 arg = skipwhite(arg + len);
3282 }
3283
3284 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003285}
3286
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003288source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003290 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003291}
3292
3293/*
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003294 * Find the file "name" in all directories in "path" and invoke
3295 * "callback(fname, cookie)".
3296 * "name" can contain wildcards.
3297 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3298 * When "flags" has DIP_DIR: find directories instead of files.
3299 * When "flags" has DIP_ERR: give an error message if there is no match.
3300 *
3301 * return FAIL when no file could be sourced, OK otherwise.
3302 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003303 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003304do_in_path(
3305 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003306 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003307 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003308 void (*callback)(char_u *fname, void *ck),
3309 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310{
3311 char_u *rtp;
3312 char_u *np;
3313 char_u *buf;
3314 char_u *rtp_copy;
3315 char_u *tail;
3316 int num_files;
3317 char_u **files;
3318 int i;
3319 int did_one = FALSE;
3320#ifdef AMIGA
3321 struct Process *proc = (struct Process *)FindTask(0L);
3322 APTR save_winptr = proc->pr_WindowPtr;
3323
3324 /* Avoid a requester here for a volume that doesn't exist. */
3325 proc->pr_WindowPtr = (APTR)-1L;
3326#endif
3327
3328 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3329 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003330 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331 buf = alloc(MAXPATHL);
3332 if (buf != NULL && rtp_copy != NULL)
3333 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003334 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003335 {
3336 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003337 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003338 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003339 verbose_leave();
3340 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003341
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 /* Loop over all entries in 'runtimepath'. */
3343 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003344 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003345 {
Bram Moolenaar66459b72016-08-06 19:01:55 +02003346 size_t buflen;
3347
Bram Moolenaar071d4272004-06-13 20:20:40 +00003348 /* Copy the path from 'runtimepath' to buf[]. */
3349 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaar66459b72016-08-06 19:01:55 +02003350 buflen = STRLEN(buf);
3351
3352 /* Skip after or non-after directories. */
3353 if (flags & (DIP_NOAFTER | DIP_AFTER))
3354 {
3355 int is_after = buflen >= 5
3356 && STRCMP(buf + buflen - 5, "after") == 0;
3357
3358 if ((is_after && (flags & DIP_NOAFTER))
3359 || (!is_after && (flags & DIP_AFTER)))
3360 continue;
3361 }
3362
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003363 if (name == NULL)
3364 {
3365 (*callback)(buf, (void *) &cookie);
3366 if (!did_one)
3367 did_one = (cookie == NULL);
3368 }
Bram Moolenaar66459b72016-08-06 19:01:55 +02003369 else if (buflen + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003370 {
3371 add_pathsep(buf);
3372 tail = buf + STRLEN(buf);
3373
3374 /* Loop over all patterns in "name" */
3375 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003376 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 {
3378 /* Append the pattern from "name" to buf[]. */
3379 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3380 "\t ");
3381
3382 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003383 {
3384 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003385 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003386 verbose_leave();
3387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388
3389 /* Expand wildcards, invoke the callback for each match. */
3390 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003391 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 {
3393 for (i = 0; i < num_files; ++i)
3394 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003395 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003396 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003397 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003398 break;
3399 }
3400 FreeWild(num_files, files);
3401 }
3402 }
3403 }
3404 }
3405 }
3406 vim_free(buf);
3407 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003408 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003409 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003410 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3411
3412 if (flags & DIP_ERR)
3413 EMSG3(_(e_dirnotf), basepath, name);
3414 else if (p_verbose > 0)
3415 {
3416 verbose_enter();
3417 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3418 verbose_leave();
3419 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003420 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003421
3422#ifdef AMIGA
3423 proc->pr_WindowPtr = save_winptr;
3424#endif
3425
3426 return did_one ? OK : FAIL;
3427}
3428
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003429/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003430 * Find "name" in "path". When found, invoke the callback function for
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003431 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003432 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3433 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003434 * Returns OK when at least one match found, FAIL otherwise.
3435 *
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003436 * If "name" is NULL calls callback for each entry in "path". Cookie is
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003437 * passed by reference in this case, setting it to NULL indicates that callback
3438 * has done its job.
3439 */
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003440 static int
3441do_in_path_and_pp(
3442 char_u *path,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003443 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003444 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003445 void (*callback)(char_u *fname, void *ck),
3446 void *cookie)
3447{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003448 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003449 char_u *s;
3450 int len;
3451 char *start_dir = "pack/*/start/*/%s";
3452 char *opt_dir = "pack/*/opt/*/%s";
3453
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003454 if ((flags & DIP_NORTP) == 0)
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003455 done = do_in_path(path, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003456
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003457 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003458 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003459 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003460 s = alloc(len);
3461 if (s == NULL)
3462 return FAIL;
3463 vim_snprintf((char *)s, len, start_dir, name);
3464 done = do_in_path(p_pp, s, flags, callback, cookie);
3465 vim_free(s);
3466 }
3467
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003468 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003469 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003470 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003471 s = alloc(len);
3472 if (s == NULL)
3473 return FAIL;
3474 vim_snprintf((char *)s, len, opt_dir, name);
3475 done = do_in_path(p_pp, s, flags, callback, cookie);
3476 vim_free(s);
3477 }
3478
3479 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003480}
3481
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003482/*
Bram Moolenaar07ecfa62017-06-27 14:43:55 +02003483 * Just like do_in_path_and_pp(), using 'runtimepath' for "path".
3484 */
3485 int
3486do_in_runtimepath(
3487 char_u *name,
3488 int flags,
3489 void (*callback)(char_u *fname, void *ck),
3490 void *cookie)
3491{
3492 return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
3493}
3494
3495/*
3496 * Source the file "name" from all directories in 'runtimepath'.
3497 * "name" can contain wildcards.
3498 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3499 *
3500 * return FAIL when no file could be sourced, OK otherwise.
3501 */
3502 int
3503source_runtime(char_u *name, int flags)
3504{
3505 return source_in_path(p_rtp, name, flags);
3506}
3507
3508/*
3509 * Just like source_runtime(), but use "path" instead of 'runtimepath'.
3510 */
3511 int
3512source_in_path(char_u *path, char_u *name, int flags)
3513{
3514 return do_in_path_and_pp(path, name, flags, source_callback, NULL);
3515}
3516
3517
3518/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003519 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003520 */
3521 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003522source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003523{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003524 int num_files;
3525 char_u **files;
3526 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003527
Bram Moolenaarf3654822016-03-04 22:12:23 +01003528 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003529 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003530 for (i = 0; i < num_files; ++i)
3531 (void)do_source(files[i], FALSE, DOSO_NONE);
3532 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003533 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003534}
3535
Bram Moolenaar49b27322016-04-05 21:13:00 +02003536/* used for "cookie" of add_pack_plugin() */
3537static int APP_ADD_DIR;
3538static int APP_LOAD;
3539static int APP_BOTH;
3540
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003541 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003542add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003543{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003544 char_u *p4, *p3, *p2, *p1, *p;
3545 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003546 int c;
3547 char_u *new_rtp;
3548 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003549 size_t oldlen;
3550 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003551 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003552 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003553 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003554 size_t fname_len;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003555 char_u *buf = NULL;
3556 char_u *rtp_ffname;
3557 int match;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003558
Bram Moolenaar91715872016-03-03 17:13:03 +01003559 if (ffname == NULL)
3560 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003561 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003562 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003563 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003564 p4 = p3 = p2 = p1 = get_past_head(ffname);
Bram Moolenaar91acfff2017-03-12 19:22:36 +01003565 for (p = p1; *p; MB_PTR_ADV(p))
Bram Moolenaarf3654822016-03-04 22:12:23 +01003566 if (vim_ispathsep_nocolon(*p))
3567 {
3568 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3569 }
3570
3571 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003572 * rtp/pack/name/start/name
3573 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003574 *
3575 * find the part up to "pack" in 'runtimepath' */
3576 c = *p4;
3577 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003578
3579 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3580 fname_len = STRLEN(ffname);
3581 insp = p_rtp;
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003582 buf = alloc(MAXPATHL);
3583 if (buf == NULL)
3584 goto theend;
3585 while (*insp != NUL)
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003586 {
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003587 copy_option_part(&insp, buf, MAXPATHL, ",");
3588 add_pathsep(buf);
3589 rtp_ffname = fix_fname(buf);
3590 if (rtp_ffname == NULL)
3591 goto theend;
3592 match = vim_fnamencmp(rtp_ffname, ffname, fname_len) == 0;
3593 vim_free(rtp_ffname);
3594 if (match)
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003595 break;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003596 }
3597
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003598 if (*insp == NUL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003599 /* not found, append at the end */
3600 insp = p_rtp + STRLEN(p_rtp);
3601 else
Bram Moolenaarf3654822016-03-04 22:12:23 +01003602 /* append after the matching directory. */
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003603 --insp;
Bram Moolenaarf3654822016-03-04 22:12:23 +01003604 *p4 = c;
3605
Bram Moolenaara5702442016-05-24 19:37:29 +02003606 /* check if rtp/pack/name/start/name/after exists */
3607 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3608 if (afterdir != NULL && mch_isdir(afterdir))
3609 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3610
Bram Moolenaarb0550662016-05-31 21:37:36 +02003611 oldlen = STRLEN(p_rtp);
3612 addlen = STRLEN(ffname) + 1; /* add one for comma */
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003613 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1));
3614 /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003615 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003616 goto theend;
3617 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003618 mch_memmove(new_rtp, p_rtp, keep);
3619 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003620 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003621 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003622 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003623 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003624 if (afterlen > 0)
3625 {
3626 STRCAT(new_rtp, ",");
3627 STRCAT(new_rtp, afterdir);
3628 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003629 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3630 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003631 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003632 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003633
Bram Moolenaar49b27322016-04-05 21:13:00 +02003634 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003635 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003636 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003637 static char *ftpat = "%s/ftdetect/*.vim";
3638 int len;
3639 char_u *pat;
3640
3641 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3642 pat = alloc(len);
3643 if (pat == NULL)
3644 goto theend;
3645 vim_snprintf((char *)pat, len, plugpat, ffname);
3646 source_all_matches(pat);
3647
3648#ifdef FEAT_AUTOCMD
3649 {
3650 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3651
3652 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3653 * found when it loads. */
3654 if (cmd != NULL && eval_to_number(cmd) > 0)
3655 {
3656 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3657 vim_snprintf((char *)pat, len, ftpat, ffname);
3658 source_all_matches(pat);
3659 do_cmdline_cmd((char_u *)"augroup END");
3660 }
3661 vim_free(cmd);
3662 }
3663#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003664 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003665 }
3666
3667theend:
Bram Moolenaar2f9e5752017-02-05 16:07:54 +01003668 vim_free(buf);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003669 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003670}
3671
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003672/*
3673 * Add all packages in the "start" directory to 'runtimepath'.
3674 */
3675 void
3676add_pack_start_dirs(void)
3677{
3678 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3679 add_pack_plugin, &APP_ADD_DIR);
3680}
3681
3682/*
3683 * Load plugins from all packages in the "start" directory.
3684 */
3685 void
3686load_start_packages(void)
3687{
3688 did_source_packages = TRUE;
3689 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3690 add_pack_plugin, &APP_LOAD);
3691}
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003692
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003693/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003694 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003695 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003696 */
3697 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003698ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003699{
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003700 if (!did_source_packages || eap->forceit)
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003701 {
Bram Moolenaar49b27322016-04-05 21:13:00 +02003702 /* First do a round to add all directories to 'runtimepath', then load
3703 * the plugins. This allows for plugins to use an autoload directory
3704 * of another plugin. */
Bram Moolenaarce876aa2017-06-04 17:47:42 +02003705 add_pack_start_dirs();
3706 load_start_packages();
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003707 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003708}
3709
3710/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003711 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003712 */
3713 void
3714ex_packadd(exarg_T *eap)
3715{
3716 static char *plugpat = "pack/*/opt/%s";
3717 int len;
3718 char *pat;
3719
3720 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3721 pat = (char *)alloc(len);
3722 if (pat == NULL)
3723 return;
3724 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003725 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003726 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003727 vim_free(pat);
3728}
3729
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3731/*
3732 * ":options"
3733 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003735ex_options(
3736 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737{
3738 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3739}
3740#endif
3741
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003742#if defined(FEAT_PYTHON3) || defined(FEAT_PYTHON) || defined(PROTO)
3743
3744# if (defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
3745/*
3746 * Detect Python 3 or 2, and initialize 'pyxversion'.
3747 */
3748 void
3749init_pyxversion(void)
3750{
3751 if (p_pyx == 0)
3752 {
3753 if (python3_enabled(FALSE))
3754 p_pyx = 3;
3755 else if (python_enabled(FALSE))
3756 p_pyx = 2;
3757 }
3758}
3759# endif
3760
3761/*
3762 * Does a file contain one of the following strings at the beginning of any
3763 * line?
3764 * "#!(any string)python2" => returns 2
3765 * "#!(any string)python3" => returns 3
3766 * "# requires python 2.x" => returns 2
3767 * "# requires python 3.x" => returns 3
3768 * otherwise return 0.
3769 */
3770 static int
3771requires_py_version(char_u *filename)
3772{
3773 FILE *file;
3774 int requires_py_version = 0;
3775 int i, lines;
3776
3777 lines = (int)p_mls;
3778 if (lines < 0)
3779 lines = 5;
3780
3781 file = mch_fopen((char *)filename, "r");
3782 if (file != NULL)
3783 {
3784 for (i = 0; i < lines; i++)
3785 {
3786 if (vim_fgets(IObuff, IOSIZE, file))
3787 break;
3788 if (i == 0 && IObuff[0] == '#' && IObuff[1] == '!')
3789 {
3790 /* Check shebang. */
3791 if (strstr((char *)IObuff + 2, "python2") != NULL)
3792 {
3793 requires_py_version = 2;
3794 break;
3795 }
3796 if (strstr((char *)IObuff + 2, "python3") != NULL)
3797 {
3798 requires_py_version = 3;
3799 break;
3800 }
3801 }
3802 IObuff[21] = '\0';
3803 if (STRCMP("# requires python 2.x", IObuff) == 0)
3804 {
3805 requires_py_version = 2;
3806 break;
3807 }
3808 if (STRCMP("# requires python 3.x", IObuff) == 0)
3809 {
3810 requires_py_version = 3;
3811 break;
3812 }
3813 }
3814 fclose(file);
3815 }
3816 return requires_py_version;
3817}
3818
3819
3820/*
3821 * Source a python file using the requested python version.
3822 */
3823 static void
3824source_pyx_file(exarg_T *eap, char_u *fname)
3825{
3826 exarg_T ex;
3827 int v = requires_py_version(fname);
3828
3829# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3830 init_pyxversion();
3831# endif
3832 if (v == 0)
3833 {
3834# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3835 /* user didn't choose a preference, 'pyx' is used */
3836 v = p_pyx;
3837# elif defined(FEAT_PYTHON)
3838 v = 2;
3839# elif defined(FEAT_PYTHON3)
3840 v = 3;
3841# endif
3842 }
3843
3844 /*
3845 * now source, if required python version is not supported show
3846 * unobtrusive message.
3847 */
3848 if (eap == NULL)
3849 vim_memset(&ex, 0, sizeof(ex));
3850 else
3851 ex = *eap;
3852 ex.arg = fname;
3853 ex.cmd = (char_u *)(v == 2 ? "pyfile" : "pyfile3");
3854
3855 if (v == 2)
3856 {
3857# ifdef FEAT_PYTHON
3858 ex_pyfile(&ex);
3859# else
3860 vim_snprintf((char *)IObuff, IOSIZE,
3861 _("W20: Required python version 2.x not supported, ignoring file: %s"),
3862 fname);
3863 MSG(IObuff);
3864# endif
3865 return;
3866 }
3867 else
3868 {
3869# ifdef FEAT_PYTHON3
3870 ex_py3file(&ex);
3871# else
3872 vim_snprintf((char *)IObuff, IOSIZE,
3873 _("W21: Required python version 3.x not supported, ignoring file: %s"),
3874 fname);
3875 MSG(IObuff);
3876# endif
3877 return;
3878 }
3879}
3880
3881/*
3882 * ":pyxfile {fname}"
3883 */
3884 void
3885ex_pyxfile(exarg_T *eap)
3886{
3887 source_pyx_file(eap, eap->arg);
3888}
3889
3890/*
3891 * ":pyx"
3892 */
3893 void
3894ex_pyx(exarg_T *eap)
3895{
3896# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3897 init_pyxversion();
3898 if (p_pyx == 2)
3899 ex_python(eap);
3900 else
3901 ex_py3(eap);
3902# elif defined(FEAT_PYTHON)
3903 ex_python(eap);
3904# elif defined(FEAT_PYTHON3)
3905 ex_py3(eap);
3906# endif
3907}
3908
3909/*
3910 * ":pyxdo"
3911 */
3912 void
3913ex_pyxdo(exarg_T *eap)
3914{
3915# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3916 init_pyxversion();
3917 if (p_pyx == 2)
3918 ex_pydo(eap);
3919 else
3920 ex_py3do(eap);
3921# elif defined(FEAT_PYTHON)
3922 ex_pydo(eap);
3923# elif defined(FEAT_PYTHON3)
3924 ex_py3do(eap);
3925# endif
3926}
3927
3928#endif
3929
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930/*
3931 * ":source {fname}"
3932 */
3933 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003934ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935{
3936#ifdef FEAT_BROWSE
3937 if (cmdmod.browse)
3938 {
3939 char_u *fname = NULL;
3940
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003941 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3943 if (fname != NULL)
3944 {
3945 cmd_source(fname, eap);
3946 vim_free(fname);
3947 }
3948 }
3949 else
3950#endif
3951 cmd_source(eap->arg, eap);
3952}
3953
3954 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003955cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003956{
3957 if (*fname == NUL)
3958 EMSG(_(e_argreq));
3959
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003961 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003962 * Need to execute the commands directly. This is required at least
3963 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003964 * - ":g" command busy
3965 * - after ":argdo", ":windo" or ":bufdo"
3966 * - another command follows
3967 * - inside a loop
3968 */
3969 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3970#ifdef FEAT_EVAL
3971 || eap->cstack->cs_idx >= 0
3972#endif
3973 );
3974
3975 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003976 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977 EMSG2(_(e_notopen), fname);
3978}
3979
3980/*
3981 * ":source" and associated commands.
3982 */
3983/*
3984 * Structure used to store info for each sourced file.
3985 * It is shared between do_source() and getsourceline().
3986 * This is required, because it needs to be handed to do_cmdline() and
3987 * sourcing can be done recursively.
3988 */
3989struct source_cookie
3990{
3991 FILE *fp; /* opened file for sourcing */
3992 char_u *nextline; /* if not NULL: line that was read ahead */
3993 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003994#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3996 int error; /* TRUE if LF found after CR-LF */
3997#endif
3998#ifdef FEAT_EVAL
3999 linenr_T breakpoint; /* next line with breakpoint or zero */
4000 char_u *fname; /* name of sourced file */
4001 int dbg_tick; /* debug_tick when breakpoint was set */
4002 int level; /* top nesting level of sourced file */
4003#endif
4004#ifdef FEAT_MBYTE
4005 vimconv_T conv; /* type of conversion */
4006#endif
4007};
4008
4009#ifdef FEAT_EVAL
4010/*
4011 * Return the address holding the next breakpoint line for a source cookie.
4012 */
4013 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004014source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015{
4016 return &((struct source_cookie *)cookie)->breakpoint;
4017}
4018
4019/*
4020 * Return the address holding the debug tick for a source cookie.
4021 */
4022 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004023source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024{
4025 return &((struct source_cookie *)cookie)->dbg_tick;
4026}
4027
4028/*
4029 * Return the nesting level for a source cookie.
4030 */
4031 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004032source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033{
4034 return ((struct source_cookie *)cookie)->level;
4035}
4036#endif
4037
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004038static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004040#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
4041# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004042static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043
4044/*
4045 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004046 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047 */
4048 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004049fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004050{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004051# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01004052 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
4053# else
4054 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004055# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056
4057 if (fd_tmp == -1)
4058 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004059
4060# ifdef HAVE_FD_CLOEXEC
4061 {
4062 int fdflags = fcntl(fd_tmp, F_GETFD);
4063 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02004064 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004065 }
4066# endif
4067
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 return fdopen(fd_tmp, READBIN);
4069}
4070#endif
4071
4072
4073/*
4074 * do_source: Read the file "fname" and execute its lines as EX commands.
4075 *
4076 * This function may be called recursively!
4077 *
4078 * return FAIL if file could not be opened, OK otherwise
4079 */
4080 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004081do_source(
4082 char_u *fname,
4083 int check_other, /* check for .vimrc and _vimrc */
4084 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085{
4086 struct source_cookie cookie;
4087 char_u *save_sourcing_name;
4088 linenr_T save_sourcing_lnum;
4089 char_u *p;
4090 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00004091 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 int retval = FAIL;
4093#ifdef FEAT_EVAL
4094 scid_T save_current_SID;
4095 static scid_T last_current_SID = 0;
4096 void *save_funccalp;
4097 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004098 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02004100 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 int stat_ok;
4102# endif
4103#endif
4104#ifdef STARTUPTIME
4105 struct timeval tv_rel;
4106 struct timeval tv_start;
4107#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004108#ifdef FEAT_PROFILE
4109 proftime_T wait_start;
4110#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 if (p == NULL)
4114 return retval;
4115 fname_exp = fix_fname(p);
4116 vim_free(p);
4117 if (fname_exp == NULL)
4118 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 if (mch_isdir(fname_exp))
4120 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00004121 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 goto theend;
4123 }
4124
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004125#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004126 /* Apply SourceCmd autocommands, they should get the file and source it. */
4127 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
4128 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
4129 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004130 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004131# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004132 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004133# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004134 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004135# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00004136 goto theend;
4137 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00004138
4139 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00004140 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
4141#endif
4142
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004143#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4145#else
4146 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4147#endif
4148 if (cookie.fp == NULL && check_other)
4149 {
4150 /*
4151 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
4152 * and ".exrc" by "_exrc" or vice versa.
4153 */
4154 p = gettail(fname_exp);
4155 if ((*p == '.' || *p == '_')
4156 && (STRICMP(p + 1, "vimrc") == 0
4157 || STRICMP(p + 1, "gvimrc") == 0
4158 || STRICMP(p + 1, "exrc") == 0))
4159 {
4160 if (*p == '_')
4161 *p = '.';
4162 else
4163 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01004164#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
4166#else
4167 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
4168#endif
4169 }
4170 }
4171
4172 if (cookie.fp == NULL)
4173 {
4174 if (p_verbose > 0)
4175 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004176 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004178 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179 else
4180 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004181 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004182 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183 }
4184 goto theend;
4185 }
4186
4187 /*
4188 * The file exists.
4189 * - In verbose mode, give a message.
4190 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
4191 */
4192 if (p_verbose > 1)
4193 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004194 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004196 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004197 else
4198 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00004199 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004200 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004202 if (is_vimrc == DOSO_VIMRC)
4203 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
4204 else if (is_vimrc == DOSO_GVIMRC)
4205 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206
4207#ifdef USE_CRNL
4208 /* If no automatic file format: Set default to CR-NL. */
4209 if (*p_ffs == NUL)
4210 cookie.fileformat = EOL_DOS;
4211 else
4212 cookie.fileformat = EOL_UNKNOWN;
4213 cookie.error = FALSE;
4214#endif
4215
4216#ifdef USE_CR
4217 /* If no automatic file format: Set default to CR. */
4218 if (*p_ffs == NUL)
4219 cookie.fileformat = EOL_MAC;
4220 else
4221 cookie.fileformat = EOL_UNKNOWN;
4222 cookie.error = FALSE;
4223#endif
4224
4225 cookie.nextline = NULL;
4226 cookie.finished = FALSE;
4227
4228#ifdef FEAT_EVAL
4229 /*
4230 * Check if this script has a breakpoint.
4231 */
4232 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
4233 cookie.fname = fname_exp;
4234 cookie.dbg_tick = debug_tick;
4235
4236 cookie.level = ex_nesting_level;
4237#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238
4239 /*
4240 * Keep the sourcing name/lnum, for recursive calls.
4241 */
4242 save_sourcing_name = sourcing_name;
4243 sourcing_name = fname_exp;
4244 save_sourcing_lnum = sourcing_lnum;
4245 sourcing_lnum = 0;
4246
Bram Moolenaar73881402009-02-04 16:50:47 +00004247#ifdef FEAT_MBYTE
4248 cookie.conv.vc_type = CONV_NONE; /* no conversion */
4249
4250 /* Read the first line so we can check for a UTF-8 BOM. */
4251 firstline = getsourceline(0, (void *)&cookie, 0);
4252 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
4253 && firstline[1] == 0xbb && firstline[2] == 0xbf)
4254 {
4255 /* Found BOM; setup conversion, skip over BOM and recode the line. */
4256 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
4257 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00004258 if (p == NULL)
4259 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00004260 if (p != NULL)
4261 {
4262 vim_free(firstline);
4263 firstline = p;
4264 }
4265 }
4266#endif
4267
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004269 if (time_fd != NULL)
4270 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271#endif
4272
4273#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00004274# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004275 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004276 prof_child_enter(&wait_start); /* entering a child now */
4277# endif
4278
4279 /* Don't use local function variables, if called from a function.
4280 * Also starts profiling timer for nested script. */
4281 save_funccalp = save_funccal();
4282
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283 /*
4284 * Check if this script was sourced before to finds its SID.
4285 * If it's new, generate a new SID.
4286 */
4287 save_current_SID = current_SID;
4288# ifdef UNIX
4289 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
4290# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004291 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
4292 {
4293 si = &SCRIPT_ITEM(current_SID);
4294 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295 && (
4296# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00004297 /* Compare dev/ino when possible, it catches symbolic
4298 * links. Also compare file names, the inode may change
4299 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004300 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004301 && (si->sn_dev == st.st_dev
4302 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00004304 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004306 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004307 if (current_SID == 0)
4308 {
4309 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004310 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
4311 == FAIL)
4312 goto almosttheend;
4313 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00004315 ++script_items.ga_len;
4316 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
4317# ifdef FEAT_PROFILE
4318 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004321 si = &SCRIPT_ITEM(current_SID);
4322 si->sn_name = fname_exp;
4323 fname_exp = NULL;
4324# ifdef UNIX
4325 if (stat_ok)
4326 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004327 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004328 si->sn_dev = st.st_dev;
4329 si->sn_ino = st.st_ino;
4330 }
4331 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00004332 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004333# endif
4334
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 /* Allocate the local script variables to use for this script. */
4336 new_script_vars(current_SID);
4337 }
4338
Bram Moolenaar05159a02005-02-26 23:04:13 +00004339# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004340 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004341 {
4342 int forceit;
4343
4344 /* Check if we do profiling for this script. */
4345 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
4346 {
4347 script_do_profile(si);
4348 si->sn_pr_force = forceit;
4349 }
4350 if (si->sn_prof_on)
4351 {
4352 ++si->sn_pr_count;
4353 profile_start(&si->sn_pr_start);
4354 profile_zero(&si->sn_pr_children);
4355 }
4356 }
4357# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004358#endif
4359
4360 /*
4361 * Call do_cmdline, which will call getsourceline() to get the lines.
4362 */
Bram Moolenaar73881402009-02-04 16:50:47 +00004363 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00004366
4367#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004368 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004369 {
4370 /* Get "si" again, "script_items" may have been reallocated. */
4371 si = &SCRIPT_ITEM(current_SID);
4372 if (si->sn_prof_on)
4373 {
4374 profile_end(&si->sn_pr_start);
4375 profile_sub_wait(&wait_start, &si->sn_pr_start);
4376 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004377 profile_self(&si->sn_pr_self, &si->sn_pr_start,
4378 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004379 }
4380 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381#endif
4382
4383 if (got_int)
4384 EMSG(_(e_interr));
4385 sourcing_name = save_sourcing_name;
4386 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004387 if (p_verbose > 1)
4388 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004389 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004390 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004392 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004393 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 }
4395#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004396 if (time_fd != NULL)
4397 {
4398 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4399 time_msg((char *)IObuff, &tv_start);
4400 time_pop(&tv_rel);
4401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402#endif
4403
4404#ifdef FEAT_EVAL
4405 /*
4406 * After a "finish" in debug mode, need to break at first command of next
4407 * sourced file.
4408 */
4409 if (save_debug_break_level > ex_nesting_level
4410 && debug_break_level == ex_nesting_level)
4411 ++debug_break_level;
4412#endif
4413
Bram Moolenaar05159a02005-02-26 23:04:13 +00004414#ifdef FEAT_EVAL
4415almosttheend:
4416 current_SID = save_current_SID;
4417 restore_funccal(save_funccalp);
4418# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004419 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004420 prof_child_exit(&wait_start); /* leaving a child now */
4421# endif
4422#endif
4423 fclose(cookie.fp);
4424 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004425 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004426#ifdef FEAT_MBYTE
4427 convert_setup(&cookie.conv, NULL, NULL);
4428#endif
4429
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430theend:
4431 vim_free(fname_exp);
4432 return retval;
4433}
4434
4435#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004436
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437/*
4438 * ":scriptnames"
4439 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004441ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442{
4443 int i;
4444
Bram Moolenaar05159a02005-02-26 23:04:13 +00004445 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4446 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004447 {
4448 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4449 NameBuff, MAXPATHL, TRUE);
4450 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452}
4453
4454# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4455/*
4456 * Fix slashes in the list of script names for 'shellslash'.
4457 */
4458 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004459scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460{
4461 int i;
4462
Bram Moolenaar05159a02005-02-26 23:04:13 +00004463 for (i = 1; i <= script_items.ga_len; ++i)
4464 if (SCRIPT_ITEM(i).sn_name != NULL)
4465 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466}
4467# endif
4468
4469/*
4470 * Get a pointer to a script name. Used for ":verbose set".
4471 */
4472 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004473get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474{
4475 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004476 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004478 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004480 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004481 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004482 return (char_u *)_("environment variable");
4483 if (id == SID_ERROR)
4484 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004485 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004487
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004488# if defined(EXITFREE) || defined(PROTO)
4489 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004490free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004491{
4492 int i;
4493
4494 for (i = script_items.ga_len; i > 0; --i)
4495 vim_free(SCRIPT_ITEM(i).sn_name);
4496 ga_clear(&script_items);
4497}
4498# endif
4499
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500#endif
4501
4502#if defined(USE_CR) || defined(PROTO)
4503
4504# if defined(__MSL__) && (__MSL__ >= 22)
4505/*
4506 * Newer version of the Metrowerks library handle DOS and UNIX files
4507 * without help.
4508 * Test with earlier versions, MSL 2.2 is the library supplied with
4509 * Codewarrior Pro 2.
4510 */
4511 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004512fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513{
4514 return fgets(s, n, stream);
4515}
4516# else
4517/*
4518 * Version of fgets() which also works for lines ending in a <CR> only
4519 * (Macintosh format).
4520 * For older versions of the Metrowerks library.
4521 * At least CodeWarrior 9 needed this code.
4522 */
4523 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004524fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525{
4526 int c = 0;
4527 int char_read = 0;
4528
4529 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4530 {
4531 c = fgetc(stream);
4532 s[char_read++] = c;
4533 /* If the file is in DOS format, we need to skip a NL after a CR. I
4534 * thought it was the other way around, but this appears to work... */
4535 if (c == '\n')
4536 {
4537 c = fgetc(stream);
4538 if (c != '\r')
4539 ungetc(c, stream);
4540 }
4541 }
4542
4543 s[char_read] = 0;
4544 if (char_read == 0)
4545 return NULL;
4546
4547 if (feof(stream) && char_read == 1)
4548 return NULL;
4549
4550 return s;
4551}
4552# endif
4553#endif
4554
4555/*
4556 * Get one full line from a sourced file.
4557 * Called by do_cmdline() when it's called from do_source().
4558 *
4559 * Return a pointer to the line in allocated memory.
4560 * Return NULL for end-of-file or some error.
4561 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004563getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564{
4565 struct source_cookie *sp = (struct source_cookie *)cookie;
4566 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004567 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568
4569#ifdef FEAT_EVAL
4570 /* If breakpoints have been added/deleted need to check for it. */
4571 if (sp->dbg_tick < debug_tick)
4572 {
4573 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4574 sp->dbg_tick = debug_tick;
4575 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004576# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004577 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004578 script_line_end();
4579# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580#endif
4581 /*
4582 * Get current line. If there is a read-ahead line, use it, otherwise get
4583 * one now.
4584 */
4585 if (sp->finished)
4586 line = NULL;
4587 else if (sp->nextline == NULL)
4588 line = get_one_sourceline(sp);
4589 else
4590 {
4591 line = sp->nextline;
4592 sp->nextline = NULL;
4593 ++sourcing_lnum;
4594 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004595#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004596 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004597 script_line_start();
4598#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004599
4600 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4601 * contain the 'C' flag. */
4602 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4603 {
4604 /* compensate for the one line read-ahead */
4605 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004606
4607 /* Get the next line and concatenate it when it starts with a
4608 * backslash. We always need to read the next line, keep it in
4609 * sp->nextline. */
4610 sp->nextline = get_one_sourceline(sp);
4611 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004613 garray_T ga;
4614
Bram Moolenaarb549a732012-02-22 18:29:33 +01004615 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004616 ga_concat(&ga, line);
4617 ga_concat(&ga, p + 1);
4618 for (;;)
4619 {
4620 vim_free(sp->nextline);
4621 sp->nextline = get_one_sourceline(sp);
4622 if (sp->nextline == NULL)
4623 break;
4624 p = skipwhite(sp->nextline);
4625 if (*p != '\\')
4626 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004627 /* Adjust the growsize to the current length to speed up
4628 * concatenating many lines. */
4629 if (ga.ga_len > 400)
4630 {
4631 if (ga.ga_len > 8000)
4632 ga.ga_growsize = 8000;
4633 else
4634 ga.ga_growsize = ga.ga_len;
4635 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004636 ga_concat(&ga, p + 1);
4637 }
4638 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004639 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004640 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641 }
4642 }
4643
4644#ifdef FEAT_MBYTE
4645 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4646 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004647 char_u *s;
4648
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 /* Convert the encoding of the script line. */
4650 s = string_convert(&sp->conv, line, NULL);
4651 if (s != NULL)
4652 {
4653 vim_free(line);
4654 line = s;
4655 }
4656 }
4657#endif
4658
4659#ifdef FEAT_EVAL
4660 /* Did we encounter a breakpoint? */
4661 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4662 {
4663 dbg_breakpoint(sp->fname, sourcing_lnum);
4664 /* Find next breakpoint. */
4665 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4666 sp->dbg_tick = debug_tick;
4667 }
4668#endif
4669
4670 return line;
4671}
4672
4673 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004674get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004675{
4676 garray_T ga;
4677 int len;
4678 int c;
4679 char_u *buf;
4680#ifdef USE_CRNL
4681 int has_cr; /* CR-LF found */
4682#endif
4683#ifdef USE_CR
4684 char_u *scan;
4685#endif
4686 int have_read = FALSE;
4687
4688 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004689 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690
4691 /*
4692 * Loop until there is a finished line (or end-of-file).
4693 */
4694 sourcing_lnum++;
4695 for (;;)
4696 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004697 /* make room to read at least 120 (more) characters */
4698 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699 break;
4700 buf = (char_u *)ga.ga_data;
4701
4702#ifdef USE_CR
4703 if (sp->fileformat == EOL_MAC)
4704 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004705 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4706 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004707 break;
4708 }
4709 else
4710#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004711 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4712 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004714 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715#ifdef USE_CRNL
4716 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4717 * CTRL-Z by its own, or after a NL. */
4718 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4719 && sp->fileformat == EOL_DOS
4720 && buf[len - 1] == Ctrl_Z)
4721 {
4722 buf[len - 1] = NUL;
4723 break;
4724 }
4725#endif
4726
4727#ifdef USE_CR
4728 /* If the read doesn't stop on a new line, and there's
4729 * some CR then we assume a Mac format */
4730 if (sp->fileformat == EOL_UNKNOWN)
4731 {
4732 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4733 sp->fileformat = EOL_MAC;
4734 else
4735 sp->fileformat = EOL_UNIX;
4736 }
4737
4738 if (sp->fileformat == EOL_MAC)
4739 {
4740 scan = vim_strchr(buf, '\r');
4741
4742 if (scan != NULL)
4743 {
4744 *scan = '\n';
4745 if (*(scan + 1) != 0)
4746 {
4747 *(scan + 1) = 0;
4748 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4749 }
4750 }
4751 len = STRLEN(buf);
4752 }
4753#endif
4754
4755 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004756 ga.ga_len = len;
4757
4758 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004759 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760 continue;
4761
4762 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4763 {
4764#ifdef USE_CRNL
4765 has_cr = (len >= 2 && buf[len - 2] == '\r');
4766 if (sp->fileformat == EOL_UNKNOWN)
4767 {
4768 if (has_cr)
4769 sp->fileformat = EOL_DOS;
4770 else
4771 sp->fileformat = EOL_UNIX;
4772 }
4773
4774 if (sp->fileformat == EOL_DOS)
4775 {
4776 if (has_cr) /* replace trailing CR */
4777 {
4778 buf[len - 2] = '\n';
4779 --len;
4780 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 }
4782 else /* lines like ":map xx yy^M" will have failed */
4783 {
4784 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004785 {
Bram Moolenaar8820b482017-03-16 17:23:31 +01004786 msg_source(HL_ATTR(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 sp->error = TRUE;
4790 sp->fileformat = EOL_UNIX;
4791 }
4792 }
4793#endif
4794 /* The '\n' is escaped if there is an odd number of ^V's just
4795 * before it, first set "c" just before the 'V's and then check
4796 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4797 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4798 ;
4799 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4800 {
4801 sourcing_lnum++;
4802 continue;
4803 }
4804
4805 buf[len - 1] = NUL; /* remove the NL */
4806 }
4807
4808 /*
4809 * Check for ^C here now and then, so recursive :so can be broken.
4810 */
4811 line_breakcheck();
4812 break;
4813 }
4814
4815 if (have_read)
4816 return (char_u *)ga.ga_data;
4817
4818 vim_free(ga.ga_data);
4819 return NULL;
4820}
4821
Bram Moolenaar05159a02005-02-26 23:04:13 +00004822#if defined(FEAT_PROFILE) || defined(PROTO)
4823/*
4824 * Called when starting to read a script line.
4825 * "sourcing_lnum" must be correct!
4826 * When skipping lines it may not actually be executed, but we won't find out
4827 * until later and we need to store the time now.
4828 */
4829 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004830script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004831{
4832 scriptitem_T *si;
4833 sn_prl_T *pp;
4834
4835 if (current_SID <= 0 || current_SID > script_items.ga_len)
4836 return;
4837 si = &SCRIPT_ITEM(current_SID);
4838 if (si->sn_prof_on && sourcing_lnum >= 1)
4839 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004840 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004841 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004842 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004843 si->sn_prl_idx = sourcing_lnum - 1;
4844 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4845 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4846 {
4847 /* Zero counters for a line that was not used before. */
4848 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4849 pp->snp_count = 0;
4850 profile_zero(&pp->sn_prl_total);
4851 profile_zero(&pp->sn_prl_self);
4852 ++si->sn_prl_ga.ga_len;
4853 }
4854 si->sn_prl_execed = FALSE;
4855 profile_start(&si->sn_prl_start);
4856 profile_zero(&si->sn_prl_children);
4857 profile_get_wait(&si->sn_prl_wait);
4858 }
4859}
4860
4861/*
4862 * Called when actually executing a function line.
4863 */
4864 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004865script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004866{
4867 scriptitem_T *si;
4868
4869 if (current_SID <= 0 || current_SID > script_items.ga_len)
4870 return;
4871 si = &SCRIPT_ITEM(current_SID);
4872 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4873 si->sn_prl_execed = TRUE;
4874}
4875
4876/*
4877 * Called when done with a function line.
4878 */
4879 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004880script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004881{
4882 scriptitem_T *si;
4883 sn_prl_T *pp;
4884
4885 if (current_SID <= 0 || current_SID > script_items.ga_len)
4886 return;
4887 si = &SCRIPT_ITEM(current_SID);
4888 if (si->sn_prof_on && si->sn_prl_idx >= 0
4889 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4890 {
4891 if (si->sn_prl_execed)
4892 {
4893 pp = &PRL_ITEM(si, si->sn_prl_idx);
4894 ++pp->snp_count;
4895 profile_end(&si->sn_prl_start);
4896 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004897 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004898 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4899 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004900 }
4901 si->sn_prl_idx = -1;
4902 }
4903}
4904#endif
4905
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906/*
4907 * ":scriptencoding": Set encoding conversion for a sourced script.
4908 * Without the multi-byte feature it's simply ignored.
4909 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004911ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912{
4913#ifdef FEAT_MBYTE
4914 struct source_cookie *sp;
4915 char_u *name;
4916
4917 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4918 {
4919 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4920 return;
4921 }
4922
4923 if (*eap->arg != NUL)
4924 {
4925 name = enc_canonize(eap->arg);
4926 if (name == NULL) /* out of memory */
4927 return;
4928 }
4929 else
4930 name = eap->arg;
4931
4932 /* Setup for conversion from the specified encoding to 'encoding'. */
4933 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4934 convert_setup(&sp->conv, name, p_enc);
4935
4936 if (name != eap->arg)
4937 vim_free(name);
4938#endif
4939}
4940
4941#if defined(FEAT_EVAL) || defined(PROTO)
4942/*
4943 * ":finish": Mark a sourced file as finished.
4944 */
4945 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004946ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947{
4948 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4949 do_finish(eap, FALSE);
4950 else
4951 EMSG(_("E168: :finish used outside of a sourced file"));
4952}
4953
4954/*
4955 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4956 * Also called for a pending finish at the ":endtry" or after returning from
4957 * an extra do_cmdline(). "reanimate" is used in the latter case.
4958 */
4959 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004960do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004961{
4962 int idx;
4963
4964 if (reanimate)
4965 ((struct source_cookie *)getline_cookie(eap->getline,
4966 eap->cookie))->finished = FALSE;
4967
4968 /*
4969 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4970 * not in its finally clause (which then is to be executed next) is found.
4971 * In this case, make the ":finish" pending for execution at the ":endtry".
4972 * Otherwise, finish normally.
4973 */
4974 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4975 if (idx >= 0)
4976 {
4977 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4978 report_make_pending(CSTP_FINISH, NULL);
4979 }
4980 else
4981 ((struct source_cookie *)getline_cookie(eap->getline,
4982 eap->cookie))->finished = TRUE;
4983}
4984
4985
4986/*
4987 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4988 * message for missing ":endif".
4989 * Return FALSE when not sourcing a file.
4990 */
4991 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004992source_finished(
4993 char_u *(*fgetline)(int, void *, int),
4994 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004995{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004996 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004998 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999}
5000#endif
5001
5002#if defined(FEAT_LISTCMDS) || defined(PROTO)
5003/*
5004 * ":checktime [buffer]"
5005 */
5006 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005007ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008{
5009 buf_T *buf;
5010 int save_no_check_timestamps = no_check_timestamps;
5011
5012 no_check_timestamps = 0;
5013 if (eap->addr_count == 0) /* default is all buffers */
5014 check_timestamps(FALSE);
5015 else
5016 {
5017 buf = buflist_findnr((int)eap->line2);
5018 if (buf != NULL) /* cannot happen? */
5019 (void)buf_check_timestamp(buf, FALSE);
5020 }
5021 no_check_timestamps = save_no_check_timestamps;
5022}
5023#endif
5024
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5026 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005027# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005028static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005029
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005030 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005031get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005033 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005034
Bram Moolenaar48e330a2016-02-23 14:53:34 +01005035 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005036 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005037
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005038# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039 if (loc != NULL)
5040 {
5041 char_u *p;
5042
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005043 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
5044 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005045 p = vim_strchr(loc, '=');
5046 if (p != NULL)
5047 {
5048 loc = ++p;
5049 while (*p != NUL) /* remove trailing newline */
5050 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005051 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052 {
5053 *p = NUL;
5054 break;
5055 }
5056 ++p;
5057 }
5058 }
5059 }
5060# endif
5061
5062 return loc;
5063}
5064#endif
5065
5066
5067#ifdef WIN32
5068/*
5069 * On MS-Windows locale names are strings like "German_Germany.1252", but
5070 * gettext expects "de". Try to translate one into another here for a few
5071 * supported languages.
5072 */
5073 static char_u *
5074gettext_lang(char_u *name)
5075{
5076 int i;
5077 static char *(mtable[]) = {
5078 "afrikaans", "af",
5079 "czech", "cs",
5080 "dutch", "nl",
5081 "german", "de",
5082 "english_united kingdom", "en_GB",
5083 "spanish", "es",
5084 "french", "fr",
5085 "italian", "it",
5086 "japanese", "ja",
5087 "korean", "ko",
5088 "norwegian", "no",
5089 "polish", "pl",
5090 "russian", "ru",
5091 "slovak", "sk",
5092 "swedish", "sv",
5093 "ukrainian", "uk",
5094 "chinese_china", "zh_CN",
5095 "chinese_taiwan", "zh_TW",
5096 NULL};
5097
5098 for (i = 0; mtable[i] != NULL; i += 2)
5099 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005100 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 return name;
5102}
5103#endif
5104
5105#if defined(FEAT_MULTI_LANG) || defined(PROTO)
5106/*
5107 * Obtain the current messages language. Used to set the default for
5108 * 'helplang'. May return NULL or an empty string.
5109 */
5110 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005111get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112{
5113 char_u *p;
5114
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005115# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005117 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005118# else
5119 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00005120 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
5121 * and LC_MONETARY may be set differently for a Japanese working in the
5122 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005123 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124# endif
5125# else
5126 p = mch_getenv((char_u *)"LC_ALL");
5127 if (p == NULL || *p == NUL)
5128 {
5129 p = mch_getenv((char_u *)"LC_MESSAGES");
5130 if (p == NULL || *p == NUL)
5131 p = mch_getenv((char_u *)"LANG");
5132 }
5133# endif
5134# ifdef WIN32
5135 p = gettext_lang(p);
5136# endif
5137 return p;
5138}
5139#endif
5140
Bram Moolenaardef9e822004-12-31 20:58:58 +00005141/* Complicated #if; matches with where get_mess_env() is used below. */
5142#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5143 && defined(LC_MESSAGES))) \
5144 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5145 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
5146 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01005147static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005148
5149/*
5150 * Get the language used for messages from the environment.
5151 */
5152 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005153get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005154{
5155 char_u *p;
5156
5157 p = mch_getenv((char_u *)"LC_ALL");
5158 if (p == NULL || *p == NUL)
5159 {
5160 p = mch_getenv((char_u *)"LC_MESSAGES");
5161 if (p == NULL || *p == NUL)
5162 {
5163 p = mch_getenv((char_u *)"LANG");
5164 if (p != NULL && VIM_ISDIGIT(*p))
5165 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005166# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00005167 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005168 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169# endif
5170 }
5171 }
5172 return p;
5173}
5174#endif
5175
5176#if defined(FEAT_EVAL) || defined(PROTO)
5177
5178/*
5179 * Set the "v:lang" variable according to the current locale setting.
5180 * Also do "v:lc_time"and "v:ctype".
5181 */
5182 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005183set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184{
5185 char_u *loc;
5186
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005187# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005188 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189# else
5190 /* setlocale() not supported: use the default value */
5191 loc = (char_u *)"C";
5192# endif
5193 set_vim_var_string(VV_CTYPE, loc, -1);
5194
5195 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
5196 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005197# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005198 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199# else
5200 loc = get_mess_env();
5201# endif
5202 set_vim_var_string(VV_LANG, loc, -1);
5203
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02005204# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01005205 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005206# endif
5207 set_vim_var_string(VV_LC_TIME, loc, -1);
5208}
5209#endif
5210
5211#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
5212 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
5213/*
5214 * ":language": Set the language (locale).
5215 */
5216 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005217ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218{
5219 char *loc;
5220 char_u *p;
5221 char_u *name;
5222 int what = LC_ALL;
5223 char *whatstr = "";
5224#ifdef LC_MESSAGES
5225# define VIM_LC_MESSAGES LC_MESSAGES
5226#else
5227# define VIM_LC_MESSAGES 6789
5228#endif
5229
5230 name = eap->arg;
5231
5232 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
5233 * Allow abbreviation, but require at least 3 characters to avoid
5234 * confusion with a two letter language name "me" or "ct". */
5235 p = skiptowhite(eap->arg);
Bram Moolenaar1c465442017-03-12 20:10:05 +01005236 if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 {
5238 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
5239 {
5240 what = VIM_LC_MESSAGES;
5241 name = skipwhite(p);
5242 whatstr = "messages ";
5243 }
5244 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
5245 {
5246 what = LC_CTYPE;
5247 name = skipwhite(p);
5248 whatstr = "ctype ";
5249 }
5250 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
5251 {
5252 what = LC_TIME;
5253 name = skipwhite(p);
5254 whatstr = "time ";
5255 }
5256 }
5257
5258 if (*name == NUL)
5259 {
5260#ifndef LC_MESSAGES
5261 if (what == VIM_LC_MESSAGES)
5262 p = get_mess_env();
5263 else
5264#endif
5265 p = (char_u *)setlocale(what, NULL);
5266 if (p == NULL || *p == NUL)
5267 p = (char_u *)"Unknown";
5268 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
5269 }
5270 else
5271 {
5272#ifndef LC_MESSAGES
5273 if (what == VIM_LC_MESSAGES)
5274 loc = "";
5275 else
5276#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005277 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005278 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00005279#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
5280 /* Make sure strtod() uses a decimal point, not a comma. */
5281 setlocale(LC_NUMERIC, "C");
5282#endif
5283 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005284 if (loc == NULL)
5285 EMSG2(_("E197: Cannot set language to \"%s\""), name);
5286 else
5287 {
5288#ifdef HAVE_NL_MSG_CAT_CNTR
5289 /* Need to do this for GNU gettext, otherwise cached translations
5290 * will be used again. */
5291 extern int _nl_msg_cat_cntr;
5292
5293 ++_nl_msg_cat_cntr;
5294#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00005295 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005296 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
5297
5298 if (what != LC_TIME)
5299 {
5300 /* Tell gettext() what to translate to. It apparently doesn't
5301 * use the currently effective locale. Also do this when
5302 * FEAT_GETTEXT isn't defined, so that shell commands use this
5303 * value. */
5304 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005305 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005306 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02005307
5308 /* Clear $LANGUAGE because GNU gettext uses it. */
5309 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00005310# ifdef WIN32
5311 /* Apparently MS-Windows printf() may cause a crash when
5312 * we give it 8-bit text while it's expecting text in the
5313 * current locale. This call avoids that. */
5314 setlocale(LC_CTYPE, "C");
5315# endif
5316 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005317 if (what != LC_CTYPE)
5318 {
5319 char_u *mname;
5320#ifdef WIN32
5321 mname = gettext_lang(name);
5322#else
5323 mname = name;
5324#endif
5325 vim_setenv((char_u *)"LC_MESSAGES", mname);
5326#ifdef FEAT_MULTI_LANG
5327 set_helplang_default(mname);
5328#endif
5329 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005330 }
5331
5332# ifdef FEAT_EVAL
5333 /* Set v:lang, v:lc_time and v:ctype to the final result. */
5334 set_lang_var();
5335# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02005336# ifdef FEAT_TITLE
5337 maketitle();
5338# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005339 }
5340 }
5341}
5342
5343# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005344
5345static char_u **locales = NULL; /* Array of all available locales */
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005346
5347# ifndef WIN32
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005348static int did_init_locales = FALSE;
5349
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005350/* Return an array of strings for all available locales + NULL for the
5351 * last element. Return NULL in case of error. */
5352 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005353find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005354{
5355 garray_T locales_ga;
5356 char_u *loc;
5357
5358 /* Find all available locales by running command "locale -a". If this
5359 * doesn't work we won't have completion. */
5360 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02005361 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005362 if (locale_a == NULL)
5363 return NULL;
5364 ga_init2(&locales_ga, sizeof(char_u *), 20);
5365
5366 /* Transform locale_a string where each locale is separated by "\n"
5367 * into an array of locale strings. */
5368 loc = (char_u *)strtok((char *)locale_a, "\n");
5369
5370 while (loc != NULL)
5371 {
5372 if (ga_grow(&locales_ga, 1) == FAIL)
5373 break;
5374 loc = vim_strsave(loc);
5375 if (loc == NULL)
5376 break;
5377
5378 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5379 loc = (char_u *)strtok(NULL, "\n");
5380 }
5381 vim_free(locale_a);
5382 if (ga_grow(&locales_ga, 1) == FAIL)
5383 {
5384 ga_clear(&locales_ga);
5385 return NULL;
5386 }
5387 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5388 return (char_u **)locales_ga.ga_data;
5389}
Bram Moolenaarb8f7bd62017-01-12 20:28:25 +01005390# endif
5391
5392/*
5393 * Lazy initialization of all available locales.
5394 */
5395 static void
5396init_locales(void)
5397{
5398# ifndef WIN32
5399 if (!did_init_locales)
5400 {
5401 did_init_locales = TRUE;
5402 locales = find_locales();
5403 }
5404# endif
5405}
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005406
5407# if defined(EXITFREE) || defined(PROTO)
5408 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005409free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005410{
5411 int i;
5412 if (locales != NULL)
5413 {
5414 for (i = 0; locales[i] != NULL; i++)
5415 vim_free(locales[i]);
5416 vim_free(locales);
5417 locales = NULL;
5418 }
5419}
5420# endif
5421
Bram Moolenaar071d4272004-06-13 20:20:40 +00005422/*
5423 * Function given to ExpandGeneric() to obtain the possible arguments of the
5424 * ":language" command.
5425 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005426 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005427get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005428{
5429 if (idx == 0)
5430 return (char_u *)"messages";
5431 if (idx == 1)
5432 return (char_u *)"ctype";
5433 if (idx == 2)
5434 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005435
5436 init_locales();
5437 if (locales == NULL)
5438 return NULL;
5439 return locales[idx - 3];
5440}
5441
5442/*
5443 * Function given to ExpandGeneric() to obtain the available locales.
5444 */
5445 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005446get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005447{
5448 init_locales();
5449 if (locales == NULL)
5450 return NULL;
5451 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452}
5453# endif
5454
5455#endif