blob: c8980b44b70e6d5019276a441df538bc40da93b6 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * ex_cmds2.c: some more functions for command line commands
12 */
13
Bram Moolenaar071d4272004-06-13 20:20:40 +000014#include "vim.h"
Bram Moolenaar071d4272004-06-13 20:20:40 +000015#include "version.h"
16
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010017static void cmd_source(char_u *fname, exarg_T *eap);
Bram Moolenaar071d4272004-06-13 20:20:40 +000018
Bram Moolenaar05159a02005-02-26 23:04:13 +000019#ifdef FEAT_EVAL
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000020/* Growarray to store info about already sourced scripts.
Bram Moolenaar05159a02005-02-26 23:04:13 +000021 * For Unix also store the dev/ino, so that we don't have to stat() each
22 * script when going through the list. */
23typedef struct scriptitem_S
24{
25 char_u *sn_name;
26# ifdef UNIX
Bram Moolenaarbf0c4522009-05-16 19:16:33 +000027 int sn_dev_valid;
28 dev_t sn_dev;
Bram Moolenaar05159a02005-02-26 23:04:13 +000029 ino_t sn_ino;
30# endif
31# ifdef FEAT_PROFILE
32 int sn_prof_on; /* TRUE when script is/was profiled */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +000033 int sn_pr_force; /* forceit: profile functions in this script */
Bram Moolenaar05159a02005-02-26 23:04:13 +000034 proftime_T sn_pr_child; /* time set when going into first child */
35 int sn_pr_nest; /* nesting for sn_pr_child */
36 /* profiling the script as a whole */
37 int sn_pr_count; /* nr of times sourced */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000038 proftime_T sn_pr_total; /* time spent in script + children */
39 proftime_T sn_pr_self; /* time spent in script itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000040 proftime_T sn_pr_start; /* time at script start */
41 proftime_T sn_pr_children; /* time in children after script start */
42 /* profiling the script per line */
43 garray_T sn_prl_ga; /* things stored for every line */
44 proftime_T sn_prl_start; /* start time for current line */
45 proftime_T sn_prl_children; /* time spent in children for this line */
46 proftime_T sn_prl_wait; /* wait start time for current line */
47 int sn_prl_idx; /* index of line being timed; -1 if none */
48 int sn_prl_execed; /* line being timed was executed */
49# endif
50} scriptitem_T;
51
52static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
53#define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1])
54
55# ifdef FEAT_PROFILE
56/* Struct used in sn_prl_ga for every line of a script. */
57typedef struct sn_prl_S
58{
59 int snp_count; /* nr of times line was executed */
Bram Moolenaar8c8de832008-06-24 22:58:06 +000060 proftime_T sn_prl_total; /* time spent in a line + children */
61 proftime_T sn_prl_self; /* time spent in a line itself */
Bram Moolenaar05159a02005-02-26 23:04:13 +000062} sn_prl_T;
63
64# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
65# endif
66#endif
67
Bram Moolenaar071d4272004-06-13 20:20:40 +000068#if defined(FEAT_EVAL) || defined(PROTO)
69static int debug_greedy = FALSE; /* batch mode debugging: don't save
70 and restore typeahead. */
Bram Moolenaarf1f60f82016-01-16 15:40:53 +010071static int get_maxbacktrace_level(void);
72static void do_setdebugtracelevel(char_u *arg);
73static void do_checkbacktracelevel(void);
74static void do_showbacktrace(char_u *cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +000075
76/*
77 * do_debug(): Debug mode.
78 * Repeatedly get Ex commands, until told to continue normal execution.
79 */
80 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +010081do_debug(char_u *cmd)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082{
83 int save_msg_scroll = msg_scroll;
84 int save_State = State;
85 int save_did_emsg = did_emsg;
86 int save_cmd_silent = cmd_silent;
87 int save_msg_silent = msg_silent;
88 int save_emsg_silent = emsg_silent;
89 int save_redir_off = redir_off;
90 tasave_T typeaheadbuf;
Bram Moolenaaree3f7a52008-01-01 13:17:56 +000091 int typeahead_saved = FALSE;
Bram Moolenaar383c6f52008-01-04 15:01:07 +000092 int save_ignore_script = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +000093 int save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 int n;
95 char_u *cmdline = NULL;
96 char_u *p;
97 char *tail = NULL;
98 static int last_cmd = 0;
99#define CMD_CONT 1
100#define CMD_NEXT 2
101#define CMD_STEP 3
102#define CMD_FINISH 4
103#define CMD_QUIT 5
104#define CMD_INTERRUPT 6
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100105#define CMD_BACKTRACE 7
106#define CMD_FRAME 8
107#define CMD_UP 9
108#define CMD_DOWN 10
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109
110#ifdef ALWAYS_USE_GUI
111 /* Can't do this when there is no terminal for input/output. */
112 if (!gui.in_use)
113 {
114 /* Break as soon as possible. */
115 debug_break_level = 9999;
116 return;
117 }
118#endif
119
120 /* Make sure we are in raw mode and start termcap mode. Might have side
121 * effects... */
122 settmode(TMODE_RAW);
123 starttermcap();
124
125 ++RedrawingDisabled; /* don't redisplay the window */
126 ++no_wait_return; /* don't wait for return */
127 did_emsg = FALSE; /* don't use error from debugged stuff */
128 cmd_silent = FALSE; /* display commands */
129 msg_silent = FALSE; /* display messages */
130 emsg_silent = FALSE; /* display error messages */
131 redir_off = TRUE; /* don't redirect debug commands */
132
133 State = NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
135 if (!debug_did_msg)
136 MSG(_("Entering Debug mode. Type \"cont\" to continue."));
137 if (sourcing_name != NULL)
138 msg(sourcing_name);
139 if (sourcing_lnum != 0)
Bram Moolenaar555b2802005-05-19 21:08:39 +0000140 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141 else
Bram Moolenaar555b2802005-05-19 21:08:39 +0000142 smsg((char_u *)_("cmd: %s"), cmd);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
144 /*
145 * Repeat getting a command and executing it.
146 */
147 for (;;)
148 {
149 msg_scroll = TRUE;
150 need_wait_return = FALSE;
Bram Moolenaar85b11762016-02-27 18:13:23 +0100151
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152 /* Save the current typeahead buffer and replace it with an empty one.
153 * This makes sure we get input from the user here and don't interfere
154 * with the commands being executed. Reset "ex_normal_busy" to avoid
155 * the side effects of using ":normal". Save the stuff buffer and make
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000156 * it empty. Set ignore_script to avoid reading from script input. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157 save_ex_normal_busy = ex_normal_busy;
158 ex_normal_busy = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159 if (!debug_greedy)
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000160 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161 save_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000162 typeahead_saved = TRUE;
163 save_ignore_script = ignore_script;
164 ignore_script = TRUE;
165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166
Bram Moolenaardc303bc2016-05-17 17:45:38 +0200167 vim_free(cmdline);
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +0000168 cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000170 if (typeahead_saved)
171 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172 restore_typeahead(&typeaheadbuf);
Bram Moolenaaree3f7a52008-01-01 13:17:56 +0000173 ignore_script = save_ignore_script;
174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175 ex_normal_busy = save_ex_normal_busy;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176
177 cmdline_row = msg_row;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100178 msg_starthere();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 if (cmdline != NULL)
180 {
181 /* If this is a debug command, set "last_cmd".
182 * If not, reset "last_cmd".
183 * For a blank line use previous command. */
184 p = skipwhite(cmdline);
185 if (*p != NUL)
186 {
187 switch (*p)
188 {
189 case 'c': last_cmd = CMD_CONT;
190 tail = "ont";
191 break;
192 case 'n': last_cmd = CMD_NEXT;
193 tail = "ext";
194 break;
195 case 's': last_cmd = CMD_STEP;
196 tail = "tep";
197 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100198 case 'f':
199 last_cmd = 0;
200 if (p[1] == 'r')
201 {
202 last_cmd = CMD_FRAME;
203 tail = "rame";
204 }
205 else
206 {
207 last_cmd = CMD_FINISH;
208 tail = "inish";
209 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210 break;
211 case 'q': last_cmd = CMD_QUIT;
212 tail = "uit";
213 break;
214 case 'i': last_cmd = CMD_INTERRUPT;
215 tail = "nterrupt";
216 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100217 case 'b': last_cmd = CMD_BACKTRACE;
218 if (p[1] == 't')
219 tail = "t";
220 else
221 tail = "acktrace";
222 break;
223 case 'w': last_cmd = CMD_BACKTRACE;
224 tail = "here";
225 break;
226 case 'u': last_cmd = CMD_UP;
227 tail = "p";
228 break;
229 case 'd': last_cmd = CMD_DOWN;
230 tail = "own";
231 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 default: last_cmd = 0;
233 }
234 if (last_cmd != 0)
235 {
236 /* Check that the tail matches. */
237 ++p;
238 while (*p != NUL && *p == *tail)
239 {
240 ++p;
241 ++tail;
242 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100243 if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 last_cmd = 0;
245 }
246 }
247
248 if (last_cmd != 0)
249 {
250 /* Execute debug command: decided where to break next and
251 * return. */
252 switch (last_cmd)
253 {
254 case CMD_CONT:
255 debug_break_level = -1;
256 break;
257 case CMD_NEXT:
258 debug_break_level = ex_nesting_level;
259 break;
260 case CMD_STEP:
261 debug_break_level = 9999;
262 break;
263 case CMD_FINISH:
264 debug_break_level = ex_nesting_level - 1;
265 break;
266 case CMD_QUIT:
267 got_int = TRUE;
268 debug_break_level = -1;
269 break;
270 case CMD_INTERRUPT:
271 got_int = TRUE;
272 debug_break_level = 9999;
273 /* Do not repeat ">interrupt" cmd, continue stepping. */
274 last_cmd = CMD_STEP;
275 break;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100276 case CMD_BACKTRACE:
277 do_showbacktrace(cmd);
278 continue;
279 case CMD_FRAME:
280 if (*p == NUL)
281 {
282 do_showbacktrace(cmd);
283 }
284 else
285 {
286 p = skipwhite(p);
287 do_setdebugtracelevel(p);
288 }
289 continue;
290 case CMD_UP:
291 debug_backtrace_level++;
292 do_checkbacktracelevel();
293 continue;
294 case CMD_DOWN:
295 debug_backtrace_level--;
296 do_checkbacktracelevel();
297 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000298 }
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100299 /* Going out reset backtrace_level */
300 debug_backtrace_level = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 break;
302 }
303
304 /* don't debug this command */
305 n = debug_break_level;
306 debug_break_level = -1;
307 (void)do_cmdline(cmdline, getexline, NULL,
308 DOCMD_VERBOSE|DOCMD_EXCRESET);
309 debug_break_level = n;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 }
311 lines_left = Rows - 1;
312 }
313 vim_free(cmdline);
314
315 --RedrawingDisabled;
316 --no_wait_return;
317 redraw_all_later(NOT_VALID);
318 need_wait_return = FALSE;
319 msg_scroll = save_msg_scroll;
320 lines_left = Rows - 1;
321 State = save_State;
322 did_emsg = save_did_emsg;
323 cmd_silent = save_cmd_silent;
324 msg_silent = save_msg_silent;
325 emsg_silent = save_emsg_silent;
326 redir_off = save_redir_off;
327
328 /* Only print the message again when typing a command before coming back
329 * here. */
330 debug_did_msg = TRUE;
331}
332
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100333 static int
334get_maxbacktrace_level(void)
335{
336 char *p, *q;
Bram Moolenaardc633cf2016-04-23 14:33:19 +0200337 int maxbacktrace = 0;
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100338
Bram Moolenaarf1f60f82016-01-16 15:40:53 +0100339 if (sourcing_name != NULL)
340 {
341 p = (char *)sourcing_name;
342 while ((q = strstr(p, "..")) != NULL)
343 {
344 p = q + 2;
345 maxbacktrace++;
346 }
347 }
348 return maxbacktrace;
349}
350
351 static void
352do_setdebugtracelevel(char_u *arg)
353{
354 int level;
355
356 level = atoi((char *)arg);
357 if (*arg == '+' || level < 0)
358 debug_backtrace_level += level;
359 else
360 debug_backtrace_level = level;
361
362 do_checkbacktracelevel();
363}
364
365 static void
366do_checkbacktracelevel(void)
367{
368 if (debug_backtrace_level < 0)
369 {
370 debug_backtrace_level = 0;
371 MSG(_("frame is zero"));
372 }
373 else
374 {
375 int max = get_maxbacktrace_level();
376
377 if (debug_backtrace_level > max)
378 {
379 debug_backtrace_level = max;
380 smsg((char_u *)_("frame at highest level: %d"), max);
381 }
382 }
383}
384
385 static void
386do_showbacktrace(char_u *cmd)
387{
388 char *cur;
389 char *next;
390 int i = 0;
391 int max = get_maxbacktrace_level();
392
393 if (sourcing_name != NULL)
394 {
395 cur = (char *)sourcing_name;
396 while (!got_int)
397 {
398 next = strstr(cur, "..");
399 if (next != NULL)
400 *next = NUL;
401 if (i == max - debug_backtrace_level)
402 smsg((char_u *)"->%d %s", max - i, cur);
403 else
404 smsg((char_u *)" %d %s", max - i, cur);
405 ++i;
406 if (next == NULL)
407 break;
408 *next = '.';
409 cur = next + 2;
410 }
411 }
412 if (sourcing_lnum != 0)
413 smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
414 else
415 smsg((char_u *)_("cmd: %s"), cmd);
416}
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418/*
419 * ":debug".
420 */
421 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100422ex_debug(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423{
424 int debug_break_level_save = debug_break_level;
425
426 debug_break_level = 9999;
427 do_cmdline_cmd(eap->arg);
428 debug_break_level = debug_break_level_save;
429}
430
431static char_u *debug_breakpoint_name = NULL;
432static linenr_T debug_breakpoint_lnum;
433
434/*
435 * When debugging or a breakpoint is set on a skipped command, no debug prompt
436 * is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
437 * debug_skipped_name is then set to the source name in the breakpoint case. If
438 * a skipped command decides itself that a debug prompt should be displayed, it
439 * can do so by calling dbg_check_skipped().
440 */
441static int debug_skipped;
442static char_u *debug_skipped_name;
443
444/*
445 * Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
446 * at or below the break level. But only when the line is actually
447 * executed. Return TRUE and set breakpoint_name for skipped commands that
448 * decide to execute something themselves.
449 * Called from do_one_cmd() before executing a command.
450 */
451 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100452dbg_check_breakpoint(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453{
454 char_u *p;
455
456 debug_skipped = FALSE;
457 if (debug_breakpoint_name != NULL)
458 {
459 if (!eap->skip)
460 {
461 /* replace K_SNR with "<SNR>" */
462 if (debug_breakpoint_name[0] == K_SPECIAL
463 && debug_breakpoint_name[1] == KS_EXTRA
464 && debug_breakpoint_name[2] == (int)KE_SNR)
465 p = (char_u *)"<SNR>";
466 else
467 p = (char_u *)"";
Bram Moolenaar555b2802005-05-19 21:08:39 +0000468 smsg((char_u *)_("Breakpoint in \"%s%s\" line %ld"),
469 p,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 debug_breakpoint_name + (*p == NUL ? 0 : 3),
471 (long)debug_breakpoint_lnum);
472 debug_breakpoint_name = NULL;
473 do_debug(eap->cmd);
474 }
475 else
476 {
477 debug_skipped = TRUE;
478 debug_skipped_name = debug_breakpoint_name;
479 debug_breakpoint_name = NULL;
480 }
481 }
482 else if (ex_nesting_level <= debug_break_level)
483 {
484 if (!eap->skip)
485 do_debug(eap->cmd);
486 else
487 {
488 debug_skipped = TRUE;
489 debug_skipped_name = NULL;
490 }
491 }
492}
493
494/*
495 * Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
496 * set. Return TRUE when the debug mode is entered this time.
497 */
498 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100499dbg_check_skipped(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500{
501 int prev_got_int;
502
503 if (debug_skipped)
504 {
505 /*
506 * Save the value of got_int and reset it. We don't want a previous
507 * interruption cause flushing the input buffer.
508 */
509 prev_got_int = got_int;
510 got_int = FALSE;
511 debug_breakpoint_name = debug_skipped_name;
512 /* eap->skip is TRUE */
513 eap->skip = FALSE;
514 (void)dbg_check_breakpoint(eap);
515 eap->skip = TRUE;
516 got_int |= prev_got_int;
517 return TRUE;
518 }
519 return FALSE;
520}
521
522/*
523 * The list of breakpoints: dbg_breakp.
524 * This is a grow-array of structs.
525 */
526struct debuggy
527{
528 int dbg_nr; /* breakpoint number */
529 int dbg_type; /* DBG_FUNC or DBG_FILE */
530 char_u *dbg_name; /* function or file name */
531 regprog_T *dbg_prog; /* regexp program */
532 linenr_T dbg_lnum; /* line number in function or file */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000533 int dbg_forceit; /* ! used */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534};
535
536static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
Bram Moolenaar05159a02005-02-26 23:04:13 +0000537#define BREAKP(idx) (((struct debuggy *)dbg_breakp.ga_data)[idx])
538#define DEBUGGY(gap, idx) (((struct debuggy *)gap->ga_data)[idx])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539static int last_breakp = 0; /* nr of last defined breakpoint */
540
Bram Moolenaar05159a02005-02-26 23:04:13 +0000541#ifdef FEAT_PROFILE
542/* Profiling uses file and func names similar to breakpoints. */
543static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545#define DBG_FUNC 1
546#define DBG_FILE 2
547
Bram Moolenaarf28dbce2016-01-29 22:03:47 +0100548static int dbg_parsearg(char_u *arg, garray_T *gap);
549static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T *gap, int *fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
551/*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000552 * Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
553 * in the entry just after the last one in dbg_breakp. Note that "dbg_name"
554 * is allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 * Returns FAIL for failure.
556 */
557 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100558dbg_parsearg(
559 char_u *arg,
560 garray_T *gap) /* either &dbg_breakp or &prof_ga */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
562 char_u *p = arg;
563 char_u *q;
564 struct debuggy *bp;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000565 int here = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566
Bram Moolenaar05159a02005-02-26 23:04:13 +0000567 if (ga_grow(gap, 1) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 return FAIL;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000569 bp = &DEBUGGY(gap, gap->ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570
571 /* Find "func" or "file". */
572 if (STRNCMP(p, "func", 4) == 0)
573 bp->dbg_type = DBG_FUNC;
574 else if (STRNCMP(p, "file", 4) == 0)
575 bp->dbg_type = DBG_FILE;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000576 else if (
577#ifdef FEAT_PROFILE
578 gap != &prof_ga &&
579#endif
580 STRNCMP(p, "here", 4) == 0)
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000581 {
582 if (curbuf->b_ffname == NULL)
583 {
584 EMSG(_(e_noname));
585 return FAIL;
586 }
587 bp->dbg_type = DBG_FILE;
588 here = TRUE;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 else
591 {
592 EMSG2(_(e_invarg2), p);
593 return FAIL;
594 }
595 p = skipwhite(p + 4);
596
597 /* Find optional line number. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000598 if (here)
599 bp->dbg_lnum = curwin->w_cursor.lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000600 else if (
601#ifdef FEAT_PROFILE
602 gap != &prof_ga &&
603#endif
604 VIM_ISDIGIT(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 {
606 bp->dbg_lnum = getdigits(&p);
607 p = skipwhite(p);
608 }
609 else
610 bp->dbg_lnum = 0;
611
612 /* Find the function or file name. Don't accept a function name with (). */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000613 if ((!here && *p == NUL)
614 || (here && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL))
616 {
617 EMSG2(_(e_invarg2), arg);
618 return FAIL;
619 }
620
621 if (bp->dbg_type == DBG_FUNC)
622 bp->dbg_name = vim_strsave(p);
Bram Moolenaarf4b8e572004-06-24 15:53:16 +0000623 else if (here)
624 bp->dbg_name = vim_strsave(curbuf->b_ffname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 else
626 {
627 /* Expand the file name in the same way as do_source(). This means
628 * doing it twice, so that $DIR/file gets expanded when $DIR is
629 * "~/dir". */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 q = expand_env_save(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 if (q == NULL)
632 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 p = expand_env_save(q);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 vim_free(q);
635 if (p == NULL)
636 return FAIL;
Bram Moolenaar843ee412004-06-30 16:16:41 +0000637 if (*p != '*')
638 {
639 bp->dbg_name = fix_fname(p);
640 vim_free(p);
641 }
642 else
643 bp->dbg_name = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 }
645
646 if (bp->dbg_name == NULL)
647 return FAIL;
648 return OK;
649}
650
651/*
652 * ":breakadd".
653 */
654 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100655ex_breakadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656{
657 struct debuggy *bp;
658 char_u *pat;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000659 garray_T *gap;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
Bram Moolenaar05159a02005-02-26 23:04:13 +0000661 gap = &dbg_breakp;
662#ifdef FEAT_PROFILE
663 if (eap->cmdidx == CMD_profile)
664 gap = &prof_ga;
665#endif
666
667 if (dbg_parsearg(eap->arg, gap) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000669 bp = &DEBUGGY(gap, gap->ga_len);
670 bp->dbg_forceit = eap->forceit;
671
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, FALSE);
673 if (pat != NULL)
674 {
675 bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
676 vim_free(pat);
677 }
678 if (pat == NULL || bp->dbg_prog == NULL)
679 vim_free(bp->dbg_name);
680 else
681 {
682 if (bp->dbg_lnum == 0) /* default line number is 1 */
683 bp->dbg_lnum = 1;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000684#ifdef FEAT_PROFILE
685 if (eap->cmdidx != CMD_profile)
686#endif
687 {
688 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
689 ++debug_tick;
690 }
691 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 }
693 }
694}
695
696/*
697 * ":debuggreedy".
698 */
699 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100700ex_debuggreedy(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701{
702 if (eap->addr_count == 0 || eap->line2 != 0)
703 debug_greedy = TRUE;
704 else
705 debug_greedy = FALSE;
706}
707
708/*
Bram Moolenaard9fba312005-06-26 22:34:35 +0000709 * ":breakdel" and ":profdel".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 */
711 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100712ex_breakdel(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713{
714 struct debuggy *bp, *bpi;
715 int nr;
716 int todel = -1;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000717 int del_all = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 int i;
719 linenr_T best_lnum = 0;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000720 garray_T *gap;
721
722 gap = &dbg_breakp;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000723 if (eap->cmdidx == CMD_profdel)
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200724 {
725#ifdef FEAT_PROFILE
Bram Moolenaard9fba312005-06-26 22:34:35 +0000726 gap = &prof_ga;
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200727#else
728 ex_ni(eap);
729 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000730#endif
Bram Moolenaar38bdbd62012-06-20 15:48:57 +0200731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (vim_isdigit(*eap->arg))
734 {
735 /* ":breakdel {nr}" */
736 nr = atol((char *)eap->arg);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000737 for (i = 0; i < gap->ga_len; ++i)
738 if (DEBUGGY(gap, i).dbg_nr == nr)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 {
740 todel = i;
741 break;
742 }
743 }
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000744 else if (*eap->arg == '*')
745 {
746 todel = 0;
747 del_all = TRUE;
748 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 else
750 {
751 /* ":breakdel {func|file} [lnum] {name}" */
Bram Moolenaard9fba312005-06-26 22:34:35 +0000752 if (dbg_parsearg(eap->arg, gap) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 return;
Bram Moolenaard9fba312005-06-26 22:34:35 +0000754 bp = &DEBUGGY(gap, gap->ga_len);
755 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000757 bpi = &DEBUGGY(gap, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 if (bp->dbg_type == bpi->dbg_type
759 && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
760 && (bp->dbg_lnum == bpi->dbg_lnum
761 || (bp->dbg_lnum == 0
762 && (best_lnum == 0
763 || bpi->dbg_lnum < best_lnum))))
764 {
765 todel = i;
766 best_lnum = bpi->dbg_lnum;
767 }
768 }
769 vim_free(bp->dbg_name);
770 }
771
772 if (todel < 0)
773 EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
774 else
Bram Moolenaard9fba312005-06-26 22:34:35 +0000775 {
776 while (gap->ga_len > 0)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000777 {
Bram Moolenaard9fba312005-06-26 22:34:35 +0000778 vim_free(DEBUGGY(gap, todel).dbg_name);
Bram Moolenaar473de612013-06-08 18:19:48 +0200779 vim_regfree(DEBUGGY(gap, todel).dbg_prog);
Bram Moolenaard9fba312005-06-26 22:34:35 +0000780 --gap->ga_len;
781 if (todel < gap->ga_len)
782 mch_memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
783 (gap->ga_len - todel) * sizeof(struct debuggy));
784#ifdef FEAT_PROFILE
785 if (eap->cmdidx == CMD_breakdel)
786#endif
787 ++debug_tick;
Bram Moolenaarf461c8e2005-06-25 23:04:51 +0000788 if (!del_all)
789 break;
790 }
Bram Moolenaard9fba312005-06-26 22:34:35 +0000791
792 /* If all breakpoints were removed clear the array. */
793 if (gap->ga_len == 0)
794 ga_clear(gap);
795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796}
797
798/*
799 * ":breaklist".
800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100802ex_breaklist(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803{
804 struct debuggy *bp;
805 int i;
806
807 if (dbg_breakp.ga_len == 0)
808 MSG(_("No breakpoints defined"));
809 else
810 for (i = 0; i < dbg_breakp.ga_len; ++i)
811 {
812 bp = &BREAKP(i);
Bram Moolenaard58ea072011-06-26 04:25:30 +0200813 if (bp->dbg_type == DBG_FILE)
814 home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 smsg((char_u *)_("%3d %s %s line %ld"),
816 bp->dbg_nr,
817 bp->dbg_type == DBG_FUNC ? "func" : "file",
Bram Moolenaard58ea072011-06-26 04:25:30 +0200818 bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 (long)bp->dbg_lnum);
820 }
821}
822
823/*
824 * Find a breakpoint for a function or sourced file.
825 * Returns line number at which to break; zero when no matching breakpoint.
826 */
827 linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100828dbg_find_breakpoint(
829 int file, /* TRUE for a file, FALSE for a function */
830 char_u *fname, /* file or function name */
831 linenr_T after) /* after this line number */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832{
Bram Moolenaar05159a02005-02-26 23:04:13 +0000833 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
834}
835
836#if defined(FEAT_PROFILE) || defined(PROTO)
837/*
838 * Return TRUE if profiling is on for a function or sourced file.
839 */
840 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100841has_profiling(
842 int file, /* TRUE for a file, FALSE for a function */
843 char_u *fname, /* file or function name */
844 int *fp) /* return: forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000845{
846 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
847 != (linenr_T)0);
848}
849#endif
850
851/*
852 * Common code for dbg_find_breakpoint() and has_profiling().
853 */
854 static linenr_T
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100855debuggy_find(
856 int file, /* TRUE for a file, FALSE for a function */
857 char_u *fname, /* file or function name */
858 linenr_T after, /* after this line number */
859 garray_T *gap, /* either &dbg_breakp or &prof_ga */
860 int *fp) /* if not NULL: return forceit */
Bram Moolenaar05159a02005-02-26 23:04:13 +0000861{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 struct debuggy *bp;
863 int i;
864 linenr_T lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 char_u *name = fname;
866 int prev_got_int;
867
Bram Moolenaar05159a02005-02-26 23:04:13 +0000868 /* Return quickly when there are no breakpoints. */
869 if (gap->ga_len == 0)
870 return (linenr_T)0;
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 /* Replace K_SNR in function name with "<SNR>". */
873 if (!file && fname[0] == K_SPECIAL)
874 {
875 name = alloc((unsigned)STRLEN(fname) + 3);
876 if (name == NULL)
877 name = fname;
878 else
879 {
880 STRCPY(name, "<SNR>");
881 STRCPY(name + 5, fname + 3);
882 }
883 }
884
Bram Moolenaar05159a02005-02-26 23:04:13 +0000885 for (i = 0; i < gap->ga_len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 {
Bram Moolenaar05159a02005-02-26 23:04:13 +0000887 /* Skip entries that are not useful or are for a line that is beyond
888 * an already found breakpoint. */
889 bp = &DEBUGGY(gap, i);
890 if (((bp->dbg_type == DBG_FILE) == file && (
891#ifdef FEAT_PROFILE
892 gap == &prof_ga ||
893#endif
894 (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 /*
Bram Moolenaar05159a02005-02-26 23:04:13 +0000897 * Save the value of got_int and reset it. We don't want a
898 * previous interruption cancel matching, only hitting CTRL-C
899 * while matching should abort it.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 */
901 prev_got_int = got_int;
902 got_int = FALSE;
Bram Moolenaardffa5b82014-11-19 16:38:07 +0100903 if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0))
Bram Moolenaar05159a02005-02-26 23:04:13 +0000904 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 lnum = bp->dbg_lnum;
Bram Moolenaar05159a02005-02-26 23:04:13 +0000906 if (fp != NULL)
907 *fp = bp->dbg_forceit;
908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 got_int |= prev_got_int;
910 }
911 }
912 if (name != fname)
913 vim_free(name);
914
915 return lnum;
916}
917
918/*
919 * Called when a breakpoint was encountered.
920 */
921 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100922dbg_breakpoint(char_u *name, linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923{
924 /* We need to check if this line is actually executed in do_one_cmd() */
925 debug_breakpoint_name = name;
926 debug_breakpoint_lnum = lnum;
927}
Bram Moolenaar05159a02005-02-26 23:04:13 +0000928
929
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000930# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000931/*
932 * Store the current time in "tm".
933 */
934 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100935profile_start(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000936{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000937# ifdef WIN3264
938 QueryPerformanceCounter(tm);
939# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000940 gettimeofday(tm, NULL);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000941# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000942}
943
944/*
945 * Compute the elapsed time from "tm" till now and store in "tm".
946 */
947 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100948profile_end(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000949{
950 proftime_T now;
951
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000952# ifdef WIN3264
953 QueryPerformanceCounter(&now);
954 tm->QuadPart = now.QuadPart - tm->QuadPart;
955# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000956 gettimeofday(&now, NULL);
957 tm->tv_usec = now.tv_usec - tm->tv_usec;
958 tm->tv_sec = now.tv_sec - tm->tv_sec;
959 if (tm->tv_usec < 0)
960 {
961 tm->tv_usec += 1000000;
962 --tm->tv_sec;
963 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000964# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000965}
966
967/*
968 * Subtract the time "tm2" from "tm".
969 */
970 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100971profile_sub(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +0000972{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000973# ifdef WIN3264
974 tm->QuadPart -= tm2->QuadPart;
975# else
Bram Moolenaar05159a02005-02-26 23:04:13 +0000976 tm->tv_usec -= tm2->tv_usec;
977 tm->tv_sec -= tm2->tv_sec;
978 if (tm->tv_usec < 0)
979 {
980 tm->tv_usec += 1000000;
981 --tm->tv_sec;
982 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +0000983# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +0000984}
985
986/*
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000987 * Return a string that represents the time in "tm".
988 * Uses a static buffer!
989 */
990 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +0100991profile_msg(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +0000992{
993 static char buf[50];
994
995# ifdef WIN3264
996 LARGE_INTEGER fr;
997
998 QueryPerformanceFrequency(&fr);
999 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
1000# else
1001 sprintf(buf, "%3ld.%06ld", (long)tm->tv_sec, (long)tm->tv_usec);
Bram Moolenaar76929292008-01-06 19:07:36 +00001002# endif
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001003 return buf;
1004}
1005
Bram Moolenaar79c2c882016-02-07 21:19:28 +01001006# if defined(FEAT_FLOAT) || defined(PROTO)
1007/*
1008 * Return a float that represents the time in "tm".
1009 */
1010 float_T
1011profile_float(proftime_T *tm)
1012{
1013# ifdef WIN3264
1014 LARGE_INTEGER fr;
1015
1016 QueryPerformanceFrequency(&fr);
1017 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
1018# else
1019 return (float_T)tm->tv_sec + (float_T)tm->tv_usec / 1000000.0;
1020# endif
1021}
1022# endif
1023
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001024/*
Bram Moolenaar76929292008-01-06 19:07:36 +00001025 * Put the time "msec" past now in "tm".
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001026 */
Bram Moolenaar76929292008-01-06 19:07:36 +00001027 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001028profile_setlimit(long msec, proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001029{
1030 if (msec <= 0) /* no limit */
1031 profile_zero(tm);
1032 else
1033 {
1034# ifdef WIN3264
1035 LARGE_INTEGER fr;
1036
1037 QueryPerformanceCounter(tm);
1038 QueryPerformanceFrequency(&fr);
Bram Moolenaarb3c70982008-01-18 10:40:55 +00001039 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
Bram Moolenaar76929292008-01-06 19:07:36 +00001040# else
1041 long usec;
1042
1043 gettimeofday(tm, NULL);
1044 usec = (long)tm->tv_usec + (long)msec * 1000;
1045 tm->tv_usec = usec % 1000000L;
1046 tm->tv_sec += usec / 1000000L;
1047# endif
1048 }
1049}
1050
1051/*
1052 * Return TRUE if the current time is past "tm".
1053 */
1054 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001055profile_passed_limit(proftime_T *tm)
Bram Moolenaar76929292008-01-06 19:07:36 +00001056{
1057 proftime_T now;
1058
1059# ifdef WIN3264
1060 if (tm->QuadPart == 0) /* timer was not set */
1061 return FALSE;
1062 QueryPerformanceCounter(&now);
1063 return (now.QuadPart > tm->QuadPart);
1064# else
1065 if (tm->tv_sec == 0) /* timer was not set */
1066 return FALSE;
1067 gettimeofday(&now, NULL);
1068 return (now.tv_sec > tm->tv_sec
1069 || (now.tv_sec == tm->tv_sec && now.tv_usec > tm->tv_usec));
1070# endif
1071}
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001072
1073/*
1074 * Set the time in "tm" to zero.
1075 */
1076 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001077profile_zero(proftime_T *tm)
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001078{
1079# ifdef WIN3264
1080 tm->QuadPart = 0;
1081# else
1082 tm->tv_usec = 0;
1083 tm->tv_sec = 0;
1084# endif
1085}
1086
Bram Moolenaar76929292008-01-06 19:07:36 +00001087# endif /* FEAT_PROFILE || FEAT_RELTIME */
1088
Bram Moolenaar975b5272016-03-15 23:10:59 +01001089# if defined(FEAT_TIMERS) || defined(PROTO)
1090static timer_T *first_timer = NULL;
1091static int last_timer_id = 0;
1092
1093/*
1094 * Insert a timer in the list of timers.
1095 */
1096 static void
1097insert_timer(timer_T *timer)
1098{
1099 timer->tr_next = first_timer;
1100 timer->tr_prev = NULL;
1101 if (first_timer != NULL)
1102 first_timer->tr_prev = timer;
1103 first_timer = timer;
Bram Moolenaar4231da42016-06-02 14:30:04 +02001104 did_add_timer = TRUE;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001105}
1106
1107/*
1108 * Take a timer out of the list of timers.
1109 */
1110 static void
1111remove_timer(timer_T *timer)
1112{
1113 if (timer->tr_prev == NULL)
1114 first_timer = timer->tr_next;
1115 else
1116 timer->tr_prev->tr_next = timer->tr_next;
1117 if (timer->tr_next != NULL)
1118 timer->tr_next->tr_prev = timer->tr_prev;
1119}
1120
1121 static void
1122free_timer(timer_T *timer)
1123{
1124 vim_free(timer->tr_callback);
1125 partial_unref(timer->tr_partial);
1126 vim_free(timer);
1127}
1128
1129/*
1130 * Create a timer and return it. NULL if out of memory.
1131 * Caller should set the callback.
1132 */
1133 timer_T *
1134create_timer(long msec, int repeat)
1135{
1136 timer_T *timer = (timer_T *)alloc_clear(sizeof(timer_T));
1137
1138 if (timer == NULL)
1139 return NULL;
1140 timer->tr_id = ++last_timer_id;
1141 insert_timer(timer);
1142 if (repeat != 0)
1143 {
1144 timer->tr_repeat = repeat - 1;
1145 timer->tr_interval = msec;
1146 }
1147
1148 profile_setlimit(msec, &timer->tr_due);
1149 return timer;
1150}
1151
1152/*
1153 * Invoke the callback of "timer".
1154 */
1155 static void
1156timer_callback(timer_T *timer)
1157{
1158 typval_T rettv;
1159 int dummy;
1160 typval_T argv[2];
1161
1162 argv[0].v_type = VAR_NUMBER;
1163 argv[0].vval.v_number = timer->tr_id;
1164 argv[1].v_type = VAR_UNKNOWN;
1165
1166 call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
1167 &rettv, 1, argv, 0L, 0L, &dummy, TRUE,
1168 timer->tr_partial, NULL);
1169 clear_tv(&rettv);
1170}
1171
1172/*
1173 * Call timers that are due.
1174 * Return the time in msec until the next timer is due.
1175 */
1176 long
Bram Moolenaarcf089462016-06-12 21:18:43 +02001177check_due_timer(void)
Bram Moolenaar975b5272016-03-15 23:10:59 +01001178{
1179 timer_T *timer;
1180 long this_due;
Bram Moolenaar597385a2016-03-16 23:24:43 +01001181 long next_due = -1;
Bram Moolenaar975b5272016-03-15 23:10:59 +01001182 proftime_T now;
1183 int did_one = FALSE;
1184# ifdef WIN3264
1185 LARGE_INTEGER fr;
1186
1187 QueryPerformanceFrequency(&fr);
1188# endif
1189 while (!got_int)
1190 {
1191 profile_start(&now);
1192 next_due = -1;
1193 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1194 {
1195# ifdef WIN3264
1196 this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
1197 / (double)fr.QuadPart) * 1000);
1198# else
1199 this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
1200 + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1201# endif
1202 if (this_due <= 1)
1203 {
1204 remove_timer(timer);
1205 timer_callback(timer);
1206 did_one = TRUE;
1207 if (timer->tr_repeat != 0)
1208 {
1209 profile_setlimit(timer->tr_interval, &timer->tr_due);
1210 if (timer->tr_repeat > 0)
1211 --timer->tr_repeat;
1212 insert_timer(timer);
1213 }
1214 else
1215 free_timer(timer);
1216 /* the callback may do anything, start all over */
1217 break;
1218 }
1219 if (next_due == -1 || next_due > this_due)
1220 next_due = this_due;
1221 }
1222 if (timer == NULL)
1223 break;
1224 }
1225
1226 if (did_one)
1227 redraw_after_callback();
1228
1229 return next_due;
1230}
1231
1232/*
1233 * Find a timer by ID. Returns NULL if not found;
1234 */
1235 timer_T *
1236find_timer(int id)
1237{
1238 timer_T *timer;
1239
1240 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1241 if (timer->tr_id == id)
1242 break;
1243 return timer;
1244}
1245
1246
1247/*
1248 * Stop a timer and delete it.
1249 */
1250 void
1251stop_timer(timer_T *timer)
1252{
1253 remove_timer(timer);
1254 free_timer(timer);
1255}
Bram Moolenaare3188e22016-05-31 21:13:04 +02001256
1257/*
1258 * Mark references in partials of timers.
1259 */
1260 int
1261set_ref_in_timer(int copyID)
1262{
1263 int abort = FALSE;
1264 timer_T *timer;
1265 typval_T tv;
1266
1267 for (timer = first_timer; timer != NULL; timer = timer->tr_next)
1268 {
1269 tv.v_type = VAR_PARTIAL;
1270 tv.vval.v_partial = timer->tr_partial;
1271 abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
1272 }
1273 return abort;
1274}
Bram Moolenaar975b5272016-03-15 23:10:59 +01001275# endif
1276
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001277#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
1278# if defined(HAVE_MATH_H)
1279# include <math.h>
1280# endif
1281
1282/*
1283 * Divide the time "tm" by "count" and store in "tm2".
1284 */
1285 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001286profile_divide(proftime_T *tm, int count, proftime_T *tm2)
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001287{
1288 if (count == 0)
1289 profile_zero(tm2);
1290 else
1291 {
1292# ifdef WIN3264
1293 tm2->QuadPart = tm->QuadPart / count;
1294# else
1295 double usec = (tm->tv_sec * 1000000.0 + tm->tv_usec) / count;
1296
1297 tm2->tv_sec = floor(usec / 1000000.0);
Bram Moolenaara2e14fc2013-06-10 20:10:44 +02001298 tm2->tv_usec = vim_round(usec - (tm2->tv_sec * 1000000.0));
Bram Moolenaar8a7f5a22013-06-06 14:01:46 +02001299# endif
1300 }
1301}
1302#endif
1303
Bram Moolenaar76929292008-01-06 19:07:36 +00001304# if defined(FEAT_PROFILE) || defined(PROTO)
1305/*
1306 * Functions for profiling.
1307 */
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001308static void script_do_profile(scriptitem_T *si);
1309static void script_dump_profile(FILE *fd);
Bram Moolenaar76929292008-01-06 19:07:36 +00001310static proftime_T prof_wait_time;
1311
Bram Moolenaar433f7c82006-03-21 21:29:36 +00001312/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001313 * Add the time "tm2" to "tm".
1314 */
1315 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001316profile_add(proftime_T *tm, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001317{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001318# ifdef WIN3264
1319 tm->QuadPart += tm2->QuadPart;
1320# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001321 tm->tv_usec += tm2->tv_usec;
1322 tm->tv_sec += tm2->tv_sec;
1323 if (tm->tv_usec >= 1000000)
1324 {
1325 tm->tv_usec -= 1000000;
1326 ++tm->tv_sec;
1327 }
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001328# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001329}
1330
1331/*
Bram Moolenaar1056d982006-03-09 22:37:52 +00001332 * Add the "self" time from the total time and the children's time.
1333 */
1334 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001335profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
Bram Moolenaar1056d982006-03-09 22:37:52 +00001336{
1337 /* Check that the result won't be negative. Can happen with recursive
1338 * calls. */
1339#ifdef WIN3264
1340 if (total->QuadPart <= children->QuadPart)
1341 return;
1342#else
1343 if (total->tv_sec < children->tv_sec
1344 || (total->tv_sec == children->tv_sec
1345 && total->tv_usec <= children->tv_usec))
1346 return;
1347#endif
1348 profile_add(self, total);
1349 profile_sub(self, children);
1350}
1351
1352/*
Bram Moolenaar05159a02005-02-26 23:04:13 +00001353 * Get the current waittime.
1354 */
1355 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001356profile_get_wait(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001357{
1358 *tm = prof_wait_time;
1359}
1360
1361/*
1362 * Subtract the passed waittime since "tm" from "tma".
1363 */
1364 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001365profile_sub_wait(proftime_T *tm, proftime_T *tma)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001366{
1367 proftime_T tm3 = prof_wait_time;
1368
1369 profile_sub(&tm3, tm);
1370 profile_sub(tma, &tm3);
1371}
1372
1373/*
1374 * Return TRUE if "tm1" and "tm2" are equal.
1375 */
1376 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001377profile_equal(proftime_T *tm1, proftime_T *tm2)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001378{
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001379# ifdef WIN3264
1380 return (tm1->QuadPart == tm2->QuadPart);
1381# else
Bram Moolenaar05159a02005-02-26 23:04:13 +00001382 return (tm1->tv_usec == tm2->tv_usec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001383# endif
1384}
1385
1386/*
1387 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
1388 */
1389 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001390profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001391{
1392# ifdef WIN3264
1393 return (int)(tm2->QuadPart - tm1->QuadPart);
1394# else
1395 if (tm1->tv_sec == tm2->tv_sec)
1396 return tm2->tv_usec - tm1->tv_usec;
1397 return tm2->tv_sec - tm1->tv_sec;
1398# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00001399}
1400
Bram Moolenaar05159a02005-02-26 23:04:13 +00001401static char_u *profile_fname = NULL;
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001402static proftime_T pause_time;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001403
1404/*
1405 * ":profile cmd args"
1406 */
1407 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001408ex_profile(exarg_T *eap)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001409{
1410 char_u *e;
1411 int len;
1412
1413 e = skiptowhite(eap->arg);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00001414 len = (int)(e - eap->arg);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001415 e = skipwhite(e);
1416
1417 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
1418 {
1419 vim_free(profile_fname);
Bram Moolenaard94682f2015-04-13 15:37:56 +02001420 profile_fname = expand_env_save_opt(e, TRUE);
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001421 do_profiling = PROF_YES;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001422 profile_zero(&prof_wait_time);
1423 set_vim_var_nr(VV_PROFILING, 1L);
1424 }
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001425 else if (do_profiling == PROF_NONE)
Bram Moolenaar54c1b492010-02-24 14:01:28 +01001426 EMSG(_("E750: First use \":profile start {fname}\""));
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00001427 else if (STRCMP(eap->arg, "pause") == 0)
1428 {
1429 if (do_profiling == PROF_YES)
1430 profile_start(&pause_time);
1431 do_profiling = PROF_PAUSED;
1432 }
1433 else if (STRCMP(eap->arg, "continue") == 0)
1434 {
1435 if (do_profiling == PROF_PAUSED)
1436 {
1437 profile_end(&pause_time);
1438 profile_add(&prof_wait_time, &pause_time);
1439 }
1440 do_profiling = PROF_YES;
1441 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00001442 else
1443 {
1444 /* The rest is similar to ":breakadd". */
1445 ex_breakadd(eap);
1446 }
1447}
1448
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001449/* Command line expansion for :profile. */
1450static enum
1451{
1452 PEXP_SUBCMD, /* expand :profile sub-commands */
Bram Moolenaar49789dc2011-02-25 14:46:09 +01001453 PEXP_FUNC /* expand :profile func {funcname} */
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001454} pexpand_what;
1455
1456static char *pexpand_cmds[] = {
1457 "start",
1458#define PROFCMD_START 0
1459 "pause",
1460#define PROFCMD_PAUSE 1
1461 "continue",
1462#define PROFCMD_CONTINUE 2
1463 "func",
1464#define PROFCMD_FUNC 3
1465 "file",
1466#define PROFCMD_FILE 4
1467 NULL
1468#define PROFCMD_LAST 5
1469};
1470
1471/*
1472 * Function given to ExpandGeneric() to obtain the profile command
1473 * specific expansion.
1474 */
1475 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001476get_profile_name(expand_T *xp UNUSED, int idx)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001477{
1478 switch (pexpand_what)
1479 {
1480 case PEXP_SUBCMD:
1481 return (char_u *)pexpand_cmds[idx];
1482 /* case PEXP_FUNC: TODO */
1483 default:
1484 return NULL;
1485 }
1486}
1487
1488/*
1489 * Handle command line completion for :profile command.
1490 */
1491 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001492set_context_in_profile_cmd(expand_T *xp, char_u *arg)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001493{
1494 char_u *end_subcmd;
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001495
1496 /* Default: expand subcommands. */
1497 xp->xp_context = EXPAND_PROFILE;
1498 pexpand_what = PEXP_SUBCMD;
1499 xp->xp_pattern = arg;
1500
1501 end_subcmd = skiptowhite(arg);
1502 if (*end_subcmd == NUL)
1503 return;
1504
Bram Moolenaar8b9c05f2010-03-02 17:54:33 +01001505 if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
Bram Moolenaarf86f26c2010-02-03 15:14:22 +01001506 {
1507 xp->xp_context = EXPAND_FILES;
1508 xp->xp_pattern = skipwhite(end_subcmd);
1509 return;
1510 }
1511
1512 /* TODO: expand function names after "func" */
1513 xp->xp_context = EXPAND_NOTHING;
1514}
1515
Bram Moolenaar05159a02005-02-26 23:04:13 +00001516/*
1517 * Dump the profiling info.
1518 */
1519 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001520profile_dump(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001521{
1522 FILE *fd;
1523
1524 if (profile_fname != NULL)
1525 {
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001526 fd = mch_fopen((char *)profile_fname, "w");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001527 if (fd == NULL)
1528 EMSG2(_(e_notopen), profile_fname);
1529 else
1530 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00001531 script_dump_profile(fd);
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00001532 func_dump_profile(fd);
Bram Moolenaar05159a02005-02-26 23:04:13 +00001533 fclose(fd);
1534 }
1535 }
1536}
1537
1538/*
1539 * Start profiling script "fp".
1540 */
1541 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001542script_do_profile(scriptitem_T *si)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001543{
1544 si->sn_pr_count = 0;
1545 profile_zero(&si->sn_pr_total);
1546 profile_zero(&si->sn_pr_self);
1547
1548 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
1549 si->sn_prl_idx = -1;
1550 si->sn_prof_on = TRUE;
1551 si->sn_pr_nest = 0;
1552}
1553
1554/*
1555 * save time when starting to invoke another script or function.
1556 */
1557 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001558script_prof_save(
1559 proftime_T *tm) /* place to store wait time */
Bram Moolenaar05159a02005-02-26 23:04:13 +00001560{
1561 scriptitem_T *si;
1562
1563 if (current_SID > 0 && current_SID <= script_items.ga_len)
1564 {
1565 si = &SCRIPT_ITEM(current_SID);
1566 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
1567 profile_start(&si->sn_pr_child);
1568 }
1569 profile_get_wait(tm);
1570}
1571
1572/*
1573 * Count time spent in children after invoking another script or function.
1574 */
1575 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001576script_prof_restore(proftime_T *tm)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001577{
1578 scriptitem_T *si;
1579
1580 if (current_SID > 0 && current_SID <= script_items.ga_len)
1581 {
1582 si = &SCRIPT_ITEM(current_SID);
1583 if (si->sn_prof_on && --si->sn_pr_nest == 0)
1584 {
1585 profile_end(&si->sn_pr_child);
1586 profile_sub_wait(tm, &si->sn_pr_child); /* don't count wait time */
1587 profile_add(&si->sn_pr_children, &si->sn_pr_child);
1588 profile_add(&si->sn_prl_children, &si->sn_pr_child);
1589 }
1590 }
1591}
1592
1593static proftime_T inchar_time;
1594
1595/*
1596 * Called when starting to wait for the user to type a character.
1597 */
1598 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001599prof_inchar_enter(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001600{
1601 profile_start(&inchar_time);
1602}
1603
1604/*
1605 * Called when finished waiting for the user to type a character.
1606 */
1607 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001608prof_inchar_exit(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001609{
1610 profile_end(&inchar_time);
1611 profile_add(&prof_wait_time, &inchar_time);
1612}
1613
1614/*
1615 * Dump the profiling results for all scripts in file "fd".
1616 */
1617 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001618script_dump_profile(FILE *fd)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001619{
1620 int id;
1621 scriptitem_T *si;
1622 int i;
1623 FILE *sfd;
1624 sn_prl_T *pp;
1625
1626 for (id = 1; id <= script_items.ga_len; ++id)
1627 {
1628 si = &SCRIPT_ITEM(id);
1629 if (si->sn_prof_on)
1630 {
1631 fprintf(fd, "SCRIPT %s\n", si->sn_name);
1632 if (si->sn_pr_count == 1)
1633 fprintf(fd, "Sourced 1 time\n");
1634 else
1635 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
1636 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
1637 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
1638 fprintf(fd, "\n");
1639 fprintf(fd, "count total (s) self (s)\n");
1640
Bram Moolenaarbfd8fc02005-09-20 23:22:24 +00001641 sfd = mch_fopen((char *)si->sn_name, "r");
Bram Moolenaar05159a02005-02-26 23:04:13 +00001642 if (sfd == NULL)
1643 fprintf(fd, "Cannot open file!\n");
1644 else
1645 {
1646 for (i = 0; i < si->sn_prl_ga.ga_len; ++i)
1647 {
1648 if (vim_fgets(IObuff, IOSIZE, sfd))
1649 break;
1650 pp = &PRL_ITEM(si, i);
1651 if (pp->snp_count > 0)
1652 {
1653 fprintf(fd, "%5d ", pp->snp_count);
1654 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
1655 fprintf(fd, " ");
1656 else
1657 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
1658 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
1659 }
1660 else
1661 fprintf(fd, " ");
1662 fprintf(fd, "%s", IObuff);
1663 }
1664 fclose(sfd);
1665 }
1666 fprintf(fd, "\n");
1667 }
1668 }
1669}
1670
1671/*
1672 * Return TRUE when a function defined in the current script should be
1673 * profiled.
1674 */
1675 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001676prof_def_func(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00001677{
Bram Moolenaar53180ce2005-07-05 21:48:14 +00001678 if (current_SID > 0)
1679 return SCRIPT_ITEM(current_SID).sn_pr_force;
1680 return FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00001681}
1682
1683# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684#endif
1685
1686/*
1687 * If 'autowrite' option set, try to write the file.
1688 * Careful: autocommands may make "buf" invalid!
1689 *
1690 * return FAIL for failure, OK otherwise
1691 */
1692 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001693autowrite(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001694{
Bram Moolenaar373154b2007-02-13 05:19:30 +00001695 int r;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001696 bufref_T bufref;
Bram Moolenaar373154b2007-02-13 05:19:30 +00001697
Bram Moolenaar071d4272004-06-13 20:20:40 +00001698 if (!(p_aw || p_awa) || !p_write
1699#ifdef FEAT_QUICKFIX
Bram Moolenaar373154b2007-02-13 05:19:30 +00001700 /* never autowrite a "nofile" or "nowrite" buffer */
1701 || bt_dontwrite(buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001702#endif
Bram Moolenaar373154b2007-02-13 05:19:30 +00001703 || (!forceit && buf->b_p_ro) || buf->b_ffname == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704 return FAIL;
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001705 set_bufref(&bufref, buf);
Bram Moolenaar373154b2007-02-13 05:19:30 +00001706 r = buf_write_all(buf, forceit);
1707
1708 /* Writing may succeed but the buffer still changed, e.g., when there is a
1709 * conversion error. We do want to return FAIL then. */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001710 if (bufref_valid(&bufref) && bufIsChanged(buf))
Bram Moolenaar373154b2007-02-13 05:19:30 +00001711 r = FAIL;
1712 return r;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713}
1714
1715/*
1716 * flush all buffers, except the ones that are readonly
1717 */
1718 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001719autowrite_all(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001720{
1721 buf_T *buf;
1722
1723 if (!(p_aw || p_awa) || !p_write)
1724 return;
1725 for (buf = firstbuf; buf; buf = buf->b_next)
1726 if (bufIsChanged(buf) && !buf->b_p_ro)
1727 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001728#ifdef FEAT_AUTOCMD
1729 bufref_T bufref;
1730
1731 set_bufref(&bufref, buf);
1732#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733 (void)buf_write_all(buf, FALSE);
1734#ifdef FEAT_AUTOCMD
1735 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001736 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001737 buf = firstbuf;
1738#endif
1739 }
1740}
1741
1742/*
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001743 * Return TRUE if buffer was changed and cannot be abandoned.
1744 * For flags use the CCGD_ values.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001745 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001746 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001747check_changed(buf_T *buf, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001748{
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001749 int forceit = (flags & CCGD_FORCEIT);
1750#ifdef FEAT_AUTOCMD
1751 bufref_T bufref;
1752
1753 set_bufref(&bufref, buf);
1754#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001755
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756 if ( !forceit
1757 && bufIsChanged(buf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001758 && ((flags & CCGD_MULTWIN) || buf->b_nwindows <= 1)
1759 && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 {
1761#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1762 if ((p_confirm || cmdmod.confirm) && p_write)
1763 {
1764 buf_T *buf2;
1765 int count = 0;
1766
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001767 if (flags & CCGD_ALLBUF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1769 if (bufIsChanged(buf2)
1770 && (buf2->b_ffname != NULL
1771# ifdef FEAT_BROWSE
1772 || cmdmod.browse
1773# endif
1774 ))
1775 ++count;
1776# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001777 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001778 /* Autocommand deleted buffer, oops! It's not changed now. */
1779 return FALSE;
1780# endif
1781 dialog_changed(buf, count > 1);
1782# ifdef FEAT_AUTOCMD
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001783 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784 /* Autocommand deleted buffer, oops! It's not changed now. */
1785 return FALSE;
1786# endif
1787 return bufIsChanged(buf);
1788 }
1789#endif
Bram Moolenaar45d3b142013-11-09 03:31:51 +01001790 if (flags & CCGD_EXCMD)
1791 EMSG(_(e_nowrtmsg));
1792 else
1793 EMSG(_(e_nowrtmsg_nobang));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 return TRUE;
1795 }
1796 return FALSE;
1797}
1798
1799#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) || defined(PROTO)
1800
1801#if defined(FEAT_BROWSE) || defined(PROTO)
1802/*
1803 * When wanting to write a file without a file name, ask the user for a name.
1804 */
1805 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001806browse_save_fname(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001807{
1808 if (buf->b_fname == NULL)
1809 {
1810 char_u *fname;
1811
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00001812 fname = do_browse(BROWSE_SAVE, (char_u *)_("Save As"),
1813 NULL, NULL, NULL, NULL, buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 if (fname != NULL)
1815 {
1816 if (setfname(buf, fname, NULL, TRUE) == OK)
1817 buf->b_flags |= BF_NOTEDITED;
1818 vim_free(fname);
1819 }
1820 }
1821}
1822#endif
1823
1824/*
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02001825 * Ask the user what to do when abandoning a changed buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 * Must check 'write' option first!
1827 */
1828 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001829dialog_changed(
1830 buf_T *buf,
1831 int checkall) /* may abandon all changed buffers */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832{
Bram Moolenaard9462e32011-04-11 21:35:11 +02001833 char_u buff[DIALOG_MSG_SIZE];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001834 int ret;
1835 buf_T *buf2;
Bram Moolenaar8218f602012-04-25 17:32:18 +02001836 exarg_T ea;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837
Bram Moolenaar82cf9b62005-06-07 21:09:25 +00001838 dialog_msg(buff, _("Save changes to \"%s\"?"),
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 (buf->b_fname != NULL) ?
1840 buf->b_fname : (char_u *)_("Untitled"));
1841 if (checkall)
1842 ret = vim_dialog_yesnoallcancel(VIM_QUESTION, NULL, buff, 1);
1843 else
1844 ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
1845
Bram Moolenaar8218f602012-04-25 17:32:18 +02001846 /* Init ea pseudo-structure, this is needed for the check_overwrite()
1847 * function. */
1848 ea.append = ea.forceit = FALSE;
1849
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 if (ret == VIM_YES)
1851 {
1852#ifdef FEAT_BROWSE
1853 /* May get file name, when there is none */
1854 browse_save_fname(buf);
1855#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001856 if (buf->b_fname != NULL && check_overwrite(&ea, buf,
1857 buf->b_fname, buf->b_ffname, FALSE) == OK)
1858 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 (void)buf_write_all(buf, FALSE);
1860 }
1861 else if (ret == VIM_NO)
1862 {
1863 unchanged(buf, TRUE);
1864 }
1865 else if (ret == VIM_ALL)
1866 {
1867 /*
1868 * Write all modified files that can be written.
1869 * Skip readonly buffers, these need to be confirmed
1870 * individually.
1871 */
1872 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1873 {
1874 if (bufIsChanged(buf2)
1875 && (buf2->b_ffname != NULL
1876#ifdef FEAT_BROWSE
1877 || cmdmod.browse
1878#endif
1879 )
1880 && !buf2->b_p_ro)
1881 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001882#ifdef FEAT_AUTOCMD
1883 bufref_T bufref;
1884
1885 set_bufref(&bufref, buf2);
1886#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887#ifdef FEAT_BROWSE
1888 /* May get file name, when there is none */
1889 browse_save_fname(buf2);
1890#endif
Bram Moolenaar8218f602012-04-25 17:32:18 +02001891 if (buf2->b_fname != NULL && check_overwrite(&ea, buf2,
1892 buf2->b_fname, buf2->b_ffname, FALSE) == OK)
1893 /* didn't hit Cancel */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001894 (void)buf_write_all(buf2, FALSE);
1895#ifdef FEAT_AUTOCMD
1896 /* an autocommand may have deleted the buffer */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02001897 if (!bufref_valid(&bufref))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001898 buf2 = firstbuf;
1899#endif
1900 }
1901 }
1902 }
1903 else if (ret == VIM_DISCARDALL)
1904 {
1905 /*
1906 * mark all buffers as unchanged
1907 */
1908 for (buf2 = firstbuf; buf2 != NULL; buf2 = buf2->b_next)
1909 unchanged(buf2, TRUE);
1910 }
1911}
1912#endif
1913
1914/*
1915 * Return TRUE if the buffer "buf" can be abandoned, either by making it
1916 * hidden, autowriting it or unloading it.
1917 */
1918 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001919can_abandon(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920{
1921 return ( P_HID(buf)
1922 || !bufIsChanged(buf)
1923 || buf->b_nwindows > 1
1924 || autowrite(buf, forceit) == OK
1925 || forceit);
1926}
1927
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01001928static void add_bufnum(int *bufnrs, int *bufnump, int nr);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001929
1930/*
1931 * Add a buffer number to "bufnrs", unless it's already there.
1932 */
1933 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001934add_bufnum(int *bufnrs, int *bufnump, int nr)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001935{
1936 int i;
1937
1938 for (i = 0; i < *bufnump; ++i)
1939 if (bufnrs[i] == nr)
1940 return;
1941 bufnrs[*bufnump] = nr;
1942 *bufnump = *bufnump + 1;
1943}
1944
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945/*
1946 * Return TRUE if any buffer was changed and cannot be abandoned.
1947 * That changed buffer becomes the current buffer.
Bram Moolenaar027387f2016-01-02 22:25:52 +01001948 * When "unload" is true the current buffer is unloaded instead of making it
1949 * hidden. This is used for ":q!".
Bram Moolenaar071d4272004-06-13 20:20:40 +00001950 */
1951 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01001952check_changed_any(
1953 int hidden, /* Only check hidden buffers */
1954 int unload)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955{
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001956 int ret = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001957 buf_T *buf;
1958 int save;
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001959 int i;
1960 int bufnum = 0;
1961 int bufcount = 0;
1962 int *bufnrs;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963#ifdef FEAT_WINDOWS
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001964 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 win_T *wp;
1966#endif
1967
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001968 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1969 ++bufcount;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970
Bram Moolenaar970a1b82012-03-23 18:39:18 +01001971 if (bufcount == 0)
1972 return FALSE;
1973
1974 bufnrs = (int *)alloc(sizeof(int) * bufcount);
1975 if (bufnrs == NULL)
1976 return FALSE;
1977
1978 /* curbuf */
1979 bufnrs[bufnum++] = curbuf->b_fnum;
1980#ifdef FEAT_WINDOWS
1981 /* buf in curtab */
1982 FOR_ALL_WINDOWS(wp)
1983 if (wp->w_buffer != curbuf)
1984 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1985
1986 /* buf in other tab */
1987 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next)
1988 if (tp != curtab)
1989 for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next)
1990 add_bufnum(bufnrs, &bufnum, wp->w_buffer->b_fnum);
1991#endif
1992 /* any other buf */
1993 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
1994 add_bufnum(bufnrs, &bufnum, buf->b_fnum);
1995
1996 for (i = 0; i < bufnum; ++i)
1997 {
1998 buf = buflist_findnr(bufnrs[i]);
1999 if (buf == NULL)
2000 continue;
2001 if ((!hidden || buf->b_nwindows == 0) && bufIsChanged(buf))
2002 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002003 bufref_T bufref;
2004
2005 set_bufref(&bufref, buf);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002006 /* Try auto-writing the buffer. If this fails but the buffer no
2007 * longer exists it's not changed, that's OK. */
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002008 if (check_changed(buf, (p_awa ? CCGD_AW : 0)
2009 | CCGD_MULTWIN
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002010 | CCGD_ALLBUF) && bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002011 break; /* didn't save - still changes */
2012 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002013 }
2014
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002015 if (i >= bufnum)
2016 goto theend;
2017
2018 ret = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019 exiting = FALSE;
2020#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2021 /*
2022 * When ":confirm" used, don't give an error message.
2023 */
2024 if (!(p_confirm || cmdmod.confirm))
2025#endif
2026 {
2027 /* There must be a wait_return for this message, do_buffer()
2028 * may cause a redraw. But wait_return() is a no-op when vgetc()
2029 * is busy (Quit used from window menu), then make sure we don't
2030 * cause a scroll up. */
Bram Moolenaar61660ea2006-04-07 21:40:07 +00002031 if (vgetc_busy > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002032 {
2033 msg_row = cmdline_row;
2034 msg_col = 0;
2035 msg_didout = FALSE;
2036 }
2037 if (EMSG2(_("E162: No write since last change for buffer \"%s\""),
Bram Moolenaare1704ba2012-10-03 18:25:00 +02002038 buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002039 {
2040 save = no_wait_return;
2041 no_wait_return = FALSE;
2042 wait_return(FALSE);
2043 no_wait_return = save;
2044 }
2045 }
2046
2047#ifdef FEAT_WINDOWS
2048 /* Try to find a window that contains the buffer. */
2049 if (buf != curbuf)
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002050 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002051 if (wp->w_buffer == buf)
2052 {
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002053# ifdef FEAT_AUTOCMD
2054 bufref_T bufref;
2055
2056 set_bufref(&bufref, buf);
2057# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002058 goto_tabpage_win(tp, wp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059# ifdef FEAT_AUTOCMD
2060 /* Paranoia: did autocms wipe out the buffer with changes? */
Bram Moolenaar7c0a2f32016-07-10 22:11:16 +02002061 if (!bufref_valid(&bufref))
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002062 {
2063 goto theend;
2064 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065# endif
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002066 goto buf_found;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002067 }
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002068buf_found:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002069#endif
2070
2071 /* Open the changed buffer in the current window. */
2072 if (buf != curbuf)
Bram Moolenaar027387f2016-01-02 22:25:52 +01002073 set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074
Bram Moolenaar970a1b82012-03-23 18:39:18 +01002075theend:
2076 vim_free(bufnrs);
2077 return ret;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078}
2079
2080/*
2081 * return FAIL if there is no file name, OK if there is one
2082 * give error message for FAIL
2083 */
2084 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002085check_fname(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086{
2087 if (curbuf->b_ffname == NULL)
2088 {
2089 EMSG(_(e_noname));
2090 return FAIL;
2091 }
2092 return OK;
2093}
2094
2095/*
2096 * flush the contents of a buffer, unless it has no file name
2097 *
2098 * return FAIL for failure, OK otherwise
2099 */
2100 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002101buf_write_all(buf_T *buf, int forceit)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102{
2103 int retval;
2104#ifdef FEAT_AUTOCMD
2105 buf_T *old_curbuf = curbuf;
2106#endif
2107
2108 retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
2109 (linenr_T)1, buf->b_ml.ml_line_count, NULL,
2110 FALSE, forceit, TRUE, FALSE));
2111#ifdef FEAT_AUTOCMD
2112 if (curbuf != old_curbuf)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002113 {
2114 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 MSG(_("Warning: Entered other buffer unexpectedly (check autocommands)"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00002116 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002117#endif
2118 return retval;
2119}
2120
2121/*
2122 * Code to handle the argument list.
2123 */
2124
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002125static char_u *do_one_arg(char_u *str);
2126static int do_arglist(char_u *str, int what, int after);
2127static void alist_check_arg_idx(void);
2128static int editing_arg_idx(win_T *win);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002129#ifdef FEAT_LISTCMDS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01002130static int alist_add_list(int count, char_u **files, int after);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002131#endif
2132#define AL_SET 1
2133#define AL_ADD 2
2134#define AL_DEL 3
2135
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136/*
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002137 * Isolate one argument, taking backticks.
2138 * Changes the argument in-place, puts a NUL after it. Backticks remain.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002139 * Return a pointer to the start of the next argument.
2140 */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002141 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002142do_one_arg(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143{
2144 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145 int inbacktick;
2146
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 inbacktick = FALSE;
2148 for (p = str; *str; ++str)
2149 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002150 /* When the backslash is used for escaping the special meaning of a
2151 * character we need to keep it until wildcard expansion. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152 if (rem_backslash(str))
2153 {
2154 *p++ = *str++;
2155 *p++ = *str;
2156 }
2157 else
2158 {
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002159 /* An item ends at a space not in backticks */
2160 if (!inbacktick && vim_isspace(*str))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002161 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002162 if (*str == '`')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002163 inbacktick ^= TRUE;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002164 *p++ = *str;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 }
2166 }
2167 str = skipwhite(str);
2168 *p = NUL;
2169
2170 return str;
2171}
2172
Bram Moolenaar86b68352004-12-27 21:59:20 +00002173/*
2174 * Separate the arguments in "str" and return a list of pointers in the
2175 * growarray "gap".
2176 */
2177 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002178get_arglist(garray_T *gap, char_u *str)
Bram Moolenaar86b68352004-12-27 21:59:20 +00002179{
2180 ga_init2(gap, (int)sizeof(char_u *), 20);
2181 while (*str != NUL)
2182 {
2183 if (ga_grow(gap, 1) == FAIL)
2184 {
2185 ga_clear(gap);
2186 return FAIL;
2187 }
2188 ((char_u **)gap->ga_data)[gap->ga_len++] = str;
2189
2190 /* Isolate one argument, change it in-place, put a NUL after it. */
2191 str = do_one_arg(str);
2192 }
2193 return OK;
2194}
2195
Bram Moolenaar7df351e2006-01-23 22:30:28 +00002196#if defined(FEAT_QUICKFIX) || defined(FEAT_SYN_HL) || defined(PROTO)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002197/*
2198 * Parse a list of arguments (file names), expand them and return in
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002199 * "fnames[fcountp]". When "wig" is TRUE, removes files matching 'wildignore'.
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002200 * Return FAIL or OK.
2201 */
2202 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002203get_arglist_exp(
2204 char_u *str,
2205 int *fcountp,
2206 char_u ***fnamesp,
2207 int wig)
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002208{
2209 garray_T ga;
2210 int i;
2211
2212 if (get_arglist(&ga, str) == FAIL)
2213 return FAIL;
Bram Moolenaar8f5c6f02012-06-29 12:57:06 +02002214 if (wig == TRUE)
2215 i = expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2216 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2217 else
2218 i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
2219 fcountp, fnamesp, EW_FILE|EW_NOTFOUND);
2220
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00002221 ga_clear(&ga);
2222 return i;
2223}
2224#endif
2225
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226#if defined(FEAT_GUI) || defined(FEAT_CLIENTSERVER) || defined(PROTO)
2227/*
2228 * Redefine the argument list.
2229 */
2230 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002231set_arglist(char_u *str)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232{
2233 do_arglist(str, AL_SET, 0);
2234}
2235#endif
2236
2237/*
2238 * "what" == AL_SET: Redefine the argument list to 'str'.
2239 * "what" == AL_ADD: add files in 'str' to the argument list after "after".
2240 * "what" == AL_DEL: remove files in 'str' from the argument list.
2241 *
2242 * Return FAIL for failure, OK otherwise.
2243 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002245do_arglist(
2246 char_u *str,
Bram Moolenaarf1d25012016-03-03 12:22:53 +01002247 int what,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002248 int after UNUSED) /* 0 means before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249{
2250 garray_T new_ga;
2251 int exp_count;
2252 char_u **exp_files;
2253 int i;
2254#ifdef FEAT_LISTCMDS
2255 char_u *p;
2256 int match;
2257#endif
2258
2259 /*
Bram Moolenaar2faa29f2016-01-23 23:02:34 +01002260 * Set default argument for ":argadd" command.
2261 */
2262 if (what == AL_ADD && *str == NUL)
2263 {
2264 if (curbuf->b_ffname == NULL)
2265 return FAIL;
2266 str = curbuf->b_fname;
2267 }
2268
2269 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 * Collect all file name arguments in "new_ga".
2271 */
Bram Moolenaar86b68352004-12-27 21:59:20 +00002272 if (get_arglist(&new_ga, str) == FAIL)
2273 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274
2275#ifdef FEAT_LISTCMDS
2276 if (what == AL_DEL)
2277 {
2278 regmatch_T regmatch;
2279 int didone;
2280
2281 /*
2282 * Delete the items: use each item as a regexp and find a match in the
2283 * argument list.
2284 */
Bram Moolenaar71afbfe2013-03-19 16:49:16 +01002285 regmatch.rm_ic = p_fic; /* ignore case when 'fileignorecase' is set */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 for (i = 0; i < new_ga.ga_len && !got_int; ++i)
2287 {
2288 p = ((char_u **)new_ga.ga_data)[i];
2289 p = file_pat_to_reg_pat(p, NULL, NULL, FALSE);
2290 if (p == NULL)
2291 break;
2292 regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
2293 if (regmatch.regprog == NULL)
2294 {
2295 vim_free(p);
2296 break;
2297 }
2298
2299 didone = FALSE;
2300 for (match = 0; match < ARGCOUNT; ++match)
2301 if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]),
2302 (colnr_T)0))
2303 {
2304 didone = TRUE;
2305 vim_free(ARGLIST[match].ae_fname);
2306 mch_memmove(ARGLIST + match, ARGLIST + match + 1,
2307 (ARGCOUNT - match - 1) * sizeof(aentry_T));
2308 --ALIST(curwin)->al_ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309 if (curwin->w_arg_idx > match)
2310 --curwin->w_arg_idx;
2311 --match;
2312 }
2313
Bram Moolenaar473de612013-06-08 18:19:48 +02002314 vim_regfree(regmatch.regprog);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 vim_free(p);
2316 if (!didone)
2317 EMSG2(_(e_nomatch2), ((char_u **)new_ga.ga_data)[i]);
2318 }
2319 ga_clear(&new_ga);
2320 }
2321 else
2322#endif
2323 {
2324 i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
2325 &exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
2326 ga_clear(&new_ga);
Bram Moolenaar2db5c3b2016-01-16 22:49:34 +01002327 if (i == FAIL || exp_count == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 {
2329 EMSG(_(e_nomatch));
2330 return FAIL;
2331 }
2332
2333#ifdef FEAT_LISTCMDS
2334 if (what == AL_ADD)
2335 {
2336 (void)alist_add_list(exp_count, exp_files, after);
2337 vim_free(exp_files);
2338 }
2339 else /* what == AL_SET */
2340#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00002341 alist_set(ALIST(curwin), exp_count, exp_files, FALSE, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 }
2343
2344 alist_check_arg_idx();
2345
2346 return OK;
2347}
2348
2349/*
2350 * Check the validity of the arg_idx for each other window.
2351 */
2352 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002353alist_check_arg_idx(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354{
2355#ifdef FEAT_WINDOWS
2356 win_T *win;
Bram Moolenaarf740b292006-02-16 22:11:02 +00002357 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358
Bram Moolenaarf740b292006-02-16 22:11:02 +00002359 FOR_ALL_TAB_WINDOWS(tp, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 if (win->w_alist == curwin->w_alist)
2361 check_arg_idx(win);
2362#else
2363 check_arg_idx(curwin);
2364#endif
2365}
2366
2367/*
Bram Moolenaarb8ff1fb2012-02-04 21:59:01 +01002368 * Return TRUE if window "win" is editing the file at the current argument
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002369 * index.
2370 */
2371 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002372editing_arg_idx(win_T *win)
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002373{
2374 return !(win->w_arg_idx >= WARGCOUNT(win)
2375 || (win->w_buffer->b_fnum
2376 != WARGLIST(win)[win->w_arg_idx].ae_fnum
2377 && (win->w_buffer->b_ffname == NULL
2378 || !(fullpathcmp(
2379 alist_name(&WARGLIST(win)[win->w_arg_idx]),
2380 win->w_buffer->b_ffname, TRUE) & FPC_SAME))));
2381}
2382
2383/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 * Check if window "win" is editing the w_arg_idx file in its argument list.
2385 */
2386 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002387check_arg_idx(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388{
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002389 if (WARGCOUNT(win) > 1 && !editing_arg_idx(win))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 {
2391 /* We are not editing the current entry in the argument list.
2392 * Set "arg_had_last" if we are editing the last one. */
2393 win->w_arg_idx_invalid = TRUE;
2394 if (win->w_arg_idx != WARGCOUNT(win) - 1
2395 && arg_had_last == FALSE
2396#ifdef FEAT_WINDOWS
2397 && ALIST(win) == &global_alist
2398#endif
2399 && GARGCOUNT > 0
2400 && win->w_arg_idx < GARGCOUNT
2401 && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
2402 || (win->w_buffer->b_ffname != NULL
2403 && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
2404 win->w_buffer->b_ffname, TRUE) & FPC_SAME))))
2405 arg_had_last = TRUE;
2406 }
2407 else
2408 {
2409 /* We are editing the current entry in the argument list.
2410 * Set "arg_had_last" if it's also the last one */
2411 win->w_arg_idx_invalid = FALSE;
2412 if (win->w_arg_idx == WARGCOUNT(win) - 1
2413#ifdef FEAT_WINDOWS
2414 && win->w_alist == &global_alist
2415#endif
2416 )
2417 arg_had_last = TRUE;
2418 }
2419}
2420
2421/*
2422 * ":args", ":argslocal" and ":argsglobal".
2423 */
2424 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002425ex_args(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426{
2427 int i;
2428
2429 if (eap->cmdidx != CMD_args)
2430 {
2431#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2432 alist_unlink(ALIST(curwin));
2433 if (eap->cmdidx == CMD_argglobal)
2434 ALIST(curwin) = &global_alist;
2435 else /* eap->cmdidx == CMD_arglocal */
2436 alist_new();
2437#else
2438 ex_ni(eap);
2439 return;
2440#endif
2441 }
2442
2443 if (!ends_excmd(*eap->arg))
2444 {
2445 /*
2446 * ":args file ..": define new argument list, handle like ":next"
2447 * Also for ":argslocal file .." and ":argsglobal file ..".
2448 */
2449 ex_next(eap);
2450 }
2451 else
2452#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2453 if (eap->cmdidx == CMD_args)
2454#endif
2455 {
2456 /*
2457 * ":args": list arguments.
2458 */
2459 if (ARGCOUNT > 0)
2460 {
2461 /* Overwrite the command, for a short list there is no scrolling
2462 * required and no wait_return(). */
2463 gotocmdline(TRUE);
2464 for (i = 0; i < ARGCOUNT; ++i)
2465 {
2466 if (i == curwin->w_arg_idx)
2467 msg_putchar('[');
2468 msg_outtrans(alist_name(&ARGLIST[i]));
2469 if (i == curwin->w_arg_idx)
2470 msg_putchar(']');
2471 msg_putchar(' ');
2472 }
2473 }
2474 }
2475#if defined(FEAT_WINDOWS) && defined(FEAT_LISTCMDS)
2476 else if (eap->cmdidx == CMD_arglocal)
2477 {
2478 garray_T *gap = &curwin->w_alist->al_ga;
2479
2480 /*
2481 * ":argslocal": make a local copy of the global argument list.
2482 */
2483 if (ga_grow(gap, GARGCOUNT) == OK)
2484 for (i = 0; i < GARGCOUNT; ++i)
2485 if (GARGLIST[i].ae_fname != NULL)
2486 {
2487 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname =
2488 vim_strsave(GARGLIST[i].ae_fname);
2489 AARGLIST(curwin->w_alist)[gap->ga_len].ae_fnum =
2490 GARGLIST[i].ae_fnum;
2491 ++gap->ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492 }
2493 }
2494#endif
2495}
2496
2497/*
2498 * ":previous", ":sprevious", ":Next" and ":sNext".
2499 */
2500 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002501ex_previous(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502{
2503 /* If past the last one already, go to the last one. */
2504 if (curwin->w_arg_idx - (int)eap->line2 >= ARGCOUNT)
2505 do_argfile(eap, ARGCOUNT - 1);
2506 else
2507 do_argfile(eap, curwin->w_arg_idx - (int)eap->line2);
2508}
2509
2510/*
2511 * ":rewind", ":first", ":sfirst" and ":srewind".
2512 */
2513 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002514ex_rewind(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515{
2516 do_argfile(eap, 0);
2517}
2518
2519/*
2520 * ":last" and ":slast".
2521 */
2522 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002523ex_last(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002524{
2525 do_argfile(eap, ARGCOUNT - 1);
2526}
2527
2528/*
2529 * ":argument" and ":sargument".
2530 */
2531 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002532ex_argument(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533{
2534 int i;
2535
2536 if (eap->addr_count > 0)
2537 i = eap->line2 - 1;
2538 else
2539 i = curwin->w_arg_idx;
2540 do_argfile(eap, i);
2541}
2542
2543/*
2544 * Edit file "argn" of the argument lists.
2545 */
2546 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002547do_argfile(exarg_T *eap, int argn)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548{
2549 int other;
2550 char_u *p;
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002551 int old_arg_idx = curwin->w_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552
2553 if (argn < 0 || argn >= ARGCOUNT)
2554 {
2555 if (ARGCOUNT <= 1)
2556 EMSG(_("E163: There is only one file to edit"));
2557 else if (argn < 0)
2558 EMSG(_("E164: Cannot go before first file"));
2559 else
2560 EMSG(_("E165: Cannot go beyond last file"));
2561 }
2562 else
2563 {
2564 setpcmark();
2565#ifdef FEAT_GUI
2566 need_mouse_correct = TRUE;
2567#endif
2568
2569#ifdef FEAT_WINDOWS
Bram Moolenaardf1bdc92006-02-23 21:32:16 +00002570 /* split window or create new tab page first */
2571 if (*eap->cmd == 's' || cmdmod.tab != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 {
2573 if (win_split(0, 0) == FAIL)
2574 return;
Bram Moolenaar3368ea22010-09-21 16:56:35 +02002575 RESET_BINDING(curwin);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 }
2577 else
2578#endif
2579 {
2580 /*
2581 * if 'hidden' set, only check for changed file when re-editing
2582 * the same buffer
2583 */
2584 other = TRUE;
2585 if (P_HID(curbuf))
2586 {
2587 p = fix_fname(alist_name(&ARGLIST[argn]));
2588 other = otherfile(p);
2589 vim_free(p);
2590 }
2591 if ((!P_HID(curbuf) || !other)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002592 && check_changed(curbuf, CCGD_AW
2593 | (other ? 0 : CCGD_MULTWIN)
2594 | (eap->forceit ? CCGD_FORCEIT : 0)
2595 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002596 return;
2597 }
2598
2599 curwin->w_arg_idx = argn;
2600 if (argn == ARGCOUNT - 1
2601#ifdef FEAT_WINDOWS
2602 && curwin->w_alist == &global_alist
2603#endif
2604 )
2605 arg_had_last = TRUE;
2606
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002607 /* Edit the file; always use the last known line number.
2608 * When it fails (e.g. Abort for already edited file) restore the
2609 * argument index. */
2610 if (do_ecmd(0, alist_name(&ARGLIST[curwin->w_arg_idx]), NULL,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002611 eap, ECMD_LAST,
Bram Moolenaar701f7af2008-11-15 13:12:07 +00002612 (P_HID(curwin->w_buffer) ? ECMD_HIDE : 0)
2613 + (eap->forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002614 curwin->w_arg_idx = old_arg_idx;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615 /* like Vi: set the mark where the cursor is in the file. */
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00002616 else if (eap->cmdidx != CMD_argdo)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 setmark('\'');
2618 }
2619}
2620
2621/*
2622 * ":next", and commands that behave like it.
2623 */
2624 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002625ex_next(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626{
2627 int i;
2628
2629 /*
2630 * check for changed buffer now, if this fails the argument list is not
2631 * redefined.
2632 */
2633 if ( P_HID(curbuf)
2634 || eap->cmdidx == CMD_snext
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002635 || !check_changed(curbuf, CCGD_AW
2636 | (eap->forceit ? CCGD_FORCEIT : 0)
2637 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002638 {
2639 if (*eap->arg != NUL) /* redefine file list */
2640 {
2641 if (do_arglist(eap->arg, AL_SET, 0) == FAIL)
2642 return;
2643 i = 0;
2644 }
2645 else
2646 i = curwin->w_arg_idx + (int)eap->line2;
2647 do_argfile(eap, i);
2648 }
2649}
2650
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002651#if defined(FEAT_LISTCMDS) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652/*
2653 * ":argedit"
2654 */
2655 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002656ex_argedit(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002657{
2658 int fnum;
2659 int i;
2660 char_u *s;
2661
2662 /* Add the argument to the buffer list and get the buffer number. */
2663 fnum = buflist_add(eap->arg, BLN_LISTED);
2664
2665 /* Check if this argument is already in the argument list. */
2666 for (i = 0; i < ARGCOUNT; ++i)
2667 if (ARGLIST[i].ae_fnum == fnum)
2668 break;
2669 if (i == ARGCOUNT)
2670 {
2671 /* Can't find it, add it to the argument list. */
2672 s = vim_strsave(eap->arg);
2673 if (s == NULL)
2674 return;
2675 i = alist_add_list(1, &s,
2676 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2677 if (i < 0)
2678 return;
2679 curwin->w_arg_idx = i;
2680 }
2681
2682 alist_check_arg_idx();
2683
2684 /* Edit the argument. */
2685 do_argfile(eap, i);
2686}
2687
2688/*
2689 * ":argadd"
2690 */
2691 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002692ex_argadd(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693{
2694 do_arglist(eap->arg, AL_ADD,
2695 eap->addr_count > 0 ? (int)eap->line2 : curwin->w_arg_idx + 1);
2696#ifdef FEAT_TITLE
2697 maketitle();
2698#endif
2699}
2700
2701/*
2702 * ":argdelete"
2703 */
2704 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002705ex_argdelete(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706{
2707 int i;
2708 int n;
2709
2710 if (eap->addr_count > 0)
2711 {
2712 /* ":1,4argdel": Delete all arguments in the range. */
2713 if (eap->line2 > ARGCOUNT)
2714 eap->line2 = ARGCOUNT;
2715 n = eap->line2 - eap->line1 + 1;
2716 if (*eap->arg != NUL || n <= 0)
2717 EMSG(_(e_invarg));
2718 else
2719 {
2720 for (i = eap->line1; i <= eap->line2; ++i)
2721 vim_free(ARGLIST[i - 1].ae_fname);
2722 mch_memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
2723 (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
2724 ALIST(curwin)->al_ga.ga_len -= n;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002725 if (curwin->w_arg_idx >= eap->line2)
2726 curwin->w_arg_idx -= n;
2727 else if (curwin->w_arg_idx > eap->line1)
2728 curwin->w_arg_idx = eap->line1;
Bram Moolenaar72defda2016-01-17 18:04:33 +01002729 if (ARGCOUNT == 0)
2730 curwin->w_arg_idx = 0;
2731 else if (curwin->w_arg_idx >= ARGCOUNT)
2732 curwin->w_arg_idx = ARGCOUNT - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733 }
2734 }
2735 else if (*eap->arg == NUL)
2736 EMSG(_(e_argreq));
2737 else
2738 do_arglist(eap->arg, AL_DEL, 0);
2739#ifdef FEAT_TITLE
2740 maketitle();
2741#endif
2742}
2743
2744/*
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002745 * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 */
2747 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01002748ex_listdo(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002749{
2750 int i;
2751#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002752 win_T *wp;
2753 tabpage_T *tp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754#endif
Bram Moolenaare25bb902015-02-27 20:33:37 +01002755 buf_T *buf = curbuf;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002756 int next_fnum = 0;
2757#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
2758 char_u *save_ei = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002759#endif
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002760 char_u *p_shm_save;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002761#ifdef FEAT_QUICKFIX
Bram Moolenaared84b762015-09-09 22:35:29 +02002762 int qf_size = 0;
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002763 int qf_idx;
2764#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765
2766#ifndef FEAT_WINDOWS
2767 if (eap->cmdidx == CMD_windo)
2768 {
2769 ex_ni(eap);
2770 return;
2771 }
2772#endif
2773
Bram Moolenaar0106e3d2016-02-23 18:55:43 +01002774#ifndef FEAT_QUICKFIX
2775 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
2776 eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2777 {
2778 ex_ni(eap);
2779 return;
2780 }
2781#endif
2782
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002784 if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
Bram Moolenaardcaf10e2005-01-21 11:55:25 +00002785 /* Don't do syntax HL autocommands. Skipping the syntax file is a
2786 * great speed improvement. */
2787 save_ei = au_event_disable(",Syntax");
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002789#ifdef FEAT_CLIPBOARD
2790 start_global_changes();
2791#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792
2793 if (eap->cmdidx == CMD_windo
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002794 || eap->cmdidx == CMD_tabdo
Bram Moolenaar071d4272004-06-13 20:20:40 +00002795 || P_HID(curbuf)
Bram Moolenaar45d3b142013-11-09 03:31:51 +01002796 || !check_changed(curbuf, CCGD_AW
2797 | (eap->forceit ? CCGD_FORCEIT : 0)
2798 | CCGD_EXCMD))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800 i = 0;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002801 /* start at the eap->line1 argument/window/buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802#ifdef FEAT_WINDOWS
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002803 wp = firstwin;
2804 tp = first_tabpage;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002805#endif
Bram Moolenaara162bc52015-01-07 16:54:21 +01002806 switch (eap->cmdidx)
2807 {
2808#ifdef FEAT_WINDOWS
2809 case CMD_windo:
2810 for ( ; wp != NULL && i + 1 < eap->line1; wp = wp->w_next)
2811 i++;
2812 break;
2813 case CMD_tabdo:
2814 for( ; tp != NULL && i + 1 < eap->line1; tp = tp->tp_next)
2815 i++;
2816 break;
2817#endif
2818 case CMD_argdo:
2819 i = eap->line1 - 1;
2820 break;
Bram Moolenaara162bc52015-01-07 16:54:21 +01002821 default:
2822 break;
2823 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824 /* set pcmark now */
2825 if (eap->cmdidx == CMD_bufdo)
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002826 {
Bram Moolenaare25bb902015-02-27 20:33:37 +01002827 /* Advance to the first listed buffer after "eap->line1". */
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002828 for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
Bram Moolenaare25bb902015-02-27 20:33:37 +01002829 || !buf->b_p_bl); buf = buf->b_next)
2830 if (buf->b_fnum > eap->line2)
2831 {
2832 buf = NULL;
2833 break;
2834 }
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002835 if (buf != NULL)
Bram Moolenaare25bb902015-02-27 20:33:37 +01002836 goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002837 }
2838#ifdef FEAT_QUICKFIX
2839 else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2840 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2841 {
2842 qf_size = qf_get_size(eap);
2843 if (qf_size <= 0 || eap->line1 > qf_size)
2844 buf = NULL;
2845 else
2846 {
2847 ex_cc(eap);
2848
2849 buf = curbuf;
2850 i = eap->line1 - 1;
2851 if (eap->addr_count <= 0)
2852 /* default is all the quickfix/location list entries */
2853 eap->line2 = qf_size;
2854 }
2855 }
2856#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857 else
2858 setpcmark();
2859 listcmd_busy = TRUE; /* avoids setting pcmark below */
2860
Bram Moolenaare25bb902015-02-27 20:33:37 +01002861 while (!got_int && buf != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 {
2863 if (eap->cmdidx == CMD_argdo)
2864 {
2865 /* go to argument "i" */
2866 if (i == ARGCOUNT)
2867 break;
2868 /* Don't call do_argfile() when already there, it will try
2869 * reloading the file. */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002870 if (curwin->w_arg_idx != i || !editing_arg_idx(curwin))
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002871 {
2872 /* Clear 'shm' to avoid that the file message overwrites
2873 * any output from the command. */
2874 p_shm_save = vim_strsave(p_shm);
2875 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 do_argfile(eap, i);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002877 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2878 vim_free(p_shm_save);
2879 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002880 if (curwin->w_arg_idx != i)
2881 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002882 }
2883#ifdef FEAT_WINDOWS
2884 else if (eap->cmdidx == CMD_windo)
2885 {
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002886 /* go to window "wp" */
2887 if (!win_valid(wp))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002888 break;
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002889 win_goto(wp);
Bram Moolenaar41423242007-05-03 20:11:13 +00002890 if (curwin != wp)
2891 break; /* something must be wrong */
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002892 wp = curwin->w_next;
2893 }
2894 else if (eap->cmdidx == CMD_tabdo)
2895 {
2896 /* go to window "tp" */
2897 if (!valid_tabpage(tp))
2898 break;
Bram Moolenaar49e649f2013-05-06 04:50:35 +02002899 goto_tabpage_tp(tp, TRUE, TRUE);
Bram Moolenaar32466aa2006-02-24 23:53:04 +00002900 tp = tp->tp_next;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901 }
2902#endif
2903 else if (eap->cmdidx == CMD_bufdo)
2904 {
2905 /* Remember the number of the next listed buffer, in case
2906 * ":bwipe" is used or autocommands do something strange. */
2907 next_fnum = -1;
2908 for (buf = curbuf->b_next; buf != NULL; buf = buf->b_next)
2909 if (buf->b_p_bl)
2910 {
2911 next_fnum = buf->b_fnum;
2912 break;
2913 }
2914 }
2915
Bram Moolenaara162bc52015-01-07 16:54:21 +01002916 ++i;
2917
Bram Moolenaar071d4272004-06-13 20:20:40 +00002918 /* execute the command */
2919 do_cmdline(eap->arg, eap->getline, eap->cookie,
2920 DOCMD_VERBOSE + DOCMD_NOWAIT);
2921
2922 if (eap->cmdidx == CMD_bufdo)
2923 {
2924 /* Done? */
Bram Moolenaara162bc52015-01-07 16:54:21 +01002925 if (next_fnum < 0 || next_fnum > eap->line2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 break;
2927 /* Check if the buffer still exists. */
2928 for (buf = firstbuf; buf != NULL; buf = buf->b_next)
2929 if (buf->b_fnum == next_fnum)
2930 break;
2931 if (buf == NULL)
2932 break;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002933
2934 /* Go to the next buffer. Clear 'shm' to avoid that the file
2935 * message overwrites any output from the command. */
2936 p_shm_save = vim_strsave(p_shm);
2937 set_option_value((char_u *)"shm", 0L, (char_u *)"", 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938 goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002939 set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
2940 vim_free(p_shm_save);
2941
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002942 /* If autocommands took us elsewhere, quit here. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002943 if (curbuf->b_fnum != next_fnum)
2944 break;
2945 }
2946
Bram Moolenaaraa23b372015-09-08 18:46:31 +02002947#ifdef FEAT_QUICKFIX
2948 if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
2949 || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
2950 {
2951 if (i >= qf_size || i >= eap->line2)
2952 break;
2953
2954 qf_idx = qf_get_cur_idx(eap);
2955
2956 ex_cnext(eap);
2957
2958 /* If jumping to the next quickfix entry fails, quit here */
2959 if (qf_get_cur_idx(eap) == qf_idx)
2960 break;
2961 }
2962#endif
2963
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964 if (eap->cmdidx == CMD_windo)
2965 {
2966 validate_cursor(); /* cursor may have moved */
2967#ifdef FEAT_SCROLLBIND
2968 /* required when 'scrollbind' has been set */
2969 if (curwin->w_p_scb)
2970 do_check_scrollbind(TRUE);
2971#endif
2972 }
Bram Moolenaara162bc52015-01-07 16:54:21 +01002973
2974#ifdef FEAT_WINDOWS
2975 if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
2976 if (i+1 > eap->line2)
2977 break;
2978#endif
2979 if (eap->cmdidx == CMD_argdo && i >= eap->line2)
2980 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002981 }
2982 listcmd_busy = FALSE;
2983 }
2984
2985#if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL)
Bram Moolenaar6ac54292005-02-02 23:07:25 +00002986 if (save_ei != NULL)
2987 {
2988 au_event_restore(save_ei);
2989 apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
2990 curbuf->b_fname, TRUE, curbuf);
2991 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002992#endif
Bram Moolenaar6b1ee342014-08-06 18:17:11 +02002993#ifdef FEAT_CLIPBOARD
2994 end_global_changes();
2995#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996}
2997
2998/*
2999 * Add files[count] to the arglist of the current window after arg "after".
3000 * The file names in files[count] must have been allocated and are taken over.
3001 * Files[] itself is not taken over.
3002 * Returns index of first added argument. Returns -1 when failed (out of mem).
3003 */
3004 static int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003005alist_add_list(
3006 int count,
3007 char_u **files,
3008 int after) /* where to add: 0 = before first one */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003009{
3010 int i;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003011 int old_argcount = ARGCOUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003012
3013 if (ga_grow(&ALIST(curwin)->al_ga, count) == OK)
3014 {
3015 if (after < 0)
3016 after = 0;
3017 if (after > ARGCOUNT)
3018 after = ARGCOUNT;
3019 if (after < ARGCOUNT)
3020 mch_memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
3021 (ARGCOUNT - after) * sizeof(aentry_T));
3022 for (i = 0; i < count; ++i)
3023 {
3024 ARGLIST[after + i].ae_fname = files[i];
3025 ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
3026 }
3027 ALIST(curwin)->al_ga.ga_len += count;
Bram Moolenaara24f0a52016-01-17 19:39:00 +01003028 if (old_argcount > 0 && curwin->w_arg_idx >= after)
3029 curwin->w_arg_idx += count;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 return after;
3031 }
3032
3033 for (i = 0; i < count; ++i)
3034 vim_free(files[i]);
3035 return -1;
3036}
3037
3038#endif /* FEAT_LISTCMDS */
3039
3040#ifdef FEAT_EVAL
3041/*
3042 * ":compiler[!] {name}"
3043 */
3044 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003045ex_compiler(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046{
3047 char_u *buf;
3048 char_u *old_cur_comp = NULL;
3049 char_u *p;
3050
3051 if (*eap->arg == NUL)
3052 {
3053 /* List all compiler scripts. */
3054 do_cmdline_cmd((char_u *)"echo globpath(&rtp, 'compiler/*.vim')");
3055 /* ) keep the indenter happy... */
3056 }
3057 else
3058 {
3059 buf = alloc((unsigned)(STRLEN(eap->arg) + 14));
3060 if (buf != NULL)
3061 {
3062 if (eap->forceit)
3063 {
3064 /* ":compiler! {name}" sets global options */
3065 do_cmdline_cmd((char_u *)
3066 "command -nargs=* CompilerSet set <args>");
3067 }
3068 else
3069 {
3070 /* ":compiler! {name}" sets local options.
3071 * To remain backwards compatible "current_compiler" is always
3072 * used. A user's compiler plugin may set it, the distributed
3073 * plugin will then skip the settings. Afterwards set
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003074 * "b:current_compiler" and restore "current_compiler".
3075 * Explicitly prepend "g:" to make it work in a function. */
3076 old_cur_comp = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003077 if (old_cur_comp != NULL)
3078 old_cur_comp = vim_strsave(old_cur_comp);
3079 do_cmdline_cmd((char_u *)
3080 "command -nargs=* CompilerSet setlocal <args>");
3081 }
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003082 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00003083 do_unlet((char_u *)"b:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084
3085 sprintf((char *)buf, "compiler/%s.vim", eap->arg);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003086 if (source_runtime(buf, DIP_ALL) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087 EMSG2(_("E666: compiler not supported: %s"), eap->arg);
3088 vim_free(buf);
3089
3090 do_cmdline_cmd((char_u *)":delcommand CompilerSet");
3091
3092 /* Set "b:current_compiler" from "current_compiler". */
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003093 p = get_var_value((char_u *)"g:current_compiler");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094 if (p != NULL)
3095 set_internal_string_var((char_u *)"b:current_compiler", p);
3096
3097 /* Restore "current_compiler" for ":compiler {name}". */
3098 if (!eap->forceit)
3099 {
3100 if (old_cur_comp != NULL)
3101 {
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003102 set_internal_string_var((char_u *)"g:current_compiler",
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103 old_cur_comp);
3104 vim_free(old_cur_comp);
3105 }
3106 else
Bram Moolenaar3d63e3f2010-01-19 16:13:50 +01003107 do_unlet((char_u *)"g:current_compiler", TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003108 }
3109 }
3110 }
3111}
3112#endif
3113
3114/*
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003115 * ":runtime [what] {name}"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 */
3117 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003118ex_runtime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003120 char_u *arg = eap->arg;
3121 char_u *p = skiptowhite(arg);
3122 int len = (int)(p - arg);
3123 int flags = eap->forceit ? DIP_ALL : 0;
3124
3125 if (STRNCMP(arg, "START", len) == 0)
3126 {
3127 flags += DIP_START + DIP_NORTP;
3128 arg = skipwhite(arg + len);
3129 }
3130 else if (STRNCMP(arg, "OPT", len) == 0)
3131 {
3132 flags += DIP_OPT + DIP_NORTP;
3133 arg = skipwhite(arg + len);
3134 }
3135 else if (STRNCMP(arg, "PACK", len) == 0)
3136 {
3137 flags += DIP_START + DIP_OPT + DIP_NORTP;
3138 arg = skipwhite(arg + len);
3139 }
3140 else if (STRNCMP(arg, "ALL", len) == 0)
3141 {
3142 flags += DIP_START + DIP_OPT;
3143 arg = skipwhite(arg + len);
3144 }
3145
3146 source_runtime(arg, flags);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003147}
3148
Bram Moolenaar071d4272004-06-13 20:20:40 +00003149 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003150source_callback(char_u *fname, void *cookie UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151{
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003152 (void)do_source(fname, FALSE, DOSO_NONE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153}
3154
3155/*
3156 * Source the file "name" from all directories in 'runtimepath'.
3157 * "name" can contain wildcards.
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003158 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
Bram Moolenaar91715872016-03-03 17:13:03 +01003159 *
Bram Moolenaar071d4272004-06-13 20:20:40 +00003160 * return FAIL when no file could be sourced, OK otherwise.
3161 */
3162 int
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003163source_runtime(char_u *name, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164{
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003165 return do_in_runtimepath(name, flags, source_callback, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003166}
3167
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003168/*
3169 * Find the file "name" in all directories in "path" and invoke
3170 * "callback(fname, cookie)".
3171 * "name" can contain wildcards.
3172 * When "flags" has DIP_ALL: source all files, otherwise only the first one.
3173 * When "flags" has DIP_DIR: find directories instead of files.
3174 * When "flags" has DIP_ERR: give an error message if there is no match.
3175 *
3176 * return FAIL when no file could be sourced, OK otherwise.
3177 */
Bram Moolenaar6bef5302016-03-12 21:28:26 +01003178 int
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003179do_in_path(
3180 char_u *path,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003181 char_u *name,
Bram Moolenaar91715872016-03-03 17:13:03 +01003182 int flags,
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003183 void (*callback)(char_u *fname, void *ck),
3184 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185{
3186 char_u *rtp;
3187 char_u *np;
3188 char_u *buf;
3189 char_u *rtp_copy;
3190 char_u *tail;
3191 int num_files;
3192 char_u **files;
3193 int i;
3194 int did_one = FALSE;
3195#ifdef AMIGA
3196 struct Process *proc = (struct Process *)FindTask(0L);
3197 APTR save_winptr = proc->pr_WindowPtr;
3198
3199 /* Avoid a requester here for a volume that doesn't exist. */
3200 proc->pr_WindowPtr = (APTR)-1L;
3201#endif
3202
3203 /* Make a copy of 'runtimepath'. Invoking the callback may change the
3204 * value. */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003205 rtp_copy = vim_strsave(path);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206 buf = alloc(MAXPATHL);
3207 if (buf != NULL && rtp_copy != NULL)
3208 {
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003209 if (p_verbose > 1 && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003210 {
3211 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003212 smsg((char_u *)_("Searching for \"%s\" in \"%s\""),
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003213 (char *)name, (char *)path);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003214 verbose_leave();
3215 }
Bram Moolenaar34cdc3e2005-05-18 22:24:46 +00003216
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217 /* Loop over all entries in 'runtimepath'. */
3218 rtp = rtp_copy;
Bram Moolenaar91715872016-03-03 17:13:03 +01003219 while (*rtp != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003220 {
3221 /* Copy the path from 'runtimepath' to buf[]. */
3222 copy_option_part(&rtp, buf, MAXPATHL, ",");
Bram Moolenaarc09a6d62013-06-10 21:27:29 +02003223 if (name == NULL)
3224 {
3225 (*callback)(buf, (void *) &cookie);
3226 if (!did_one)
3227 did_one = (cookie == NULL);
3228 }
3229 else if (STRLEN(buf) + STRLEN(name) + 2 < MAXPATHL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 {
3231 add_pathsep(buf);
3232 tail = buf + STRLEN(buf);
3233
3234 /* Loop over all patterns in "name" */
3235 np = name;
Bram Moolenaar91715872016-03-03 17:13:03 +01003236 while (*np != NUL && ((flags & DIP_ALL) || !did_one))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 {
3238 /* Append the pattern from "name" to buf[]. */
3239 copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)),
3240 "\t ");
3241
3242 if (p_verbose > 2)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003243 {
3244 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003245 smsg((char_u *)_("Searching for \"%s\""), buf);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003246 verbose_leave();
3247 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248
3249 /* Expand wildcards, invoke the callback for each match. */
3250 if (gen_expand_wildcards(1, &buf, &num_files, &files,
Bram Moolenaar91715872016-03-03 17:13:03 +01003251 (flags & DIP_DIR) ? EW_DIR : EW_FILE) == OK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003252 {
3253 for (i = 0; i < num_files; ++i)
3254 {
Bram Moolenaar13fcaaf2005-04-15 21:13:42 +00003255 (*callback)(files[i], cookie);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003256 did_one = TRUE;
Bram Moolenaar91715872016-03-03 17:13:03 +01003257 if (!(flags & DIP_ALL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 break;
3259 }
3260 FreeWild(num_files, files);
3261 }
3262 }
3263 }
3264 }
3265 }
3266 vim_free(buf);
3267 vim_free(rtp_copy);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003268 if (!did_one && name != NULL)
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003269 {
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003270 char *basepath = path == p_rtp ? "runtimepath" : "packpath";
3271
3272 if (flags & DIP_ERR)
3273 EMSG3(_(e_dirnotf), basepath, name);
3274 else if (p_verbose > 0)
3275 {
3276 verbose_enter();
3277 smsg((char_u *)_("not found in '%s': \"%s\""), basepath, name);
3278 verbose_leave();
3279 }
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003280 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003281
3282#ifdef AMIGA
3283 proc->pr_WindowPtr = save_winptr;
3284#endif
3285
3286 return did_one ? OK : FAIL;
3287}
3288
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003289/*
3290 * Find "name" in 'runtimepath'. When found, invoke the callback function for
3291 * it: callback(fname, "cookie")
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003292 * When "flags" has DIP_ALL repeat for all matches, otherwise only the first
3293 * one is used.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003294 * Returns OK when at least one match found, FAIL otherwise.
3295 *
3296 * If "name" is NULL calls callback for each entry in runtimepath. Cookie is
3297 * passed by reference in this case, setting it to NULL indicates that callback
3298 * has done its job.
3299 */
3300 int
3301do_in_runtimepath(
3302 char_u *name,
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003303 int flags,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003304 void (*callback)(char_u *fname, void *ck),
3305 void *cookie)
3306{
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003307 int done = FAIL;
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003308 char_u *s;
3309 int len;
3310 char *start_dir = "pack/*/start/*/%s";
3311 char *opt_dir = "pack/*/opt/*/%s";
3312
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003313 if ((flags & DIP_NORTP) == 0)
3314 done = do_in_path(p_rtp, name, flags, callback, cookie);
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003315
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003316 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003317 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003318 len = (int)(STRLEN(start_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003319 s = alloc(len);
3320 if (s == NULL)
3321 return FAIL;
3322 vim_snprintf((char *)s, len, start_dir, name);
3323 done = do_in_path(p_pp, s, flags, callback, cookie);
3324 vim_free(s);
3325 }
3326
Bram Moolenaar8dcf2592016-03-12 22:47:14 +01003327 if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_OPT))
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003328 {
Bram Moolenaar1c8b4ed2016-03-17 21:51:03 +01003329 len = (int)(STRLEN(opt_dir) + STRLEN(name));
Bram Moolenaar7f8989d2016-03-12 22:11:39 +01003330 s = alloc(len);
3331 if (s == NULL)
3332 return FAIL;
3333 vim_snprintf((char *)s, len, opt_dir, name);
3334 done = do_in_path(p_pp, s, flags, callback, cookie);
3335 vim_free(s);
3336 }
3337
3338 return done;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003339}
3340
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003341/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003342 * Expand wildcards in "pat" and invoke do_source() for each match.
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003343 */
3344 static void
Bram Moolenaarf3654822016-03-04 22:12:23 +01003345source_all_matches(char_u *pat)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003346{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003347 int num_files;
3348 char_u **files;
3349 int i;
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003350
Bram Moolenaarf3654822016-03-04 22:12:23 +01003351 if (gen_expand_wildcards(1, &pat, &num_files, &files, EW_FILE) == OK)
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003352 {
Bram Moolenaarf3654822016-03-04 22:12:23 +01003353 for (i = 0; i < num_files; ++i)
3354 (void)do_source(files[i], FALSE, DOSO_NONE);
3355 FreeWild(num_files, files);
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003356 }
Bram Moolenaar1bdd4262016-03-03 14:23:10 +01003357}
3358
Bram Moolenaar49b27322016-04-05 21:13:00 +02003359/* used for "cookie" of add_pack_plugin() */
3360static int APP_ADD_DIR;
3361static int APP_LOAD;
3362static int APP_BOTH;
3363
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003364 static void
Bram Moolenaar91715872016-03-03 17:13:03 +01003365add_pack_plugin(char_u *fname, void *cookie)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003366{
Bram Moolenaarf3654822016-03-04 22:12:23 +01003367 char_u *p4, *p3, *p2, *p1, *p;
3368 char_u *insp;
Bram Moolenaar91715872016-03-03 17:13:03 +01003369 int c;
3370 char_u *new_rtp;
3371 int keep;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003372 size_t oldlen;
3373 size_t addlen;
Bram Moolenaara5702442016-05-24 19:37:29 +02003374 char_u *afterdir;
Bram Moolenaarb0550662016-05-31 21:37:36 +02003375 size_t afterlen = 0;
Bram Moolenaar91715872016-03-03 17:13:03 +01003376 char_u *ffname = fix_fname(fname);
Bram Moolenaarfef524b2016-07-02 22:07:22 +02003377 size_t fname_len;
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003378
Bram Moolenaar91715872016-03-03 17:13:03 +01003379 if (ffname == NULL)
3380 return;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003381 if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003382 {
Bram Moolenaara5702442016-05-24 19:37:29 +02003383 /* directory is not yet in 'runtimepath', add it */
Bram Moolenaarf3654822016-03-04 22:12:23 +01003384 p4 = p3 = p2 = p1 = get_past_head(ffname);
3385 for (p = p1; *p; mb_ptr_adv(p))
3386 if (vim_ispathsep_nocolon(*p))
3387 {
3388 p4 = p3; p3 = p2; p2 = p1; p1 = p;
3389 }
3390
3391 /* now we have:
Bram Moolenaaraf1a0e32016-03-09 22:19:26 +01003392 * rtp/pack/name/start/name
3393 * p4 p3 p2 p1
Bram Moolenaarf3654822016-03-04 22:12:23 +01003394 *
3395 * find the part up to "pack" in 'runtimepath' */
3396 c = *p4;
3397 *p4 = NUL;
Bram Moolenaar4c5717e2016-07-01 15:39:40 +02003398
3399 /* Find "ffname" in "p_rtp", ignoring '/' vs '\' differences. */
3400 fname_len = STRLEN(ffname);
3401 insp = p_rtp;
3402 for (;;)
3403 {
3404 if (vim_fnamencmp(insp, ffname, fname_len) == 0)
3405 break;
3406 insp = vim_strchr(insp, ',');
3407 if (insp == NULL)
3408 break;
3409 ++insp;
3410 }
3411
Bram Moolenaarf3654822016-03-04 22:12:23 +01003412 if (insp == NULL)
3413 /* not found, append at the end */
3414 insp = p_rtp + STRLEN(p_rtp);
3415 else
3416 {
3417 /* append after the matching directory. */
3418 insp += STRLEN(ffname);
3419 while (*insp != NUL && *insp != ',')
3420 ++insp;
3421 }
3422 *p4 = c;
3423
Bram Moolenaara5702442016-05-24 19:37:29 +02003424 /* check if rtp/pack/name/start/name/after exists */
3425 afterdir = concat_fnames(ffname, (char_u *)"after", TRUE);
3426 if (afterdir != NULL && mch_isdir(afterdir))
3427 afterlen = STRLEN(afterdir) + 1; /* add one for comma */
3428
Bram Moolenaarb0550662016-05-31 21:37:36 +02003429 oldlen = STRLEN(p_rtp);
3430 addlen = STRLEN(ffname) + 1; /* add one for comma */
3431 new_rtp = alloc((int)(oldlen + addlen + afterlen + 1)); /* add one for NUL */
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003432 if (new_rtp == NULL)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003433 goto theend;
3434 keep = (int)(insp - p_rtp);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003435 mch_memmove(new_rtp, p_rtp, keep);
3436 new_rtp[keep] = ',';
Bram Moolenaara5702442016-05-24 19:37:29 +02003437 mch_memmove(new_rtp + keep + 1, ffname, addlen);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003438 if (p_rtp[keep] != NUL)
Bram Moolenaara5702442016-05-24 19:37:29 +02003439 mch_memmove(new_rtp + keep + addlen, p_rtp + keep,
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003440 oldlen - keep + 1);
Bram Moolenaara5702442016-05-24 19:37:29 +02003441 if (afterlen > 0)
3442 {
3443 STRCAT(new_rtp, ",");
3444 STRCAT(new_rtp, afterdir);
3445 }
Bram Moolenaar863c1a92016-03-03 15:47:06 +01003446 set_option_value((char_u *)"rtp", 0L, new_rtp, 0);
3447 vim_free(new_rtp);
Bram Moolenaara5702442016-05-24 19:37:29 +02003448 vim_free(afterdir);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003449 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003450
Bram Moolenaar49b27322016-04-05 21:13:00 +02003451 if (cookie != &APP_ADD_DIR)
Bram Moolenaarf3654822016-03-04 22:12:23 +01003452 {
Bram Moolenaar71fb0c12016-04-02 22:44:16 +02003453 static char *plugpat = "%s/plugin/**/*.vim";
Bram Moolenaarf3654822016-03-04 22:12:23 +01003454 static char *ftpat = "%s/ftdetect/*.vim";
3455 int len;
3456 char_u *pat;
3457
3458 len = (int)STRLEN(ffname) + (int)STRLEN(ftpat);
3459 pat = alloc(len);
3460 if (pat == NULL)
3461 goto theend;
3462 vim_snprintf((char *)pat, len, plugpat, ffname);
3463 source_all_matches(pat);
3464
3465#ifdef FEAT_AUTOCMD
3466 {
3467 char_u *cmd = vim_strsave((char_u *)"g:did_load_filetypes");
3468
3469 /* If runtime/filetype.vim wasn't loaded yet, the scripts will be
3470 * found when it loads. */
3471 if (cmd != NULL && eval_to_number(cmd) > 0)
3472 {
3473 do_cmdline_cmd((char_u *)"augroup filetypedetect");
3474 vim_snprintf((char *)pat, len, ftpat, ffname);
3475 source_all_matches(pat);
3476 do_cmdline_cmd((char_u *)"augroup END");
3477 }
3478 vim_free(cmd);
3479 }
3480#endif
Bram Moolenaarba8cd122016-03-19 14:16:39 +01003481 vim_free(pat);
Bram Moolenaarf3654822016-03-04 22:12:23 +01003482 }
3483
3484theend:
3485 vim_free(ffname);
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003486}
3487
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003488static int did_source_packages = FALSE;
3489
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003490/*
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003491 * ":packloadall"
Bram Moolenaarf3654822016-03-04 22:12:23 +01003492 * Find plugins in the package directories and source them.
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003493 */
3494 void
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003495ex_packloadall(exarg_T *eap)
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003496{
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003497 if (!did_source_packages || (eap != NULL && eap->forceit))
3498 {
3499 did_source_packages = TRUE;
Bram Moolenaar49b27322016-04-05 21:13:00 +02003500
3501 /* First do a round to add all directories to 'runtimepath', then load
3502 * the plugins. This allows for plugins to use an autoload directory
3503 * of another plugin. */
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003504 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003505 add_pack_plugin, &APP_ADD_DIR);
3506 do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR,
3507 add_pack_plugin, &APP_LOAD);
Bram Moolenaar2d8f56a2016-03-12 20:34:27 +01003508 }
Bram Moolenaarf6fee0e2016-02-21 23:02:49 +01003509}
3510
3511/*
Bram Moolenaarf3654822016-03-04 22:12:23 +01003512 * ":packadd[!] {name}"
Bram Moolenaar91715872016-03-03 17:13:03 +01003513 */
3514 void
3515ex_packadd(exarg_T *eap)
3516{
3517 static char *plugpat = "pack/*/opt/%s";
3518 int len;
3519 char *pat;
3520
3521 len = (int)STRLEN(plugpat) + (int)STRLEN(eap->arg);
3522 pat = (char *)alloc(len);
3523 if (pat == NULL)
3524 return;
3525 vim_snprintf(pat, len, plugpat, eap->arg);
Bram Moolenaarbe82c252016-03-06 14:44:08 +01003526 do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + DIP_ERR,
Bram Moolenaar49b27322016-04-05 21:13:00 +02003527 add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
Bram Moolenaar91715872016-03-03 17:13:03 +01003528 vim_free(pat);
3529}
3530
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531#if defined(FEAT_EVAL) && defined(FEAT_AUTOCMD)
3532/*
3533 * ":options"
3534 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003535 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003536ex_options(
3537 exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538{
3539 cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
3540}
3541#endif
3542
3543/*
3544 * ":source {fname}"
3545 */
3546 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003547ex_source(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548{
3549#ifdef FEAT_BROWSE
3550 if (cmdmod.browse)
3551 {
3552 char_u *fname = NULL;
3553
Bram Moolenaar7b0294c2004-10-11 10:16:09 +00003554 fname = do_browse(0, (char_u *)_("Source Vim script"), eap->arg,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 NULL, NULL, BROWSE_FILTER_MACROS, NULL);
3556 if (fname != NULL)
3557 {
3558 cmd_source(fname, eap);
3559 vim_free(fname);
3560 }
3561 }
3562 else
3563#endif
3564 cmd_source(eap->arg, eap);
3565}
3566
3567 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003568cmd_source(char_u *fname, exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569{
3570 if (*fname == NUL)
3571 EMSG(_(e_argreq));
3572
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573 else if (eap != NULL && eap->forceit)
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003574 /* ":source!": read Normal mode commands
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003575 * Need to execute the commands directly. This is required at least
3576 * for:
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 * - ":g" command busy
3578 * - after ":argdo", ":windo" or ":bufdo"
3579 * - another command follows
3580 * - inside a loop
3581 */
3582 openscript(fname, global_busy || listcmd_busy || eap->nextcmd != NULL
3583#ifdef FEAT_EVAL
3584 || eap->cstack->cs_idx >= 0
3585#endif
3586 );
3587
3588 /* ":source" read ex commands */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003589 else if (do_source(fname, FALSE, DOSO_NONE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 EMSG2(_(e_notopen), fname);
3591}
3592
3593/*
3594 * ":source" and associated commands.
3595 */
3596/*
3597 * Structure used to store info for each sourced file.
3598 * It is shared between do_source() and getsourceline().
3599 * This is required, because it needs to be handed to do_cmdline() and
3600 * sourcing can be done recursively.
3601 */
3602struct source_cookie
3603{
3604 FILE *fp; /* opened file for sourcing */
3605 char_u *nextline; /* if not NULL: line that was read ahead */
3606 int finished; /* ":finish" used */
Bram Moolenaar860cae12010-06-05 23:22:07 +02003607#if defined(USE_CRNL) || defined(USE_CR)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
3609 int error; /* TRUE if LF found after CR-LF */
3610#endif
3611#ifdef FEAT_EVAL
3612 linenr_T breakpoint; /* next line with breakpoint or zero */
3613 char_u *fname; /* name of sourced file */
3614 int dbg_tick; /* debug_tick when breakpoint was set */
3615 int level; /* top nesting level of sourced file */
3616#endif
3617#ifdef FEAT_MBYTE
3618 vimconv_T conv; /* type of conversion */
3619#endif
3620};
3621
3622#ifdef FEAT_EVAL
3623/*
3624 * Return the address holding the next breakpoint line for a source cookie.
3625 */
3626 linenr_T *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003627source_breakpoint(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628{
3629 return &((struct source_cookie *)cookie)->breakpoint;
3630}
3631
3632/*
3633 * Return the address holding the debug tick for a source cookie.
3634 */
3635 int *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003636source_dbg_tick(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637{
3638 return &((struct source_cookie *)cookie)->dbg_tick;
3639}
3640
3641/*
3642 * Return the nesting level for a source cookie.
3643 */
3644 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003645source_level(void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646{
3647 return ((struct source_cookie *)cookie)->level;
3648}
3649#endif
3650
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003651static char_u *get_one_sourceline(struct source_cookie *sp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003652
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003653#if (defined(WIN32) && defined(FEAT_CSCOPE)) || defined(HAVE_FD_CLOEXEC)
3654# define USE_FOPEN_NOINH
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01003655static FILE *fopen_noinh_readbin(char *filename);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003656
3657/*
3658 * Special function to open a file without handle inheritance.
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003659 * When possible the handle is closed on exec().
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660 */
3661 static FILE *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003662fopen_noinh_readbin(char *filename)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663{
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003664# ifdef WIN32
Bram Moolenaar8d8ef0b2010-01-20 21:41:47 +01003665 int fd_tmp = mch_open(filename, O_RDONLY | O_BINARY | O_NOINHERIT, 0);
3666# else
3667 int fd_tmp = mch_open(filename, O_RDONLY, 0);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003668# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669
3670 if (fd_tmp == -1)
3671 return NULL;
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003672
3673# ifdef HAVE_FD_CLOEXEC
3674 {
3675 int fdflags = fcntl(fd_tmp, F_GETFD);
3676 if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
Bram Moolenaarcde88542015-08-11 19:14:00 +02003677 (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003678 }
3679# endif
3680
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 return fdopen(fd_tmp, READBIN);
3682}
3683#endif
3684
3685
3686/*
3687 * do_source: Read the file "fname" and execute its lines as EX commands.
3688 *
3689 * This function may be called recursively!
3690 *
3691 * return FAIL if file could not be opened, OK otherwise
3692 */
3693 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01003694do_source(
3695 char_u *fname,
3696 int check_other, /* check for .vimrc and _vimrc */
3697 int is_vimrc) /* DOSO_ value */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698{
3699 struct source_cookie cookie;
3700 char_u *save_sourcing_name;
3701 linenr_T save_sourcing_lnum;
3702 char_u *p;
3703 char_u *fname_exp;
Bram Moolenaar73881402009-02-04 16:50:47 +00003704 char_u *firstline = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705 int retval = FAIL;
3706#ifdef FEAT_EVAL
3707 scid_T save_current_SID;
3708 static scid_T last_current_SID = 0;
3709 void *save_funccalp;
3710 int save_debug_break_level = debug_break_level;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003711 scriptitem_T *si = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003712# ifdef UNIX
Bram Moolenaar8767f522016-07-01 17:17:39 +02003713 stat_T st;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 int stat_ok;
3715# endif
3716#endif
3717#ifdef STARTUPTIME
3718 struct timeval tv_rel;
3719 struct timeval tv_start;
3720#endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003721#ifdef FEAT_PROFILE
3722 proftime_T wait_start;
3723#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003724
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 p = expand_env_save(fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726 if (p == NULL)
3727 return retval;
3728 fname_exp = fix_fname(p);
3729 vim_free(p);
3730 if (fname_exp == NULL)
3731 return retval;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003732 if (mch_isdir(fname_exp))
3733 {
Bram Moolenaar555b2802005-05-19 21:08:39 +00003734 smsg((char_u *)_("Cannot source a directory: \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735 goto theend;
3736 }
3737
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003738#ifdef FEAT_AUTOCMD
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003739 /* Apply SourceCmd autocommands, they should get the file and source it. */
3740 if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
3741 && apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
3742 FALSE, curbuf))
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003743 {
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003744# ifdef FEAT_EVAL
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003745 retval = aborting() ? FAIL : OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003746# else
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003747 retval = OK;
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003748# endif
Bram Moolenaarf33943e2008-01-15 21:17:30 +00003749 goto theend;
3750 }
Bram Moolenaar8dd1aa52007-01-16 20:33:19 +00003751
3752 /* Apply SourcePre autocommands, they may get the file. */
Bram Moolenaar1f35bf92006-03-07 22:38:47 +00003753 apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
3754#endif
3755
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003756#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3758#else
3759 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3760#endif
3761 if (cookie.fp == NULL && check_other)
3762 {
3763 /*
3764 * Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
3765 * and ".exrc" by "_exrc" or vice versa.
3766 */
3767 p = gettail(fname_exp);
3768 if ((*p == '.' || *p == '_')
3769 && (STRICMP(p + 1, "vimrc") == 0
3770 || STRICMP(p + 1, "gvimrc") == 0
3771 || STRICMP(p + 1, "exrc") == 0))
3772 {
3773 if (*p == '_')
3774 *p = '.';
3775 else
3776 *p = '_';
Bram Moolenaar6b29b0e2010-01-19 16:22:03 +01003777#ifdef USE_FOPEN_NOINH
Bram Moolenaar071d4272004-06-13 20:20:40 +00003778 cookie.fp = fopen_noinh_readbin((char *)fname_exp);
3779#else
3780 cookie.fp = mch_fopen((char *)fname_exp, READBIN);
3781#endif
3782 }
3783 }
3784
3785 if (cookie.fp == NULL)
3786 {
3787 if (p_verbose > 0)
3788 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003789 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003791 smsg((char_u *)_("could not source \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792 else
3793 smsg((char_u *)_("line %ld: could not source \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003794 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003795 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 }
3797 goto theend;
3798 }
3799
3800 /*
3801 * The file exists.
3802 * - In verbose mode, give a message.
3803 * - For a vimrc file, may want to set 'compatible', call vimrc_found().
3804 */
3805 if (p_verbose > 1)
3806 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003807 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 if (sourcing_name == NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003809 smsg((char_u *)_("sourcing \"%s\""), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810 else
3811 smsg((char_u *)_("line %ld: sourcing \"%s\""),
Bram Moolenaar555b2802005-05-19 21:08:39 +00003812 sourcing_lnum, fname);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00003813 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +00003815 if (is_vimrc == DOSO_VIMRC)
3816 vimrc_found(fname_exp, (char_u *)"MYVIMRC");
3817 else if (is_vimrc == DOSO_GVIMRC)
3818 vimrc_found(fname_exp, (char_u *)"MYGVIMRC");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819
3820#ifdef USE_CRNL
3821 /* If no automatic file format: Set default to CR-NL. */
3822 if (*p_ffs == NUL)
3823 cookie.fileformat = EOL_DOS;
3824 else
3825 cookie.fileformat = EOL_UNKNOWN;
3826 cookie.error = FALSE;
3827#endif
3828
3829#ifdef USE_CR
3830 /* If no automatic file format: Set default to CR. */
3831 if (*p_ffs == NUL)
3832 cookie.fileformat = EOL_MAC;
3833 else
3834 cookie.fileformat = EOL_UNKNOWN;
3835 cookie.error = FALSE;
3836#endif
3837
3838 cookie.nextline = NULL;
3839 cookie.finished = FALSE;
3840
3841#ifdef FEAT_EVAL
3842 /*
3843 * Check if this script has a breakpoint.
3844 */
3845 cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
3846 cookie.fname = fname_exp;
3847 cookie.dbg_tick = debug_tick;
3848
3849 cookie.level = ex_nesting_level;
3850#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003851
3852 /*
3853 * Keep the sourcing name/lnum, for recursive calls.
3854 */
3855 save_sourcing_name = sourcing_name;
3856 sourcing_name = fname_exp;
3857 save_sourcing_lnum = sourcing_lnum;
3858 sourcing_lnum = 0;
3859
Bram Moolenaar73881402009-02-04 16:50:47 +00003860#ifdef FEAT_MBYTE
3861 cookie.conv.vc_type = CONV_NONE; /* no conversion */
3862
3863 /* Read the first line so we can check for a UTF-8 BOM. */
3864 firstline = getsourceline(0, (void *)&cookie, 0);
3865 if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
3866 && firstline[1] == 0xbb && firstline[2] == 0xbf)
3867 {
3868 /* Found BOM; setup conversion, skip over BOM and recode the line. */
3869 convert_setup(&cookie.conv, (char_u *)"utf-8", p_enc);
3870 p = string_convert(&cookie.conv, firstline + 3, NULL);
Bram Moolenaar4e2a5952009-02-05 19:48:25 +00003871 if (p == NULL)
3872 p = vim_strsave(firstline + 3);
Bram Moolenaar73881402009-02-04 16:50:47 +00003873 if (p != NULL)
3874 {
3875 vim_free(firstline);
3876 firstline = p;
3877 }
3878 }
3879#endif
3880
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01003882 if (time_fd != NULL)
3883 time_push(&tv_rel, &tv_start);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884#endif
3885
3886#ifdef FEAT_EVAL
Bram Moolenaar05159a02005-02-26 23:04:13 +00003887# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003888 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003889 prof_child_enter(&wait_start); /* entering a child now */
3890# endif
3891
3892 /* Don't use local function variables, if called from a function.
3893 * Also starts profiling timer for nested script. */
3894 save_funccalp = save_funccal();
3895
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 /*
3897 * Check if this script was sourced before to finds its SID.
3898 * If it's new, generate a new SID.
3899 */
3900 save_current_SID = current_SID;
3901# ifdef UNIX
3902 stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
3903# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003904 for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
3905 {
3906 si = &SCRIPT_ITEM(current_SID);
3907 if (si->sn_name != NULL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908 && (
3909# ifdef UNIX
Bram Moolenaar7c626922005-02-07 22:01:03 +00003910 /* Compare dev/ino when possible, it catches symbolic
3911 * links. Also compare file names, the inode may change
3912 * when the file was edited. */
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003913 ((stat_ok && si->sn_dev_valid)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003914 && (si->sn_dev == st.st_dev
3915 && si->sn_ino == st.st_ino)) ||
Bram Moolenaar071d4272004-06-13 20:20:40 +00003916# endif
Bram Moolenaar05159a02005-02-26 23:04:13 +00003917 fnamecmp(si->sn_name, fname_exp) == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003918 break;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003919 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 if (current_SID == 0)
3921 {
3922 current_SID = ++last_current_SID;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003923 if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
3924 == FAIL)
3925 goto almosttheend;
3926 while (script_items.ga_len < current_SID)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927 {
Bram Moolenaar05159a02005-02-26 23:04:13 +00003928 ++script_items.ga_len;
3929 SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
3930# ifdef FEAT_PROFILE
3931 SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00003934 si = &SCRIPT_ITEM(current_SID);
3935 si->sn_name = fname_exp;
3936 fname_exp = NULL;
3937# ifdef UNIX
3938 if (stat_ok)
3939 {
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003940 si->sn_dev_valid = TRUE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003941 si->sn_dev = st.st_dev;
3942 si->sn_ino = st.st_ino;
3943 }
3944 else
Bram Moolenaarbf0c4522009-05-16 19:16:33 +00003945 si->sn_dev_valid = FALSE;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003946# endif
3947
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 /* Allocate the local script variables to use for this script. */
3949 new_script_vars(current_SID);
3950 }
3951
Bram Moolenaar05159a02005-02-26 23:04:13 +00003952# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003953 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003954 {
3955 int forceit;
3956
3957 /* Check if we do profiling for this script. */
3958 if (!si->sn_prof_on && has_profiling(TRUE, si->sn_name, &forceit))
3959 {
3960 script_do_profile(si);
3961 si->sn_pr_force = forceit;
3962 }
3963 if (si->sn_prof_on)
3964 {
3965 ++si->sn_pr_count;
3966 profile_start(&si->sn_pr_start);
3967 profile_zero(&si->sn_pr_children);
3968 }
3969 }
3970# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003971#endif
3972
3973 /*
3974 * Call do_cmdline, which will call getsourceline() to get the lines.
3975 */
Bram Moolenaar73881402009-02-04 16:50:47 +00003976 do_cmdline(firstline, getsourceline, (void *)&cookie,
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977 DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 retval = OK;
Bram Moolenaar05159a02005-02-26 23:04:13 +00003979
3980#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00003981 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00003982 {
3983 /* Get "si" again, "script_items" may have been reallocated. */
3984 si = &SCRIPT_ITEM(current_SID);
3985 if (si->sn_prof_on)
3986 {
3987 profile_end(&si->sn_pr_start);
3988 profile_sub_wait(&wait_start, &si->sn_pr_start);
3989 profile_add(&si->sn_pr_total, &si->sn_pr_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00003990 profile_self(&si->sn_pr_self, &si->sn_pr_start,
3991 &si->sn_pr_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00003992 }
3993 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994#endif
3995
3996 if (got_int)
3997 EMSG(_(e_interr));
3998 sourcing_name = save_sourcing_name;
3999 sourcing_lnum = save_sourcing_lnum;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 if (p_verbose > 1)
4001 {
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004002 verbose_enter();
Bram Moolenaar555b2802005-05-19 21:08:39 +00004003 smsg((char_u *)_("finished sourcing %s"), fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004 if (sourcing_name != NULL)
Bram Moolenaar555b2802005-05-19 21:08:39 +00004005 smsg((char_u *)_("continuing in %s"), sourcing_name);
Bram Moolenaar54ee7752005-05-31 22:22:17 +00004006 verbose_leave();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004007 }
4008#ifdef STARTUPTIME
Bram Moolenaarc4e41982010-01-19 16:31:47 +01004009 if (time_fd != NULL)
4010 {
4011 vim_snprintf((char *)IObuff, IOSIZE, "sourcing %s", fname);
4012 time_msg((char *)IObuff, &tv_start);
4013 time_pop(&tv_rel);
4014 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015#endif
4016
4017#ifdef FEAT_EVAL
4018 /*
4019 * After a "finish" in debug mode, need to break at first command of next
4020 * sourced file.
4021 */
4022 if (save_debug_break_level > ex_nesting_level
4023 && debug_break_level == ex_nesting_level)
4024 ++debug_break_level;
4025#endif
4026
Bram Moolenaar05159a02005-02-26 23:04:13 +00004027#ifdef FEAT_EVAL
4028almosttheend:
4029 current_SID = save_current_SID;
4030 restore_funccal(save_funccalp);
4031# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004032 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004033 prof_child_exit(&wait_start); /* leaving a child now */
4034# endif
4035#endif
4036 fclose(cookie.fp);
4037 vim_free(cookie.nextline);
Bram Moolenaar73881402009-02-04 16:50:47 +00004038 vim_free(firstline);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004039#ifdef FEAT_MBYTE
4040 convert_setup(&cookie.conv, NULL, NULL);
4041#endif
4042
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043theend:
4044 vim_free(fname_exp);
4045 return retval;
4046}
4047
4048#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004049
Bram Moolenaar071d4272004-06-13 20:20:40 +00004050/*
4051 * ":scriptnames"
4052 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004054ex_scriptnames(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055{
4056 int i;
4057
Bram Moolenaar05159a02005-02-26 23:04:13 +00004058 for (i = 1; i <= script_items.ga_len && !got_int; ++i)
4059 if (SCRIPT_ITEM(i).sn_name != NULL)
Bram Moolenaard58ea072011-06-26 04:25:30 +02004060 {
4061 home_replace(NULL, SCRIPT_ITEM(i).sn_name,
4062 NameBuff, MAXPATHL, TRUE);
4063 smsg((char_u *)"%3d: %s", i, NameBuff);
Bram Moolenaar970a1b82012-03-23 18:39:18 +01004064 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065}
4066
4067# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
4068/*
4069 * Fix slashes in the list of script names for 'shellslash'.
4070 */
4071 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004072scriptnames_slash_adjust(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004073{
4074 int i;
4075
Bram Moolenaar05159a02005-02-26 23:04:13 +00004076 for (i = 1; i <= script_items.ga_len; ++i)
4077 if (SCRIPT_ITEM(i).sn_name != NULL)
4078 slash_adjust(SCRIPT_ITEM(i).sn_name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079}
4080# endif
4081
4082/*
4083 * Get a pointer to a script name. Used for ":verbose set".
4084 */
4085 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004086get_scriptname(scid_T id)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087{
4088 if (id == SID_MODELINE)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004089 return (char_u *)_("modeline");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004090 if (id == SID_CMDARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004091 return (char_u *)_("--cmd argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 if (id == SID_CARG)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004093 return (char_u *)_("-c argument");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 if (id == SID_ENV)
Bram Moolenaard1f56e62006-02-22 21:25:37 +00004095 return (char_u *)_("environment variable");
4096 if (id == SID_ERROR)
4097 return (char_u *)_("error handler");
Bram Moolenaar05159a02005-02-26 23:04:13 +00004098 return SCRIPT_ITEM(id).sn_name;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099}
Bram Moolenaar05159a02005-02-26 23:04:13 +00004100
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004101# if defined(EXITFREE) || defined(PROTO)
4102 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004103free_scriptnames(void)
Bram Moolenaar1ec484f2005-06-24 23:07:47 +00004104{
4105 int i;
4106
4107 for (i = script_items.ga_len; i > 0; --i)
4108 vim_free(SCRIPT_ITEM(i).sn_name);
4109 ga_clear(&script_items);
4110}
4111# endif
4112
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113#endif
4114
4115#if defined(USE_CR) || defined(PROTO)
4116
4117# if defined(__MSL__) && (__MSL__ >= 22)
4118/*
4119 * Newer version of the Metrowerks library handle DOS and UNIX files
4120 * without help.
4121 * Test with earlier versions, MSL 2.2 is the library supplied with
4122 * Codewarrior Pro 2.
4123 */
4124 char *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004125fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126{
4127 return fgets(s, n, stream);
4128}
4129# else
4130/*
4131 * Version of fgets() which also works for lines ending in a <CR> only
4132 * (Macintosh format).
4133 * For older versions of the Metrowerks library.
4134 * At least CodeWarrior 9 needed this code.
4135 */
4136 char *
Bram Moolenaard14e00e2016-01-31 17:30:51 +01004137fgets_cr(char *s, int n, FILE *stream)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138{
4139 int c = 0;
4140 int char_read = 0;
4141
4142 while (!feof(stream) && c != '\r' && c != '\n' && char_read < n - 1)
4143 {
4144 c = fgetc(stream);
4145 s[char_read++] = c;
4146 /* If the file is in DOS format, we need to skip a NL after a CR. I
4147 * thought it was the other way around, but this appears to work... */
4148 if (c == '\n')
4149 {
4150 c = fgetc(stream);
4151 if (c != '\r')
4152 ungetc(c, stream);
4153 }
4154 }
4155
4156 s[char_read] = 0;
4157 if (char_read == 0)
4158 return NULL;
4159
4160 if (feof(stream) && char_read == 1)
4161 return NULL;
4162
4163 return s;
4164}
4165# endif
4166#endif
4167
4168/*
4169 * Get one full line from a sourced file.
4170 * Called by do_cmdline() when it's called from do_source().
4171 *
4172 * Return a pointer to the line in allocated memory.
4173 * Return NULL for end-of-file or some error.
4174 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004176getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177{
4178 struct source_cookie *sp = (struct source_cookie *)cookie;
4179 char_u *line;
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004180 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181
4182#ifdef FEAT_EVAL
4183 /* If breakpoints have been added/deleted need to check for it. */
4184 if (sp->dbg_tick < debug_tick)
4185 {
4186 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4187 sp->dbg_tick = debug_tick;
4188 }
Bram Moolenaar05159a02005-02-26 23:04:13 +00004189# ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004190 if (do_profiling == PROF_YES)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004191 script_line_end();
4192# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004193#endif
4194 /*
4195 * Get current line. If there is a read-ahead line, use it, otherwise get
4196 * one now.
4197 */
4198 if (sp->finished)
4199 line = NULL;
4200 else if (sp->nextline == NULL)
4201 line = get_one_sourceline(sp);
4202 else
4203 {
4204 line = sp->nextline;
4205 sp->nextline = NULL;
4206 ++sourcing_lnum;
4207 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004208#ifdef FEAT_PROFILE
Bram Moolenaar9b2200a2006-03-20 21:55:45 +00004209 if (line != NULL && do_profiling == PROF_YES)
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004210 script_line_start();
4211#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212
4213 /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
4214 * contain the 'C' flag. */
4215 if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
4216 {
4217 /* compensate for the one line read-ahead */
4218 --sourcing_lnum;
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004219
4220 /* Get the next line and concatenate it when it starts with a
4221 * backslash. We always need to read the next line, keep it in
4222 * sp->nextline. */
4223 sp->nextline = get_one_sourceline(sp);
4224 if (sp->nextline != NULL && *(p = skipwhite(sp->nextline)) == '\\')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225 {
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004226 garray_T ga;
4227
Bram Moolenaarb549a732012-02-22 18:29:33 +01004228 ga_init2(&ga, (int)sizeof(char_u), 400);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004229 ga_concat(&ga, line);
4230 ga_concat(&ga, p + 1);
4231 for (;;)
4232 {
4233 vim_free(sp->nextline);
4234 sp->nextline = get_one_sourceline(sp);
4235 if (sp->nextline == NULL)
4236 break;
4237 p = skipwhite(sp->nextline);
4238 if (*p != '\\')
4239 break;
Bram Moolenaarb549a732012-02-22 18:29:33 +01004240 /* Adjust the growsize to the current length to speed up
4241 * concatenating many lines. */
4242 if (ga.ga_len > 400)
4243 {
4244 if (ga.ga_len > 8000)
4245 ga.ga_growsize = 8000;
4246 else
4247 ga.ga_growsize = ga.ga_len;
4248 }
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004249 ga_concat(&ga, p + 1);
4250 }
4251 ga_append(&ga, NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252 vim_free(line);
Bram Moolenaarb3a6bbc2012-02-05 23:10:30 +01004253 line = ga.ga_data;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254 }
4255 }
4256
4257#ifdef FEAT_MBYTE
4258 if (line != NULL && sp->conv.vc_type != CONV_NONE)
4259 {
Bram Moolenaarc047b9a2012-02-11 20:40:55 +01004260 char_u *s;
4261
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 /* Convert the encoding of the script line. */
4263 s = string_convert(&sp->conv, line, NULL);
4264 if (s != NULL)
4265 {
4266 vim_free(line);
4267 line = s;
4268 }
4269 }
4270#endif
4271
4272#ifdef FEAT_EVAL
4273 /* Did we encounter a breakpoint? */
4274 if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
4275 {
4276 dbg_breakpoint(sp->fname, sourcing_lnum);
4277 /* Find next breakpoint. */
4278 sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
4279 sp->dbg_tick = debug_tick;
4280 }
4281#endif
4282
4283 return line;
4284}
4285
4286 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004287get_one_sourceline(struct source_cookie *sp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288{
4289 garray_T ga;
4290 int len;
4291 int c;
4292 char_u *buf;
4293#ifdef USE_CRNL
4294 int has_cr; /* CR-LF found */
4295#endif
4296#ifdef USE_CR
4297 char_u *scan;
4298#endif
4299 int have_read = FALSE;
4300
4301 /* use a growarray to store the sourced line */
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004302 ga_init2(&ga, 1, 250);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303
4304 /*
4305 * Loop until there is a finished line (or end-of-file).
4306 */
4307 sourcing_lnum++;
4308 for (;;)
4309 {
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004310 /* make room to read at least 120 (more) characters */
4311 if (ga_grow(&ga, 120) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312 break;
4313 buf = (char_u *)ga.ga_data;
4314
4315#ifdef USE_CR
4316 if (sp->fileformat == EOL_MAC)
4317 {
Bram Moolenaar86b68352004-12-27 21:59:20 +00004318 if (fgets_cr((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4319 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320 break;
4321 }
4322 else
4323#endif
Bram Moolenaar86b68352004-12-27 21:59:20 +00004324 if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
4325 sp->fp) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004326 break;
Bram Moolenaar6ac54292005-02-02 23:07:25 +00004327 len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328#ifdef USE_CRNL
4329 /* Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
4330 * CTRL-Z by its own, or after a NL. */
4331 if ( (len == 1 || (len >= 2 && buf[len - 2] == '\n'))
4332 && sp->fileformat == EOL_DOS
4333 && buf[len - 1] == Ctrl_Z)
4334 {
4335 buf[len - 1] = NUL;
4336 break;
4337 }
4338#endif
4339
4340#ifdef USE_CR
4341 /* If the read doesn't stop on a new line, and there's
4342 * some CR then we assume a Mac format */
4343 if (sp->fileformat == EOL_UNKNOWN)
4344 {
4345 if (buf[len - 1] != '\n' && vim_strchr(buf, '\r') != NULL)
4346 sp->fileformat = EOL_MAC;
4347 else
4348 sp->fileformat = EOL_UNIX;
4349 }
4350
4351 if (sp->fileformat == EOL_MAC)
4352 {
4353 scan = vim_strchr(buf, '\r');
4354
4355 if (scan != NULL)
4356 {
4357 *scan = '\n';
4358 if (*(scan + 1) != 0)
4359 {
4360 *(scan + 1) = 0;
4361 fseek(sp->fp, (long)(scan - buf - len + 1), SEEK_CUR);
4362 }
4363 }
4364 len = STRLEN(buf);
4365 }
4366#endif
4367
4368 have_read = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 ga.ga_len = len;
4370
4371 /* If the line was longer than the buffer, read more. */
Bram Moolenaar86b68352004-12-27 21:59:20 +00004372 if (ga.ga_maxlen - ga.ga_len == 1 && buf[len - 1] != '\n')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373 continue;
4374
4375 if (len >= 1 && buf[len - 1] == '\n') /* remove trailing NL */
4376 {
4377#ifdef USE_CRNL
4378 has_cr = (len >= 2 && buf[len - 2] == '\r');
4379 if (sp->fileformat == EOL_UNKNOWN)
4380 {
4381 if (has_cr)
4382 sp->fileformat = EOL_DOS;
4383 else
4384 sp->fileformat = EOL_UNIX;
4385 }
4386
4387 if (sp->fileformat == EOL_DOS)
4388 {
4389 if (has_cr) /* replace trailing CR */
4390 {
4391 buf[len - 2] = '\n';
4392 --len;
4393 --ga.ga_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 }
4395 else /* lines like ":map xx yy^M" will have failed */
4396 {
4397 if (!sp->error)
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004398 {
4399 msg_source(hl_attr(HLF_W));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400 EMSG(_("W15: Warning: Wrong line separator, ^M may be missing"));
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +00004401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004402 sp->error = TRUE;
4403 sp->fileformat = EOL_UNIX;
4404 }
4405 }
4406#endif
4407 /* The '\n' is escaped if there is an odd number of ^V's just
4408 * before it, first set "c" just before the 'V's and then check
4409 * len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo */
4410 for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--)
4411 ;
4412 if ((len & 1) != (c & 1)) /* escaped NL, read more */
4413 {
4414 sourcing_lnum++;
4415 continue;
4416 }
4417
4418 buf[len - 1] = NUL; /* remove the NL */
4419 }
4420
4421 /*
4422 * Check for ^C here now and then, so recursive :so can be broken.
4423 */
4424 line_breakcheck();
4425 break;
4426 }
4427
4428 if (have_read)
4429 return (char_u *)ga.ga_data;
4430
4431 vim_free(ga.ga_data);
4432 return NULL;
4433}
4434
Bram Moolenaar05159a02005-02-26 23:04:13 +00004435#if defined(FEAT_PROFILE) || defined(PROTO)
4436/*
4437 * Called when starting to read a script line.
4438 * "sourcing_lnum" must be correct!
4439 * When skipping lines it may not actually be executed, but we won't find out
4440 * until later and we need to store the time now.
4441 */
4442 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004443script_line_start(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004444{
4445 scriptitem_T *si;
4446 sn_prl_T *pp;
4447
4448 if (current_SID <= 0 || current_SID > script_items.ga_len)
4449 return;
4450 si = &SCRIPT_ITEM(current_SID);
4451 if (si->sn_prof_on && sourcing_lnum >= 1)
4452 {
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004453 /* Grow the array before starting the timer, so that the time spent
Bram Moolenaar05159a02005-02-26 23:04:13 +00004454 * here isn't counted. */
Bram Moolenaarcde88542015-08-11 19:14:00 +02004455 (void)ga_grow(&si->sn_prl_ga, (int)(sourcing_lnum - si->sn_prl_ga.ga_len));
Bram Moolenaar05159a02005-02-26 23:04:13 +00004456 si->sn_prl_idx = sourcing_lnum - 1;
4457 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
4458 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
4459 {
4460 /* Zero counters for a line that was not used before. */
4461 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
4462 pp->snp_count = 0;
4463 profile_zero(&pp->sn_prl_total);
4464 profile_zero(&pp->sn_prl_self);
4465 ++si->sn_prl_ga.ga_len;
4466 }
4467 si->sn_prl_execed = FALSE;
4468 profile_start(&si->sn_prl_start);
4469 profile_zero(&si->sn_prl_children);
4470 profile_get_wait(&si->sn_prl_wait);
4471 }
4472}
4473
4474/*
4475 * Called when actually executing a function line.
4476 */
4477 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004478script_line_exec(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004479{
4480 scriptitem_T *si;
4481
4482 if (current_SID <= 0 || current_SID > script_items.ga_len)
4483 return;
4484 si = &SCRIPT_ITEM(current_SID);
4485 if (si->sn_prof_on && si->sn_prl_idx >= 0)
4486 si->sn_prl_execed = TRUE;
4487}
4488
4489/*
4490 * Called when done with a function line.
4491 */
4492 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004493script_line_end(void)
Bram Moolenaar05159a02005-02-26 23:04:13 +00004494{
4495 scriptitem_T *si;
4496 sn_prl_T *pp;
4497
4498 if (current_SID <= 0 || current_SID > script_items.ga_len)
4499 return;
4500 si = &SCRIPT_ITEM(current_SID);
4501 if (si->sn_prof_on && si->sn_prl_idx >= 0
4502 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
4503 {
4504 if (si->sn_prl_execed)
4505 {
4506 pp = &PRL_ITEM(si, si->sn_prl_idx);
4507 ++pp->snp_count;
4508 profile_end(&si->sn_prl_start);
4509 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004510 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
Bram Moolenaar1056d982006-03-09 22:37:52 +00004511 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
4512 &si->sn_prl_children);
Bram Moolenaar05159a02005-02-26 23:04:13 +00004513 }
4514 si->sn_prl_idx = -1;
4515 }
4516}
4517#endif
4518
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519/*
4520 * ":scriptencoding": Set encoding conversion for a sourced script.
4521 * Without the multi-byte feature it's simply ignored.
4522 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004523 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004524ex_scriptencoding(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525{
4526#ifdef FEAT_MBYTE
4527 struct source_cookie *sp;
4528 char_u *name;
4529
4530 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
4531 {
4532 EMSG(_("E167: :scriptencoding used outside of a sourced file"));
4533 return;
4534 }
4535
4536 if (*eap->arg != NUL)
4537 {
4538 name = enc_canonize(eap->arg);
4539 if (name == NULL) /* out of memory */
4540 return;
4541 }
4542 else
4543 name = eap->arg;
4544
4545 /* Setup for conversion from the specified encoding to 'encoding'. */
4546 sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie);
4547 convert_setup(&sp->conv, name, p_enc);
4548
4549 if (name != eap->arg)
4550 vim_free(name);
4551#endif
4552}
4553
4554#if defined(FEAT_EVAL) || defined(PROTO)
4555/*
4556 * ":finish": Mark a sourced file as finished.
4557 */
4558 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004559ex_finish(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560{
4561 if (getline_equal(eap->getline, eap->cookie, getsourceline))
4562 do_finish(eap, FALSE);
4563 else
4564 EMSG(_("E168: :finish used outside of a sourced file"));
4565}
4566
4567/*
4568 * Mark a sourced file as finished. Possibly makes the ":finish" pending.
4569 * Also called for a pending finish at the ":endtry" or after returning from
4570 * an extra do_cmdline(). "reanimate" is used in the latter case.
4571 */
4572 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004573do_finish(exarg_T *eap, int reanimate)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574{
4575 int idx;
4576
4577 if (reanimate)
4578 ((struct source_cookie *)getline_cookie(eap->getline,
4579 eap->cookie))->finished = FALSE;
4580
4581 /*
4582 * Cleanup (and inactivate) conditionals, but stop when a try conditional
4583 * not in its finally clause (which then is to be executed next) is found.
4584 * In this case, make the ":finish" pending for execution at the ":endtry".
4585 * Otherwise, finish normally.
4586 */
4587 idx = cleanup_conditionals(eap->cstack, 0, TRUE);
4588 if (idx >= 0)
4589 {
4590 eap->cstack->cs_pending[idx] = CSTP_FINISH;
4591 report_make_pending(CSTP_FINISH, NULL);
4592 }
4593 else
4594 ((struct source_cookie *)getline_cookie(eap->getline,
4595 eap->cookie))->finished = TRUE;
4596}
4597
4598
4599/*
4600 * Return TRUE when a sourced file had the ":finish" command: Don't give error
4601 * message for missing ":endif".
4602 * Return FALSE when not sourcing a file.
4603 */
4604 int
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004605source_finished(
4606 char_u *(*fgetline)(int, void *, int),
4607 void *cookie)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608{
Bram Moolenaar89d40322006-08-29 15:30:07 +00004609 return (getline_equal(fgetline, cookie, getsourceline)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 && ((struct source_cookie *)getline_cookie(
Bram Moolenaar89d40322006-08-29 15:30:07 +00004611 fgetline, cookie))->finished);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612}
4613#endif
4614
4615#if defined(FEAT_LISTCMDS) || defined(PROTO)
4616/*
4617 * ":checktime [buffer]"
4618 */
4619 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004620ex_checktime(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621{
4622 buf_T *buf;
4623 int save_no_check_timestamps = no_check_timestamps;
4624
4625 no_check_timestamps = 0;
4626 if (eap->addr_count == 0) /* default is all buffers */
4627 check_timestamps(FALSE);
4628 else
4629 {
4630 buf = buflist_findnr((int)eap->line2);
4631 if (buf != NULL) /* cannot happen? */
4632 (void)buf_check_timestamp(buf, FALSE);
4633 }
4634 no_check_timestamps = save_no_check_timestamps;
4635}
4636#endif
4637
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4639 && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004640# define HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004641static char_u *get_locale_val(int what);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004643 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004644get_locale_val(int what)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645{
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004646 char_u *loc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647
Bram Moolenaar48e330a2016-02-23 14:53:34 +01004648 /* Obtain the locale value from the libraries. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004649 loc = (char_u *)setlocale(what, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004650
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004651# ifdef WIN32
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652 if (loc != NULL)
4653 {
4654 char_u *p;
4655
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004656 /* setocale() returns something like "LC_COLLATE=<name>;LC_..." when
4657 * one of the values (e.g., LC_CTYPE) differs. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658 p = vim_strchr(loc, '=');
4659 if (p != NULL)
4660 {
4661 loc = ++p;
4662 while (*p != NUL) /* remove trailing newline */
4663 {
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004664 if (*p < ' ' || *p == ';')
Bram Moolenaar071d4272004-06-13 20:20:40 +00004665 {
4666 *p = NUL;
4667 break;
4668 }
4669 ++p;
4670 }
4671 }
4672 }
4673# endif
4674
4675 return loc;
4676}
4677#endif
4678
4679
4680#ifdef WIN32
4681/*
4682 * On MS-Windows locale names are strings like "German_Germany.1252", but
4683 * gettext expects "de". Try to translate one into another here for a few
4684 * supported languages.
4685 */
4686 static char_u *
4687gettext_lang(char_u *name)
4688{
4689 int i;
4690 static char *(mtable[]) = {
4691 "afrikaans", "af",
4692 "czech", "cs",
4693 "dutch", "nl",
4694 "german", "de",
4695 "english_united kingdom", "en_GB",
4696 "spanish", "es",
4697 "french", "fr",
4698 "italian", "it",
4699 "japanese", "ja",
4700 "korean", "ko",
4701 "norwegian", "no",
4702 "polish", "pl",
4703 "russian", "ru",
4704 "slovak", "sk",
4705 "swedish", "sv",
4706 "ukrainian", "uk",
4707 "chinese_china", "zh_CN",
4708 "chinese_taiwan", "zh_TW",
4709 NULL};
4710
4711 for (i = 0; mtable[i] != NULL; i += 2)
4712 if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004713 return (char_u *)mtable[i + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 return name;
4715}
4716#endif
4717
4718#if defined(FEAT_MULTI_LANG) || defined(PROTO)
4719/*
4720 * Obtain the current messages language. Used to set the default for
4721 * 'helplang'. May return NULL or an empty string.
4722 */
4723 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004724get_mess_lang(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725{
4726 char_u *p;
4727
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004728# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729# if defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004730 p = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731# else
4732 /* This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
Bram Moolenaar61660ea2006-04-07 21:40:07 +00004733 * may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
4734 * and LC_MONETARY may be set differently for a Japanese working in the
4735 * US. */
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004736 p = get_locale_val(LC_COLLATE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737# endif
4738# else
4739 p = mch_getenv((char_u *)"LC_ALL");
4740 if (p == NULL || *p == NUL)
4741 {
4742 p = mch_getenv((char_u *)"LC_MESSAGES");
4743 if (p == NULL || *p == NUL)
4744 p = mch_getenv((char_u *)"LANG");
4745 }
4746# endif
4747# ifdef WIN32
4748 p = gettext_lang(p);
4749# endif
4750 return p;
4751}
4752#endif
4753
Bram Moolenaardef9e822004-12-31 20:58:58 +00004754/* Complicated #if; matches with where get_mess_env() is used below. */
4755#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4756 && defined(LC_MESSAGES))) \
4757 || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4758 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE)) \
4759 && !defined(LC_MESSAGES))
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004760static char_u *get_mess_env(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761
4762/*
4763 * Get the language used for messages from the environment.
4764 */
4765 static char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004766get_mess_env(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004767{
4768 char_u *p;
4769
4770 p = mch_getenv((char_u *)"LC_ALL");
4771 if (p == NULL || *p == NUL)
4772 {
4773 p = mch_getenv((char_u *)"LC_MESSAGES");
4774 if (p == NULL || *p == NUL)
4775 {
4776 p = mch_getenv((char_u *)"LANG");
4777 if (p != NULL && VIM_ISDIGIT(*p))
4778 p = NULL; /* ignore something like "1043" */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004779# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 if (p == NULL || *p == NUL)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004781 p = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004782# endif
4783 }
4784 }
4785 return p;
4786}
4787#endif
4788
4789#if defined(FEAT_EVAL) || defined(PROTO)
4790
4791/*
4792 * Set the "v:lang" variable according to the current locale setting.
4793 * Also do "v:lc_time"and "v:ctype".
4794 */
4795 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004796set_lang_var(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797{
4798 char_u *loc;
4799
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004800# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004801 loc = get_locale_val(LC_CTYPE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004802# else
4803 /* setlocale() not supported: use the default value */
4804 loc = (char_u *)"C";
4805# endif
4806 set_vim_var_string(VV_CTYPE, loc, -1);
4807
4808 /* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
4809 * back to LC_CTYPE if it's empty. */
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004810# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004811 loc = get_locale_val(LC_MESSAGES);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004812# else
4813 loc = get_mess_env();
4814# endif
4815 set_vim_var_string(VV_LANG, loc, -1);
4816
Bram Moolenaar8765a4a2010-07-27 22:41:43 +02004817# ifdef HAVE_GET_LOCALE_VAL
Bram Moolenaar6aa2cd42016-02-16 15:06:59 +01004818 loc = get_locale_val(LC_TIME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819# endif
4820 set_vim_var_string(VV_LC_TIME, loc, -1);
4821}
4822#endif
4823
4824#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
4825 && (defined(FEAT_GETTEXT) || defined(FEAT_MBYTE))
4826/*
4827 * ":language": Set the language (locale).
4828 */
4829 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004830ex_language(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831{
4832 char *loc;
4833 char_u *p;
4834 char_u *name;
4835 int what = LC_ALL;
4836 char *whatstr = "";
4837#ifdef LC_MESSAGES
4838# define VIM_LC_MESSAGES LC_MESSAGES
4839#else
4840# define VIM_LC_MESSAGES 6789
4841#endif
4842
4843 name = eap->arg;
4844
4845 /* Check for "messages {name}", "ctype {name}" or "time {name}" argument.
4846 * Allow abbreviation, but require at least 3 characters to avoid
4847 * confusion with a two letter language name "me" or "ct". */
4848 p = skiptowhite(eap->arg);
4849 if ((*p == NUL || vim_iswhite(*p)) && p - eap->arg >= 3)
4850 {
4851 if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
4852 {
4853 what = VIM_LC_MESSAGES;
4854 name = skipwhite(p);
4855 whatstr = "messages ";
4856 }
4857 else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
4858 {
4859 what = LC_CTYPE;
4860 name = skipwhite(p);
4861 whatstr = "ctype ";
4862 }
4863 else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
4864 {
4865 what = LC_TIME;
4866 name = skipwhite(p);
4867 whatstr = "time ";
4868 }
4869 }
4870
4871 if (*name == NUL)
4872 {
4873#ifndef LC_MESSAGES
4874 if (what == VIM_LC_MESSAGES)
4875 p = get_mess_env();
4876 else
4877#endif
4878 p = (char_u *)setlocale(what, NULL);
4879 if (p == NULL || *p == NUL)
4880 p = (char_u *)"Unknown";
4881 smsg((char_u *)_("Current %slanguage: \"%s\""), whatstr, p);
4882 }
4883 else
4884 {
4885#ifndef LC_MESSAGES
4886 if (what == VIM_LC_MESSAGES)
4887 loc = "";
4888 else
4889#endif
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004890 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891 loc = setlocale(what, (char *)name);
Bram Moolenaar8c8de832008-06-24 22:58:06 +00004892#if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
4893 /* Make sure strtod() uses a decimal point, not a comma. */
4894 setlocale(LC_NUMERIC, "C");
4895#endif
4896 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 if (loc == NULL)
4898 EMSG2(_("E197: Cannot set language to \"%s\""), name);
4899 else
4900 {
4901#ifdef HAVE_NL_MSG_CAT_CNTR
4902 /* Need to do this for GNU gettext, otherwise cached translations
4903 * will be used again. */
4904 extern int _nl_msg_cat_cntr;
4905
4906 ++_nl_msg_cat_cntr;
4907#endif
Bram Moolenaarb8017e72007-05-10 18:59:07 +00004908 /* Reset $LC_ALL, otherwise it would overrule everything. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 vim_setenv((char_u *)"LC_ALL", (char_u *)"");
4910
4911 if (what != LC_TIME)
4912 {
4913 /* Tell gettext() what to translate to. It apparently doesn't
4914 * use the currently effective locale. Also do this when
4915 * FEAT_GETTEXT isn't defined, so that shell commands use this
4916 * value. */
4917 if (what == LC_ALL)
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004918 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919 vim_setenv((char_u *)"LANG", name);
Bram Moolenaare3a0b532013-06-28 20:36:30 +02004920
4921 /* Clear $LANGUAGE because GNU gettext uses it. */
4922 vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
Bram Moolenaar482aaeb2005-09-29 18:26:07 +00004923# ifdef WIN32
4924 /* Apparently MS-Windows printf() may cause a crash when
4925 * we give it 8-bit text while it's expecting text in the
4926 * current locale. This call avoids that. */
4927 setlocale(LC_CTYPE, "C");
4928# endif
4929 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004930 if (what != LC_CTYPE)
4931 {
4932 char_u *mname;
4933#ifdef WIN32
4934 mname = gettext_lang(name);
4935#else
4936 mname = name;
4937#endif
4938 vim_setenv((char_u *)"LC_MESSAGES", mname);
4939#ifdef FEAT_MULTI_LANG
4940 set_helplang_default(mname);
4941#endif
4942 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 }
4944
4945# ifdef FEAT_EVAL
4946 /* Set v:lang, v:lc_time and v:ctype to the final result. */
4947 set_lang_var();
4948# endif
Bram Moolenaar6cc00c72011-10-20 21:41:09 +02004949# ifdef FEAT_TITLE
4950 maketitle();
4951# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 }
4953 }
4954}
4955
4956# if defined(FEAT_CMDL_COMPL) || defined(PROTO)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004957
4958static char_u **locales = NULL; /* Array of all available locales */
4959static int did_init_locales = FALSE;
4960
Bram Moolenaarf28dbce2016-01-29 22:03:47 +01004961static void init_locales(void);
4962static char_u **find_locales(void);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004963
4964/*
4965 * Lazy initialization of all available locales.
4966 */
4967 static void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004968init_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004969{
4970 if (!did_init_locales)
4971 {
4972 did_init_locales = TRUE;
4973 locales = find_locales();
4974 }
4975}
4976
4977/* Return an array of strings for all available locales + NULL for the
4978 * last element. Return NULL in case of error. */
4979 static char_u **
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01004980find_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004981{
4982 garray_T locales_ga;
4983 char_u *loc;
4984
4985 /* Find all available locales by running command "locale -a". If this
4986 * doesn't work we won't have completion. */
4987 char_u *locale_a = get_cmd_output((char_u *)"locale -a",
Bram Moolenaar39c29ed2014-04-05 19:44:40 +02004988 NULL, SHELL_SILENT, NULL);
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02004989 if (locale_a == NULL)
4990 return NULL;
4991 ga_init2(&locales_ga, sizeof(char_u *), 20);
4992
4993 /* Transform locale_a string where each locale is separated by "\n"
4994 * into an array of locale strings. */
4995 loc = (char_u *)strtok((char *)locale_a, "\n");
4996
4997 while (loc != NULL)
4998 {
4999 if (ga_grow(&locales_ga, 1) == FAIL)
5000 break;
5001 loc = vim_strsave(loc);
5002 if (loc == NULL)
5003 break;
5004
5005 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
5006 loc = (char_u *)strtok(NULL, "\n");
5007 }
5008 vim_free(locale_a);
5009 if (ga_grow(&locales_ga, 1) == FAIL)
5010 {
5011 ga_clear(&locales_ga);
5012 return NULL;
5013 }
5014 ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
5015 return (char_u **)locales_ga.ga_data;
5016}
5017
5018# if defined(EXITFREE) || defined(PROTO)
5019 void
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005020free_locales(void)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005021{
5022 int i;
5023 if (locales != NULL)
5024 {
5025 for (i = 0; locales[i] != NULL; i++)
5026 vim_free(locales[i]);
5027 vim_free(locales);
5028 locales = NULL;
5029 }
5030}
5031# endif
5032
Bram Moolenaar071d4272004-06-13 20:20:40 +00005033/*
5034 * Function given to ExpandGeneric() to obtain the possible arguments of the
5035 * ":language" command.
5036 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005037 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005038get_lang_arg(expand_T *xp UNUSED, int idx)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039{
5040 if (idx == 0)
5041 return (char_u *)"messages";
5042 if (idx == 1)
5043 return (char_u *)"ctype";
5044 if (idx == 2)
5045 return (char_u *)"time";
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005046
5047 init_locales();
5048 if (locales == NULL)
5049 return NULL;
5050 return locales[idx - 3];
5051}
5052
5053/*
5054 * Function given to ExpandGeneric() to obtain the available locales.
5055 */
5056 char_u *
Bram Moolenaar78c0b7d2016-01-30 15:52:46 +01005057get_locales(expand_T *xp UNUSED, int idx)
Bram Moolenaar9b486ca2011-05-19 18:26:40 +02005058{
5059 init_locales();
5060 if (locales == NULL)
5061 return NULL;
5062 return locales[idx];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063}
5064# endif
5065
5066#endif